[Pkg-javascript-commits] [node-ast-types] 01/05: New upstream version 0.10.1

Julien Puydt julien.puydt at laposte.net
Mon Nov 13 06:49:28 UTC 2017


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 6e44dafc03a0d0454a5237e89e0ef4452583d042
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Mon Nov 13 07:43:16 2017 +0100

    New upstream version 0.10.1
---
 def/{babel6-core.js => babel-core.js} |  119 +-
 def/babel.js                          |  109 +-
 def/babel6.js                         |    4 -
 def/flow.js                           |  701 +++---
 main.js                               |   27 +-
 package-lock.json                     |  187 +-
 package.json                          |    6 +-
 test/run.js                           | 3849 +++++++++++++++++----------------
 8 files changed, 2501 insertions(+), 2501 deletions(-)

diff --git a/def/babel6-core.js b/def/babel-core.js
similarity index 61%
rename from def/babel6-core.js
rename to def/babel-core.js
index 9934419..50955e4 100644
--- a/def/babel6-core.js
+++ b/def/babel-core.js
@@ -1,13 +1,110 @@
 module.exports = function (fork) {
-  fork.use(require("./babel"));
+  fork.use(require("./es7"));
 
-  // var types = fork.types;
   var types = fork.use(require("../lib/types"));
-  // var defaults = fork.shared.defaults;
   var defaults = fork.use(require("../lib/shared")).defaults;
   var def = types.Type.def;
   var or = types.Type.or;
 
+  def("Noop")
+    .bases("Node")
+    .build();
+
+  def("DoExpression")
+    .bases("Expression")
+    .build("body")
+    .field("body", [def("Statement")]);
+
+  def("Super")
+    .bases("Expression")
+    .build();
+
+  def("BindExpression")
+    .bases("Expression")
+    .build("object", "callee")
+    .field("object", or(def("Expression"), null))
+    .field("callee", def("Expression"));
+
+  def("Decorator")
+    .bases("Node")
+    .build("expression")
+    .field("expression", def("Expression"));
+
+  def("Property")
+    .field("decorators",
+           or([def("Decorator")], null),
+           defaults["null"]);
+
+  def("MethodDefinition")
+    .field("decorators",
+           or([def("Decorator")], null),
+           defaults["null"]);
+
+  def("MetaProperty")
+    .bases("Expression")
+    .build("meta", "property")
+    .field("meta", def("Identifier"))
+    .field("property", def("Identifier"));
+
+  def("ParenthesizedExpression")
+    .bases("Expression")
+    .build("expression")
+    .field("expression", def("Expression"));
+
+  def("ImportSpecifier")
+    .bases("ModuleSpecifier")
+    .build("imported", "local")
+    .field("imported", def("Identifier"));
+
+  def("ImportDefaultSpecifier")
+    .bases("ModuleSpecifier")
+    .build("local");
+
+  def("ImportNamespaceSpecifier")
+    .bases("ModuleSpecifier")
+    .build("local");
+
+  def("ExportDefaultDeclaration")
+    .bases("Declaration")
+    .build("declaration")
+    .field("declaration", or(def("Declaration"), def("Expression")));
+
+  def("ExportNamedDeclaration")
+    .bases("Declaration")
+    .build("declaration", "specifiers", "source")
+    .field("declaration", or(def("Declaration"), null))
+    .field("specifiers", [def("ExportSpecifier")], defaults.emptyArray)
+    .field("source", or(def("Literal"), null), defaults["null"]);
+
+  def("ExportSpecifier")
+    .bases("ModuleSpecifier")
+    .build("local", "exported")
+    .field("exported", def("Identifier"));
+
+  def("ExportNamespaceSpecifier")
+    .bases("Specifier")
+    .build("exported")
+    .field("exported", def("Identifier"));
+
+  def("ExportDefaultSpecifier")
+    .bases("Specifier")
+    .build("exported")
+    .field("exported", def("Identifier"));
+
+  def("ExportAllDeclaration")
+    .bases("Declaration")
+    .build("exported", "source")
+    .field("exported", or(def("Identifier"), null))
+    .field("source", def("Literal"));
+
+  def("CommentBlock")
+    .bases("Comment")
+    .build("value", /*optional:*/ "leading", "trailing");
+
+  def("CommentLine")
+    .bases("Comment")
+    .build("value", /*optional:*/ "leading", "trailing");
+
   def("Directive")
     .bases("Node")
     .build("value")
@@ -41,6 +138,22 @@ module.exports = function (fork) {
     .build("value")
     .field("value", Number);
 
+  def("BigIntLiteral")
+    .bases("Literal")
+    .build("value")
+    // Only String really seems appropriate here, since BigInt values
+    // often exceed the limits of JS numbers.
+    .field("value", or(String, Number))
+    .field("extra", {
+      rawValue: String,
+      raw: String
+    }, function getDefault() {
+      return {
+        rawValue: String(this.value),
+        raw: this.value + "n"
+      };
+    });
+
   def("NullLiteral")
     .bases("Literal")
     .build()
diff --git a/def/babel.js b/def/babel.js
index 3d9352b..e0081c8 100644
--- a/def/babel.js
+++ b/def/babel.js
@@ -1,107 +1,4 @@
 module.exports = function (fork) {
-    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;
-
-    def("Noop")
-        .bases("Node")
-        .build();
-
-    def("DoExpression")
-        .bases("Expression")
-        .build("body")
-        .field("body", [def("Statement")]);
-
-    def("Super")
-        .bases("Expression")
-        .build();
-
-    def("BindExpression")
-        .bases("Expression")
-        .build("object", "callee")
-        .field("object", or(def("Expression"), null))
-        .field("callee", def("Expression"));
-
-    def("Decorator")
-        .bases("Node")
-        .build("expression")
-        .field("expression", def("Expression"));
-
-    def("Property")
-        .field("decorators",
-            or([def("Decorator")], null),
-            defaults["null"]);
-
-    def("MethodDefinition")
-        .field("decorators",
-            or([def("Decorator")], null),
-            defaults["null"]);
-
-    def("MetaProperty")
-        .bases("Expression")
-        .build("meta", "property")
-        .field("meta", def("Identifier"))
-        .field("property", def("Identifier"));
-
-    def("ParenthesizedExpression")
-        .bases("Expression")
-        .build("expression")
-        .field("expression", def("Expression"));
-
-    def("ImportSpecifier")
-        .bases("ModuleSpecifier")
-        .build("imported", "local")
-        .field("imported", def("Identifier"));
-
-    def("ImportDefaultSpecifier")
-        .bases("ModuleSpecifier")
-        .build("local");
-
-    def("ImportNamespaceSpecifier")
-        .bases("ModuleSpecifier")
-        .build("local");
-
-    def("ExportDefaultDeclaration")
-        .bases("Declaration")
-        .build("declaration")
-        .field("declaration", or(def("Declaration"), def("Expression")));
-
-    def("ExportNamedDeclaration")
-        .bases("Declaration")
-        .build("declaration", "specifiers", "source")
-        .field("declaration", or(def("Declaration"), null))
-        .field("specifiers", [def("ExportSpecifier")], defaults.emptyArray)
-        .field("source", or(def("Literal"), null), defaults["null"]);
-
-    def("ExportSpecifier")
-        .bases("ModuleSpecifier")
-        .build("local", "exported")
-        .field("exported", def("Identifier"));
-
-    def("ExportNamespaceSpecifier")
-        .bases("Specifier")
-        .build("exported")
-        .field("exported", def("Identifier"));
-
-    def("ExportDefaultSpecifier")
-        .bases("Specifier")
-        .build("exported")
-        .field("exported", def("Identifier"));
-
-    def("ExportAllDeclaration")
-        .bases("Declaration")
-        .build("exported", "source")
-        .field("exported", or(def("Identifier"), null))
-        .field("source", def("Literal"));
-
-    def("CommentBlock")
-        .bases("Comment")
-        .build("value", /*optional:*/ "leading", "trailing");
-
-    def("CommentLine")
-        .bases("Comment")
-        .build("value", /*optional:*/ "leading", "trailing");
-};
\ No newline at end of file
+  fork.use(require("./babel-core"));
+  fork.use(require("./flow"));
+};
diff --git a/def/babel6.js b/def/babel6.js
deleted file mode 100644
index 9c405b6..0000000
--- a/def/babel6.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = function (fork) {
-  fork.use(require("./babel6-core"));
-  fork.use(require("./flow"));
-};
diff --git a/def/flow.js b/def/flow.js
index 1918fdf..d78fd63 100644
--- a/def/flow.js
+++ b/def/flow.js
@@ -1,349 +1,356 @@
 module.exports = function (fork) {
-    fork.use(require("./es7"));
-
-    var types = fork.use(require("../lib/types"));
-    var def = types.Type.def;
-    var or = types.Type.or;
-    var defaults = fork.use(require("../lib/shared")).defaults;
-
-    // Type Annotations
-    def("Type").bases("Node");
-
-    def("AnyTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("EmptyTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("MixedTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("VoidTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("NumberTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("NumberLiteralTypeAnnotation")
-      .bases("Type")
-      .build("value", "raw")
-      .field("value", Number)
-      .field("raw", String);
-
-    // Babylon 6 differs in AST from Flow
-    // same as NumberLiteralTypeAnnotation
-    def("NumericLiteralTypeAnnotation")
-      .bases("Type")
-      .build("value", "raw")
-      .field("value", Number)
-      .field("raw", String);
-
-    def("StringTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("StringLiteralTypeAnnotation")
-      .bases("Type")
-      .build("value", "raw")
-      .field("value", String)
-      .field("raw", String);
-
-    def("BooleanTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("BooleanLiteralTypeAnnotation")
-      .bases("Type")
-      .build("value", "raw")
-      .field("value", Boolean)
-      .field("raw", String);
-
-    def("TypeAnnotation")
-      .bases("Node")
-      .build("typeAnnotation")
-      .field("typeAnnotation", def("Type"));
-
-    def("NullableTypeAnnotation")
-      .bases("Type")
-      .build("typeAnnotation")
-      .field("typeAnnotation", def("Type"));
-
-    def("NullLiteralTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("NullTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("ThisTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("ExistsTypeAnnotation")
-      .bases("Type")
-      .build();
-
-    def("ExistentialTypeParam")
-      .bases("Type")
-      .build();
-
-    def("FunctionTypeAnnotation")
-      .bases("Type")
-      .build("params", "returnType", "rest", "typeParameters")
-      .field("params", [def("FunctionTypeParam")])
-      .field("returnType", def("Type"))
-      .field("rest", or(def("FunctionTypeParam"), null))
-      .field("typeParameters", or(def("TypeParameterDeclaration"), null));
-
-    def("FunctionTypeParam")
-      .bases("Node")
-      .build("name", "typeAnnotation", "optional")
-      .field("name", def("Identifier"))
-      .field("typeAnnotation", def("Type"))
-      .field("optional", Boolean);
-
-    def("ArrayTypeAnnotation")
-      .bases("Type")
-      .build("elementType")
-      .field("elementType", def("Type"));
-
-    def("ObjectTypeAnnotation")
-      .bases("Type")
-      .build("properties", "indexers", "callProperties")
-      .field("properties", [or(def("ObjectTypeProperty"), def("ObjectTypeSpreadProperty"))])
-      .field("indexers", [def("ObjectTypeIndexer")], defaults.emptyArray)
-      .field("callProperties",
-        [def("ObjectTypeCallProperty")],
-        defaults.emptyArray)
-      .field("exact", Boolean, defaults["false"]);
-
-    def("ObjectTypeProperty")
-      .bases("Node")
-      .build("key", "value", "optional")
-      .field("key", or(def("Literal"), def("Identifier")))
-      .field("value", def("Type"))
-      .field("optional", Boolean)
-      .field("variance",
-        or("plus", "minus", null),
-        defaults["null"]);
-
-    def("ObjectTypeIndexer")
-      .bases("Node")
-      .build("id", "key", "value")
-      .field("id", def("Identifier"))
-      .field("key", def("Type"))
-      .field("value", def("Type"))
-      .field("variance",
-        or("plus", "minus", null),
-        defaults["null"]);
-
-    def("ObjectTypeCallProperty")
-      .bases("Node")
-      .build("value")
-      .field("value", def("FunctionTypeAnnotation"))
-      .field("static", Boolean, defaults["false"]);
-
-    def("QualifiedTypeIdentifier")
-      .bases("Node")
-      .build("qualification", "id")
-      .field("qualification",
-        or(def("Identifier"),
-          def("QualifiedTypeIdentifier")))
-      .field("id", def("Identifier"));
-
-    def("GenericTypeAnnotation")
-      .bases("Type")
-      .build("id", "typeParameters")
-      .field("id", or(def("Identifier"), def("QualifiedTypeIdentifier")))
-      .field("typeParameters", or(def("TypeParameterInstantiation"), null));
-
-    def("MemberTypeAnnotation")
-      .bases("Type")
-      .build("object", "property")
-      .field("object", def("Identifier"))
-      .field("property",
-        or(def("MemberTypeAnnotation"),
-          def("GenericTypeAnnotation")));
-
-    def("UnionTypeAnnotation")
-      .bases("Type")
-      .build("types")
-      .field("types", [def("Type")]);
-
-    def("IntersectionTypeAnnotation")
-      .bases("Type")
-      .build("types")
-      .field("types", [def("Type")]);
-
-    def("TypeofTypeAnnotation")
-      .bases("Type")
-      .build("argument")
-      .field("argument", def("Type"));
-
-    def("ObjectTypeSpreadProperty")
-      .bases("Node")
-      .build("argument")
-      .field("argument", def("Type"));
-
-    def("Identifier")
-      .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
-
-    def("ObjectPattern")
-      .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
-
-    def("TypeParameterDeclaration")
-      .bases("Node")
-      .build("params")
-      .field("params", [def("TypeParameter")]);
-
-    def("TypeParameterInstantiation")
-      .bases("Node")
-      .build("params")
-      .field("params", [def("Type")]);
-
-    def("TypeParameter")
-      .bases("Type")
-      .build("name", "variance", "bound")
-      .field("name", String)
-      .field("variance",
-        or("plus", "minus", null),
-        defaults["null"])
-      .field("bound",
-        or(def("TypeAnnotation"), null),
-        defaults["null"]);
-
-    def("Function")
-      .field("returnType",
-        or(def("TypeAnnotation"), null),
-        defaults["null"])
-      .field("typeParameters",
-        or(def("TypeParameterDeclaration"), null),
-        defaults["null"]);
-
-    def("ClassProperty")
-      .build("key", "value", "typeAnnotation", "static")
-      .field("value", or(def("Expression"), null))
-      .field("typeAnnotation", or(def("TypeAnnotation"), null))
-      .field("static", Boolean, defaults["false"])
-      .field("variance",
-        or("plus", "minus", null),
-        defaults["null"]);
-
-    def("ClassImplements")
-      .field("typeParameters",
-        or(def("TypeParameterInstantiation"), null),
-        defaults["null"]);
-
-    def("InterfaceDeclaration")
-      .bases("Declaration")
-      .build("id", "body", "extends")
-      .field("id", def("Identifier"))
-      .field("typeParameters",
-        or(def("TypeParameterDeclaration"), null),
-        defaults["null"])
-      .field("body", def("ObjectTypeAnnotation"))
-      .field("extends", [def("InterfaceExtends")]);
-
-    def("DeclareInterface")
-      .bases("InterfaceDeclaration")
-      .build("id", "body", "extends");
-
-    def("InterfaceExtends")
-      .bases("Node")
-      .build("id")
-      .field("id", def("Identifier"))
-      .field("typeParameters", or(def("TypeParameterInstantiation"), null));
-
-    def("TypeAlias")
-      .bases("Declaration")
-      .build("id", "typeParameters", "right")
-      .field("id", def("Identifier"))
-      .field("typeParameters", or(def("TypeParameterDeclaration"), null))
-      .field("right", def("Type"));
-
-    def("OpaqueType")
-      .bases("Declaration")
-      .build("id", "typeParameters", "impltype", "supertype")
-      .field("id", def("Identifier"))
-      .field("typeParameters", or(def("TypeParameterDeclaration"), null))
-      .field("implType", def("Type"))
-      .field("superType", def("Type"));
-
-    def("DeclareTypeAlias")
-      .bases("TypeAlias")
-      .build("id", "typeParameters", "right");
-
-    def("DeclareOpaqueType")
-      .bases("TypeAlias")
-      .build("id", "typeParameters", "supertype");
-
-    def("TypeCastExpression")
-      .bases("Expression")
-      .build("expression", "typeAnnotation")
-      .field("expression", def("Expression"))
-      .field("typeAnnotation", def("TypeAnnotation"));
-
-    def("TupleTypeAnnotation")
-      .bases("Type")
-      .build("types")
-      .field("types", [def("Type")]);
-
-    def("DeclareVariable")
-      .bases("Statement")
-      .build("id")
-      .field("id", def("Identifier"));
-
-    def("DeclareFunction")
-      .bases("Statement")
-      .build("id")
-      .field("id", def("Identifier"));
-
-    def("DeclareClass")
-      .bases("InterfaceDeclaration")
-      .build("id");
-
-    def("DeclareModule")
-      .bases("Statement")
-      .build("id", "body")
-      .field("id", or(def("Identifier"), def("Literal")))
-      .field("body", def("BlockStatement"));
-
-    def("DeclareModuleExports")
-      .bases("Statement")
-      .build("typeAnnotation")
-      .field("typeAnnotation", def("Type"));
-
-    def("DeclareExportDeclaration")
-      .bases("Declaration")
-      .build("default", "declaration", "specifiers", "source")
-      .field("default", Boolean)
-      .field("declaration", or(
-        def("DeclareVariable"),
-        def("DeclareFunction"),
-        def("DeclareClass"),
-        def("Type"), // Implies default.
-        null
-      ))
-      .field("specifiers", [or(
-        def("ExportSpecifier"),
-        def("ExportBatchSpecifier")
-      )], defaults.emptyArray)
-      .field("source", or(
-        def("Literal"),
-        null
-      ), defaults["null"]);
-
-    def("DeclareExportAllDeclaration")
-      .bases("Declaration")
-      .build("source")
-      .field("source", or(
-        def("Literal"),
-        null
-      ), defaults["null"]);
+  fork.use(require("./es7"));
+
+  var types = fork.use(require("../lib/types"));
+  var def = types.Type.def;
+  var or = types.Type.or;
+  var defaults = fork.use(require("../lib/shared")).defaults;
+
+  // Type Annotations
+  def("Type").bases("Node");
+
+  def("AnyTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("EmptyTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("MixedTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("VoidTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("NumberTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("NumberLiteralTypeAnnotation")
+    .bases("Type")
+    .build("value", "raw")
+    .field("value", Number)
+    .field("raw", String);
+
+  // Babylon 6 differs in AST from Flow
+  // same as NumberLiteralTypeAnnotation
+  def("NumericLiteralTypeAnnotation")
+    .bases("Type")
+    .build("value", "raw")
+    .field("value", Number)
+    .field("raw", String);
+
+  def("StringTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("StringLiteralTypeAnnotation")
+    .bases("Type")
+    .build("value", "raw")
+    .field("value", String)
+    .field("raw", String);
+
+  def("BooleanTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("BooleanLiteralTypeAnnotation")
+    .bases("Type")
+    .build("value", "raw")
+    .field("value", Boolean)
+    .field("raw", String);
+
+  def("TypeAnnotation")
+    .bases("Node")
+    .build("typeAnnotation")
+    .field("typeAnnotation", def("Type"));
+
+  def("NullableTypeAnnotation")
+    .bases("Type")
+    .build("typeAnnotation")
+    .field("typeAnnotation", def("Type"));
+
+  def("NullLiteralTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("NullTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("ThisTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("ExistsTypeAnnotation")
+    .bases("Type")
+    .build();
+
+  def("ExistentialTypeParam")
+    .bases("Type")
+    .build();
+
+  def("FunctionTypeAnnotation")
+    .bases("Type")
+    .build("params", "returnType", "rest", "typeParameters")
+    .field("params", [def("FunctionTypeParam")])
+    .field("returnType", def("Type"))
+    .field("rest", or(def("FunctionTypeParam"), null))
+    .field("typeParameters", or(def("TypeParameterDeclaration"), null));
+
+  def("FunctionTypeParam")
+    .bases("Node")
+    .build("name", "typeAnnotation", "optional")
+    .field("name", def("Identifier"))
+    .field("typeAnnotation", def("Type"))
+    .field("optional", Boolean);
+
+  def("ArrayTypeAnnotation")
+    .bases("Type")
+    .build("elementType")
+    .field("elementType", def("Type"));
+
+  def("ObjectTypeAnnotation")
+    .bases("Type")
+    .build("properties", "indexers", "callProperties")
+    .field("properties", [
+      or(def("ObjectTypeProperty"),
+         def("ObjectTypeSpreadProperty"))
+    ])
+    .field("indexers", [def("ObjectTypeIndexer")], defaults.emptyArray)
+    .field("callProperties",
+           [def("ObjectTypeCallProperty")],
+           defaults.emptyArray)
+    .field("exact", Boolean, defaults["false"]);
+
+  def("Variance")
+    .bases("Node")
+    .build("kind")
+    .field("kind", or("plus", "minus"));
+
+  var LegacyVariance = or(
+    def("Variance"),
+    "plus",
+    "minus",
+    null
+  );
+
+  def("ObjectTypeProperty")
+    .bases("Node")
+    .build("key", "value", "optional")
+    .field("key", or(def("Literal"), def("Identifier")))
+    .field("value", def("Type"))
+    .field("optional", Boolean)
+    .field("variance", LegacyVariance, defaults["null"]);
+
+  def("ObjectTypeIndexer")
+    .bases("Node")
+    .build("id", "key", "value")
+    .field("id", def("Identifier"))
+    .field("key", def("Type"))
+    .field("value", def("Type"))
+    .field("variance", LegacyVariance, defaults["null"]);
+
+  def("ObjectTypeCallProperty")
+    .bases("Node")
+    .build("value")
+    .field("value", def("FunctionTypeAnnotation"))
+    .field("static", Boolean, defaults["false"]);
+
+  def("QualifiedTypeIdentifier")
+    .bases("Node")
+    .build("qualification", "id")
+    .field("qualification",
+           or(def("Identifier"),
+              def("QualifiedTypeIdentifier")))
+    .field("id", def("Identifier"));
+
+  def("GenericTypeAnnotation")
+    .bases("Type")
+    .build("id", "typeParameters")
+    .field("id", or(def("Identifier"), def("QualifiedTypeIdentifier")))
+    .field("typeParameters", or(def("TypeParameterInstantiation"), null));
+
+  def("MemberTypeAnnotation")
+    .bases("Type")
+    .build("object", "property")
+    .field("object", def("Identifier"))
+    .field("property",
+           or(def("MemberTypeAnnotation"),
+              def("GenericTypeAnnotation")));
+
+  def("UnionTypeAnnotation")
+    .bases("Type")
+    .build("types")
+    .field("types", [def("Type")]);
+
+  def("IntersectionTypeAnnotation")
+    .bases("Type")
+    .build("types")
+    .field("types", [def("Type")]);
+
+  def("TypeofTypeAnnotation")
+    .bases("Type")
+    .build("argument")
+    .field("argument", def("Type"));
+
+  def("ObjectTypeSpreadProperty")
+    .bases("Node")
+    .build("argument")
+    .field("argument", def("Type"));
+
+  def("Identifier")
+    .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
+
+  def("ObjectPattern")
+    .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
+
+  def("TypeParameterDeclaration")
+    .bases("Node")
+    .build("params")
+    .field("params", [def("TypeParameter")]);
+
+  def("TypeParameterInstantiation")
+    .bases("Node")
+    .build("params")
+    .field("params", [def("Type")]);
+
+  def("TypeParameter")
+    .bases("Type")
+    .build("name", "variance", "bound")
+    .field("name", String)
+    .field("variance", LegacyVariance, defaults["null"])
+    .field("bound",
+           or(def("TypeAnnotation"), null),
+           defaults["null"]);
+
+  def("Function")
+    .field("returnType",
+           or(def("TypeAnnotation"), null),
+           defaults["null"])
+    .field("typeParameters",
+           or(def("TypeParameterDeclaration"), null),
+           defaults["null"]);
+
+  def("ClassProperty")
+    .build("key", "value", "typeAnnotation", "static")
+    .field("value", or(def("Expression"), null))
+    .field("typeAnnotation", or(def("TypeAnnotation"), null))
+    .field("static", Boolean, defaults["false"])
+    .field("variance", LegacyVariance, defaults["null"]);
+
+  def("ClassImplements")
+    .field("typeParameters",
+           or(def("TypeParameterInstantiation"), null),
+           defaults["null"]);
+
+  def("InterfaceDeclaration")
+    .bases("Declaration")
+    .build("id", "body", "extends")
+    .field("id", def("Identifier"))
+    .field("typeParameters",
+           or(def("TypeParameterDeclaration"), null),
+           defaults["null"])
+    .field("body", def("ObjectTypeAnnotation"))
+    .field("extends", [def("InterfaceExtends")]);
+
+  def("DeclareInterface")
+    .bases("InterfaceDeclaration")
+    .build("id", "body", "extends");
+
+  def("InterfaceExtends")
+    .bases("Node")
+    .build("id")
+    .field("id", def("Identifier"))
+    .field("typeParameters", or(def("TypeParameterInstantiation"), null));
+
+  def("TypeAlias")
+    .bases("Declaration")
+    .build("id", "typeParameters", "right")
+    .field("id", def("Identifier"))
+    .field("typeParameters", or(def("TypeParameterDeclaration"), null))
+    .field("right", def("Type"));
+
+  def("OpaqueType")
+    .bases("Declaration")
+    .build("id", "typeParameters", "impltype", "supertype")
+    .field("id", def("Identifier"))
+    .field("typeParameters", or(def("TypeParameterDeclaration"), null))
+    .field("implType", def("Type"))
+    .field("superType", def("Type"));
+
+  def("DeclareTypeAlias")
+    .bases("TypeAlias")
+    .build("id", "typeParameters", "right");
+
+  def("DeclareOpaqueType")
+    .bases("TypeAlias")
+    .build("id", "typeParameters", "supertype");
+
+  def("TypeCastExpression")
+    .bases("Expression")
+    .build("expression", "typeAnnotation")
+    .field("expression", def("Expression"))
+    .field("typeAnnotation", def("TypeAnnotation"));
+
+  def("TupleTypeAnnotation")
+    .bases("Type")
+    .build("types")
+    .field("types", [def("Type")]);
+
+  def("DeclareVariable")
+    .bases("Statement")
+    .build("id")
+    .field("id", def("Identifier"));
+
+  def("DeclareFunction")
+    .bases("Statement")
+    .build("id")
+    .field("id", def("Identifier"));
+
+  def("DeclareClass")
+    .bases("InterfaceDeclaration")
+    .build("id");
+
+  def("DeclareModule")
+    .bases("Statement")
+    .build("id", "body")
+    .field("id", or(def("Identifier"), def("Literal")))
+    .field("body", def("BlockStatement"));
+
+  def("DeclareModuleExports")
+    .bases("Statement")
+    .build("typeAnnotation")
+    .field("typeAnnotation", def("Type"));
+
+  def("DeclareExportDeclaration")
+    .bases("Declaration")
+    .build("default", "declaration", "specifiers", "source")
+    .field("default", Boolean)
+    .field("declaration", or(
+      def("DeclareVariable"),
+      def("DeclareFunction"),
+      def("DeclareClass"),
+      def("Type"), // Implies default.
+      null
+    ))
+    .field("specifiers", [or(
+      def("ExportSpecifier"),
+      def("ExportBatchSpecifier")
+    )], defaults.emptyArray)
+    .field("source", or(
+      def("Literal"),
+      null
+    ), defaults["null"]);
+
+  def("DeclareExportAllDeclaration")
+    .bases("Declaration")
+    .build("source")
+    .field("source", or(
+      def("Literal"),
+      null
+    ), defaults["null"]);
 };
diff --git a/main.js b/main.js
index c59b665..47d6c56 100644
--- a/main.js
+++ b/main.js
@@ -1,17 +1,16 @@
 module.exports = require('./fork')([
-    // This core module of AST types captures ES5 as it is parsed today by
-    // git://github.com/ariya/esprima.git#master.
-    require("./def/core"),
+  // This core module of AST types captures ES5 as it is parsed today by
+  // git://github.com/ariya/esprima.git#master.
+  require("./def/core"),
 
-    // Feel free to add to or remove from this list of extension modules to
-    // configure the precise type hierarchy that you need.
-    require("./def/es6"),
-    require("./def/es7"),
-    require("./def/mozilla"),
-    require("./def/e4x"),
-    require("./def/jsx"),
-    require("./def/flow"),
-    require("./def/esprima"),
-    require("./def/babel"),
-    require("./def/babel6")
+  // Feel free to add to or remove from this list of extension modules to
+  // configure the precise type hierarchy that you need.
+  require("./def/es6"),
+  require("./def/es7"),
+  require("./def/mozilla"),
+  require("./def/e4x"),
+  require("./def/jsx"),
+  require("./def/flow"),
+  require("./def/esprima"),
+  require("./def/babel")
 ]);
diff --git a/package-lock.json b/package-lock.json
index b5e0ad5..4e0d67c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,13 +1,13 @@
 {
   "name": "ast-types",
-  "version": "0.9.14",
+  "version": "0.10.1",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
     "acorn": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz",
-      "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
+      "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==",
       "dev": true
     },
     "acorn-jsx": {
@@ -50,9 +50,9 @@
       }
     },
     "babylon": {
-      "version": "6.18.0",
-      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+      "version": "7.0.0-beta.31",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz",
+      "integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==",
       "dev": true
     },
     "balanced-match": {
@@ -78,13 +78,10 @@
       "dev": true
     },
     "commander": {
-      "version": "2.9.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
-      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
-      "dev": true,
-      "requires": {
-        "graceful-readlink": "1.0.1"
-      }
+      "version": "2.11.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+      "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
+      "dev": true
     },
     "concat-map": {
       "version": "0.0.1",
@@ -99,18 +96,18 @@
       "dev": true
     },
     "debug": {
-      "version": "2.6.8",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
-      "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+      "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
       "dev": true,
       "requires": {
         "ms": "2.0.0"
       }
     },
     "diff": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
-      "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
+      "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
       "dev": true
     },
     "escape-string-regexp": {
@@ -120,12 +117,12 @@
       "dev": true
     },
     "espree": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz",
-      "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=",
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
+      "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
       "dev": true,
       "requires": {
-        "acorn": "5.1.2",
+        "acorn": "5.2.1",
         "acorn-jsx": "3.0.1"
       }
     },
@@ -154,9 +151,9 @@
       "dev": true
     },
     "glob": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
-      "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=",
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
       "dev": true,
       "requires": {
         "fs.realpath": "1.0.0",
@@ -167,22 +164,16 @@
         "path-is-absolute": "1.0.1"
       }
     },
-    "graceful-readlink": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
-      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
-      "dev": true
-    },
     "growl": {
-      "version": "1.9.2",
-      "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz",
-      "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=",
+      "version": "1.10.3",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
+      "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
       "dev": true
     },
     "has-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
-      "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+      "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
       "dev": true
     },
     "he": {
@@ -207,86 +198,12 @@
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
       "dev": true
     },
-    "json3": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
-      "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=",
-      "dev": true
-    },
     "lodash": {
       "version": "4.17.4",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
       "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
       "dev": true
     },
-    "lodash._baseassign": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
-      "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=",
-      "dev": true,
-      "requires": {
-        "lodash._basecopy": "3.0.1",
-        "lodash.keys": "3.1.2"
-      }
-    },
-    "lodash._basecopy": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
-      "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=",
-      "dev": true
-    },
-    "lodash._basecreate": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz",
-      "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=",
-      "dev": true
-    },
-    "lodash._getnative": {
-      "version": "3.9.1",
-      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
-      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
-      "dev": true
-    },
-    "lodash._isiterateecall": {
-      "version": "3.0.9",
-      "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
-      "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",
-      "dev": true
-    },
-    "lodash.create": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz",
-      "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=",
-      "dev": true,
-      "requires": {
-        "lodash._baseassign": "3.2.0",
-        "lodash._basecreate": "3.0.3",
-        "lodash._isiterateecall": "3.0.9"
-      }
-    },
-    "lodash.isarguments": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
-      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
-      "dev": true
-    },
-    "lodash.isarray": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
-      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
-      "dev": true
-    },
-    "lodash.keys": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
-      "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
-      "dev": true,
-      "requires": {
-        "lodash._getnative": "3.9.1",
-        "lodash.isarguments": "3.1.0",
-        "lodash.isarray": "3.0.4"
-      }
-    },
     "minimatch": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -312,9 +229,9 @@
       }
     },
     "minizlib": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.0.3.tgz",
-      "integrity": "sha1-1cGr93vhVGGZUuJTM27Mq5sqMvU=",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.0.4.tgz",
+      "integrity": "sha512-sN4U9tIJtBRwKbwgFh9qJfrPIQ/GGTRr1MGqkgOeMTLy8/lM0FcWU//FqlnZ3Vb7gJ+Mxh3FOg1EklibdajbaQ==",
       "dev": true,
       "requires": {
         "minipass": "2.2.1"
@@ -330,23 +247,21 @@
       }
     },
     "mocha": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz",
-      "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz",
+      "integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==",
       "dev": true,
       "requires": {
         "browser-stdout": "1.3.0",
-        "commander": "2.9.0",
-        "debug": "2.6.8",
-        "diff": "3.2.0",
+        "commander": "2.11.0",
+        "debug": "3.1.0",
+        "diff": "3.3.1",
         "escape-string-regexp": "1.0.5",
-        "glob": "7.1.1",
-        "growl": "1.9.2",
+        "glob": "7.1.2",
+        "growl": "1.10.3",
         "he": "1.1.1",
-        "json3": "3.3.2",
-        "lodash.create": "3.1.1",
         "mkdirp": "0.5.1",
-        "supports-color": "3.1.2"
+        "supports-color": "4.4.0"
       }
     },
     "ms": {
@@ -383,8 +298,16 @@
       "dev": true,
       "requires": {
         "acorn": "5.1.2",
-        "minizlib": "1.0.3",
+        "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
+        }
       }
     },
     "semver": {
@@ -394,12 +317,12 @@
       "dev": true
     },
     "supports-color": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz",
-      "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
+      "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
       "dev": true,
       "requires": {
-        "has-flag": "1.0.0"
+        "has-flag": "2.0.0"
       }
     },
     "to-fast-properties": {
diff --git a/package.json b/package.json
index a7309eb..8b92b08 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
     "transformation",
     "syntax"
   ],
-  "version": "0.9.14",
+  "version": "0.10.1",
   "homepage": "http://github.com/benjamn/ast-types",
   "repository": {
     "type": "git",
@@ -32,11 +32,11 @@
   "dependencies": {},
   "devDependencies": {
     "babel-types": "^6.26.0",
-    "babylon": "^6.16.1",
+    "babylon": "^7.0.0-beta.31",
     "espree": "^3.1.7",
     "esprima": "~4.0.0",
     "esprima-fb": "~14001.1.0-dev-harmony-fb",
-    "mocha": "^3.4.2",
+    "mocha": "^4.0.1",
     "reify": "^0.12.0"
   },
   "engines": {
diff --git a/test/run.js b/test/run.js
index d84bb4e..bcf5b2c 100644
--- a/test/run.js
+++ b/test/run.js
@@ -17,2242 +17,2307 @@ 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;
+  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"))
-          )
-        );
-    });
+  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;
+  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")));
+    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.
-    });
+    // 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 resolve the most precise supertypes", function() {
+    var table = types.use(require("../lib/types")).computeSupertypeLookupTable({
+      Function: true,
+      Declaration: true,
+      ArrowFunctionExpression: true,
+      Expression: true,
+      Identifier: true
     });
 
-    it("should properly linearize the inheritance hierarchy", function() {
-        assert.deepEqual(
-            types.getSupertypeNames("FunctionExpression"),
-            ["Function", "Expression", "Pattern", "Node", "Printable"]
-        );
-    });
+    function check(subtype, expectedSupertype) {
+      assert.strictEqual(table[subtype], expectedSupertype);
+    }
 
-    it("should trigger an AssertionError for unknown types", function() {
-        assert.throws(function() {
-            types.getSupertypeNames("AlienBoomerangDeclaration");
-        });
+    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));
-    });
+  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);
+  var fullPath = path.join(__dirname, "..", file);
 
-    it("should validate " + file + " with Esprima", function(done) {
-        var parse = require("esprima").parse;
+  it("should validate " + file + " with Esprima", function(done) {
+    var parse = require("esprima").parse;
 
-        fs.readFile(fullPath, "utf8", function(err, code) {
-            if (err) throw err;
+    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);
+      n.Program.assert(parse(code), true);
+      n.Program.assert(parse(code, { loc: true }), true);
 
-            done();
-        });
+      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();
-        });
+  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");
+  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");
-    });
+  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
-        );
+  it("should work for explicit fields", function() {
+    assert.strictEqual(
+      types.getFieldValue({
+        type: "CatchClause"
+      }, "type"),
+      "CatchClause"
+    );
 
-        assert.strictEqual(
-            types.getFieldValue({
-                type: "CatchClause"
-            }, "asdf"),
-            void 0
-        );
+    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.deepEqual(
-            types.getFieldValue({
-                type: "TryStatement",
-            }, "handler"),
-            null
-        );
+    assert.strictEqual(
+      types.getFieldValue({
+        type: "CatchClause"
+      }, "asdf"),
+      void 0
+    );
 
-        assert.deepEqual(
-            types.getFieldValue({
-                type: "TryStatement",
-            }, "handlers"),
-            []
-        );
+    assert.deepEqual(
+      types.getFieldValue({
+        type: "TryStatement",
+      }, "handler"),
+      null
+    );
 
-        assert.deepEqual(
-            types.getFieldValue({
-                type: "TryStatement",
-            }, "guardedHandlers"),
-            []
-        );
-    });
+    assert.deepEqual(
+      types.getFieldValue({
+        type: "TryStatement",
+      }, "handlers"),
+      []
+    );
 
-    it("should work for explicitly undefined fields", function() {
-        assert.deepEqual(
-            types.getFieldValue({
-                type: "TryStatement",
-                guardedHandlers: void 0
-            }, "guardedHandlers"),
-            []
-        );
-    });
+    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
-        );
-    });
+  it("should handle undefined objects", function() {
+    assert.equal(
+      types.getFieldValue(undefined, "name"),
+      undefined
+    );
+  });
 });
 
 describe("types.eachField", function() {
-    var context = {};
+  var context = {};
 
-    function check(node, names) {
-        var seen = [];
+  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);
+    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());
-    }
+    assert.deepEqual(seen.sort(), names.sort());
+  }
 
-    it("should give correct keys for supertypes", function() {
-        check({ type: "Expression" }, ["type"]);
-    });
+  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 work for non-buildable types", function() {
+    check({ type: "Position" }, [
+      "type", "line", "column"
     ]);
 
-    it("should complain about invalid types", function() {
-        assert.throws(function() {
-            check({ type: "asdf" }, ["type"]);
-        }, "did not recognize object of type " + JSON.stringify("asdf"));
-    });
+    check({ type: "SourceLocation" }, [
+      "type", "start", "end", "source"
+    ]);
+  });
 
-    it("should infer SourceLocation types", function() {
-        check({
-            line: 10,
-            column: 37
-        }, ["line", "column"]);
-    });
+  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 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();
+        }
+      },
 
-    var ts = b.tryStatement(
-        b.blockStatement([call, call]),
-        b.catchClause(
-            b.identifier("err"),
-            null,
-            b.blockStatement([])
-        )
-    );
+      visitLiteral: function(path) {
+        literal = path.value;
+        this.traverse(path);
+      },
 
-    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);
+      visitNode: function(path) {
+        unvisitedTypes.push(path.value.type);
+        this.traverse(path);
+      }
     });
 
-    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 });
+    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();
+        }
+      },
 
-        ids = {};
+      visitMemberExpression: function(path) {
+        try {
+          this.traverse(path);
+        } catch (err) {
+          assert.ok(err instanceof this.AbortRequest);
+          err.cancel();
+        }
+      },
 
-        types.visit(ts, {
-            visitIdentifier: function(path) {
-                ids[path.node.name] = true;
-                this.traverse(path);
-            }
-        });
+      visitLiteral: function(path) {
+        literal = path.value;
+        this.traverse(path);
+      },
 
-        // Now make sure those identifiers (foo and bar) were visited.
-        assert.deepEqual(ids, {
-            err: true,
-            foo: true,
-            bar: true
-        });
+      visitNode: function(path) {
+        unvisitedTypes.push(path.value.type);
+        this.traverse(path);
+      }
     });
 
-    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"
-        ]);
-    });
+    assert.strictEqual(root, call);
 
-    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);
-            }
-        });
+    n.Literal.assert(literal);
+    assert.strictEqual(literal.value, "baz");
+    assert.strictEqual(literal, call.expression.arguments[0]);
 
-        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.
-        ]);
+    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);
+        }
+      }
     });
 
-    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(blockComments.length, 1);
+    assert.strictEqual(blockComments[0].value, "arguments");
 
-        assert.strictEqual(lineComments.length, 1);
-        assert.strictEqual(
-            lineComments[0].value,
-            " Turn arguments into an array."
-        );
+    assert.strictEqual(lineComments.length, 1);
+    assert.strictEqual(
+      lineComments[0].value,
+      " Turn arguments into an array."
+    );
 
-        blockComments.length = 0;
-        lineComments.length = 0;
+    blockComments.length = 0;
+    lineComments.length = 0;
 
-        types.visit(ast, {
-            visitBlock: function(path) {
-                blockComments.push(path.value);
-                this.traverse(path);
-            }
-        });
+    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(blockComments.length, 1);
+    assert.strictEqual(blockComments[0].value, "arguments");
 
-        assert.strictEqual(lineComments.length, 0);
+    assert.strictEqual(lineComments.length, 0);
 
-        blockComments.length = 0;
-        lineComments.length = 0;
+    blockComments.length = 0;
+    lineComments.length = 0;
 
-        types.visit(ast, {
-            visitLine: function(path) {
-                lineComments.push(path.value);
-                this.traverse(path);
-            }
-        });
+    types.visit(ast, {
+      visitLine: function(path) {
+        lineComments.push(path.value);
+        this.traverse(path);
+      }
+    });
 
-        assert.strictEqual(blockComments.length, 0);
+    assert.strictEqual(blockComments.length, 0);
 
-        assert.strictEqual(lineComments.length, 1);
-        assert.strictEqual(
-            lineComments[0].value,
-            " Turn arguments into an array."
-        );
+    assert.strictEqual(lineComments.length, 1);
+    assert.strictEqual(
+      lineComments[0].value,
+      " Turn arguments into an array."
+    );
 
-        blockComments.length = 0;
-        lineComments.length = 0;
+    blockComments.length = 0;
+    lineComments.length = 0;
 
-        types.visit(ast, {
-            visitBlock: function(path) {
-                blockComments.push(path.value);
-                this.traverse(path);
-            },
+    types.visit(ast, {
+      visitBlock: function(path) {
+        blockComments.push(path.value);
+        this.traverse(path);
+      },
 
-            visitLine: function(path) {
-                lineComments.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(blockComments.length, 1);
+    assert.strictEqual(blockComments[0].value, "arguments");
 
-        assert.strictEqual(lineComments.length, 1);
-        assert.strictEqual(
-            lineComments[0].value,
-            " Turn arguments into an array."
-        );
-    });
+    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);
-            }
-        });
+  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);
+        }
 
-        assert.strictEqual(idCount, 2);
+        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);
-    });
+  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")
-        ]))
+  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 path = new NodePath(ast);
+    var sequenceAssignmentPath = new NodePath(sequenceAssignmentAST);
+    assert.ok(sequenceAssignmentPath.get("right").needsParens());
+  });
 
-    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);
-    });
+  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);
 
-    var binaryYield = b.expressionStatement(
-        b.logicalExpression(
-            "&&",
-            b.yieldExpression(b.identifier("a"), false),
-            b.yieldExpression(b.identifier("b"), true)
-        )
-    );
+    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 support .needsParens()", function() {
-        var argPath = path.get("expression", "argument");
-        assert.ok(argPath.needsParens());
+  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);
 
-        var exprsPath = argPath.get("expressions");
-        assert.ok(!exprsPath.needsParens());
-        assert.strictEqual(exprsPath.get("length").value, 3);
-        assert.ok(!exprsPath.get(1).needsParens());
+    n.VariableDeclarator.assert(yVariableDeclaratorPath.node);
+    n.VariableDeclarator.assert(xVariableDeclaratorPath.node);
 
-        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 remainingNodePath = yVariableDeclaratorPath.prune();
 
-        var sequenceAssignmentAST = b.assignmentExpression(
-          '=',
-          b.identifier('a'),
-          b.sequenceExpression([b.literal(1), b.literal(2)])
-        );
+    assert.strictEqual(remainingNodePath, variableDeclaration);
 
-        var sequenceAssignmentPath = new NodePath(sequenceAssignmentAST);
-        assert.ok(sequenceAssignmentPath.get("right").needsParens());
-    });
+    remainingNodePath = xVariableDeclaratorPath.prune();
 
-    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);
-    });
+    assert.strictEqual(remainingNodePath, funBlockStatementPath);
+    assert.strictEqual(funBlockStatementPath.get("body", 0).value, undefined);
+  });
 
-    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);
+  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.VariableDeclarator.assert(yVariableDeclaratorPath.node);
-        n.VariableDeclarator.assert(xVariableDeclaratorPath.node);
+    n.AssignmentExpression.assert(assignmentExpressionPath.node);
 
-        var remainingNodePath = yVariableDeclaratorPath.prune();
+    var remainingNodePath = assignmentExpressionPath.prune();
 
-        assert.strictEqual(remainingNodePath, variableDeclaration);
+    assert.strictEqual(remainingNodePath, funBlockStatementPath);
+    assert.strictEqual(funBlockStatementPath.value.body.length, 0);
+  });
 
-        remainingNodePath = xVariableDeclaratorPath.prune();
+  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");
 
-        assert.strictEqual(remainingNodePath, funBlockStatementPath);
-        assert.strictEqual(funBlockStatementPath.get("body", 0).value, undefined);
-    });
+    n.BlockStatement.assert(consequentNodePath.node);
 
-    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");
+    var remainingNodePath = consequentNodePath.prune();
 
-        n.AssignmentExpression.assert(assignmentExpressionPath.node);
+    var testExpressionNodePath = programPath.get("body", 0);
 
-        var remainingNodePath = assignmentExpressionPath.prune();
+    n.ExpressionStatement.assert(remainingNodePath.node);
+    assert.strictEqual(remainingNodePath, testExpressionNodePath);
+  });
 
-        assert.strictEqual(remainingNodePath, funBlockStatementPath);
-        assert.strictEqual(funBlockStatementPath.value.body.length, 0);
-    });
+  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");
 
-    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);
 
-        n.BlockStatement.assert(consequentNodePath.node);
+    var remainingNodePath = consequentNodePath.prune();
 
-        var remainingNodePath = consequentNodePath.prune();
+    var modifiedIfStatementNodePath = programPath.get("body", 0);
+    var negatedTestExpression = modifiedIfStatementNodePath.get("test");
 
-        var testExpressionNodePath = programPath.get("body", 0);
+    n.IfStatement.assert(remainingNodePath.node);
+    n.UnaryExpression.assert(negatedTestExpression.node);
+    assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
+    assert.strictEqual(negatedTestExpression.node.operator, "!");
+  });
 
-        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");
+  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);
+    n.BlockStatement.assert(consequentNodePath.node);
 
-        var remainingNodePath = consequentNodePath.prune();
+    var remainingNodePath = consequentNodePath.prune();
 
-        var modifiedIfStatementNodePath = programPath.get("body", 0);
-        var testExpression = modifiedIfStatementNodePath.get("test");
+    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);
-    });
+    n.IfStatement.assert(remainingNodePath.node);
+    n.Identifier.assert(testExpression.node);
+    assert.strictEqual(remainingNodePath, modifiedIfStatementNodePath);
+  });
 });
 
 describe("path.replace", function() {
-    var ast;
+  var ast;
+
+  beforeEach(function() {
+    ast = b.functionDeclaration(
+      b.identifier("fn"),
+      [],
+      b.blockStatement([
+        b.variableDeclaration(
+          "var",
+          [b.variableDeclarator(b.identifier("a"), null)]
+        )
+      ])
+    );
+  });
 
-    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
         );
-    });
 
-    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);
-            }
-        });
+        // 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.equal(ast.body.body[0].declarations[0].id.name, "b");
-    });
+        assert.strictEqual(scopeBody.get(0), path);
 
-    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]));
+        // Then replace the node, not the one we just added.
+        return b.returnStatement(b.identifier("$3"));
+      }
     });
 
-    it("should support replacement with nothing", function() {
-        types.visit(ast, {
-            visitVariableDeclaration: function(path) {
-                path.replace();
-                this.traverse(path);
-            }
-        });
+    var statements = ast.body.body;
+    assert.deepEqual(
+      statements.map(function(node) { return node.type; }),
+      ['ReturnStatement', 'VariableDeclaration', 'VariableDeclaration']
+    );
 
-        assert.equal(ast.body.body.length, 0);
-    });
+    n.ReturnStatement.assert(statements[0]);
+    assert.equal(statements[0].argument.name, "$3");
 
-    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"));
-            }
-        });
+    n.VariableDeclaration.assert(statements[1]);
+    assert.equal(statements[1].declarations[0].id.name, "$$");
 
-        var statements = ast.body.body;
-        assert.deepEqual(
-            statements.map(function(node) { return node.type; }),
-            ['ReturnStatement', 'VariableDeclaration', 'VariableDeclaration']
-        );
+    n.VariableDeclaration.assert(statements[2]);
+    assert.equal(statements[2].declarations[0].id.name, "a");
+  });
 
-        n.ReturnStatement.assert(statements[0]);
-        assert.equal(statements[0].argument.name, "$3");
+  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);
 
-        n.VariableDeclaration.assert(statements[1]);
-        assert.equal(statements[1].declarations[0].id.name, "$$");
+        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");
 
-        n.VariableDeclaration.assert(statements[2]);
-        assert.equal(statements[2].declarations[0].id.name, "a");
-    });
+        if (path.parentPath.get(path.name) !== path) {
+          assert.ok(false, "Should have reused the same path");
+        }
 
-    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);
-            }
-        });
+        this.traverse(path);
+      }
     });
+  });
 });
 
 describe("global scope", function() {
-    var scope = [
-        "var foo = 42;",
-        "function bar(baz) {",
-        "  return baz + foo;",
-        "}"
-    ];
+  var scope = [
+    "var foo = 42;",
+    "function bar(baz) {",
+    "  return baz + foo;",
+    "}"
+  ];
 
-    var ast = parse(scope.join("\n"));
+  var ast = parse(scope.join("\n"));
 
-    it("should be reachable from nested scopes", function() {
-        var globalScope;
+  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);
-            },
+    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);
+      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(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);
+        assert.strictEqual(path.scope.getGlobalScope(), globalScope);
 
-                this.traverse(path);
-            }
-        });
+        this.traverse(path);
+      }
     });
+  });
 
-    it("should be found by .lookup and .declares", function() {
-        var globalScope;
+  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);
-            },
+    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);
+      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.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);
+        assert.strictEqual(path.scope.lookup("qux"), null);
+        assert.strictEqual(globalScope.lookup("baz"), null);
 
-                this.traverse(path);
-            }
-        });
+        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']
-        );
+  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);
+      }
     });
 
-    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;
+    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"}
+    );
 
-        types.visit(ast, {
-            visitProgram: function(path) {
-                names = Object.keys(path.scope.getBindings()).sort();
-                this.traverse(path);
-            }
-        });
+    var names;
 
-        assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
+    types.visit(ast, {
+      visitProgram: function(path) {
+        names = Object.keys(path.scope.getBindings()).sort();
+        this.traverse(path);
+      }
     });
 
-    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"]);
+  });
 
-        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
     });
 
-    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
-        });
+    var names;
 
-        types.visit(ast, {
-            visitFunctionDeclaration: function(path) {
-                names = Object.keys(path.scope.lookup("zap").getBindings()).sort();
-                assert.deepEqual(names, ["zap"]);
-                this.traverse(path);
-            }
-        });
+    types.visit(ast, {
+      visitProgram: function(path) {
+        names = Object.keys(path.scope.getBindings()).sort();
+        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);
-            }
-        });
-    });
+    assert.deepEqual(names, ["x", "xyDefault", "xyNamespace", "z"]);
+  });
 
-    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);
-            }
-        });
+  it("should work for ES6 syntax (espree)", function() {
+    var names;
 
-        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");
+    var ast = require("espree").parse([
+      "var zap;",
+      "export default function(zom) {",
+      "    var innerFn = function(zip) {};",
+      "    return innerFn(zom);",
+      "};"
+    ].join("\n"), {
+      sourceType: "module",
+      ecmaVersion: 6
     });
-});
 
-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);
+    types.visit(ast, {
+      visitFunctionDeclaration: function(path) {
+        names = Object.keys(path.scope.lookup("zap").getBindings()).sort();
+        assert.deepEqual(names, ["zap"]);
+        this.traverse(path);
+      }
     });
+  });
 
-    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 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("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);
-    });
-});
+  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")
+            )
+          ])
+        );
 
-describe("array and object pattern scope", function() {
+        this.traverse(path);
+      },
 
-    function scopeFromPattern(pattern) {
-        return new NodePath(
-            b.program([
-                b.variableDeclaration('var', [
-                    b.variableDeclarator(pattern, null)
-                ])
-            ])
-        ).scope;
-    }
+      visitFunction: function(path) {
+        var funcId = path.value.id;
 
-    // ObjectPattern with Property and SpreadProperty
-    // ArrayPattern with SpreadElement
-    describe("esprima", function() {
-        var types = require('../fork')([
-            require("../def/esprima")
+        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)
+          )
         ]);
-        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);
+        path.get("body", "body").unshift(varDecl);
 
-            assert.strictEqual(scope.declares("a"), true);
-            assert.strictEqual(scope.declares("b"), false);
-            assert.strictEqual(scope.declares("c"), true);
-            assert.strictEqual(scope.declares("d"), true);
-        });
+        if (funcId.name === "bar") {
+          barVarDecl = varDecl;
+        } else if (funcId.name === "rom") {
+          romVarDecl = varDecl;
+        }
 
-        it("should handle array patterns in variable declarations", function() {
-            var scope = scopeFromPattern(arrayPattern);
+        this.traverse(path);
+      }
+    });
 
-            assert.strictEqual(scope.declares("foo"), true);
-            assert.strictEqual(scope.declares("bar"), true);
-            assert.strictEqual(scope.declares("baz"), true);
-        });
+    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");
+  });
+});
 
-        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);
-        });
-    });
+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);
+  });
+});
 
-    // 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'))
-            ]);
-        });
+describe("array and object pattern scope", function() {
 
-        it("should handle object patterns variable declarations", function() {
-            var scope = scopeFromPattern(objectPattern);
+  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;
 
-            assert.strictEqual(scope.declares("a"), true);
-            assert.strictEqual(scope.declares("b"), false);
-            assert.strictEqual(scope.declares("c"), true);
-            assert.strictEqual(scope.declares("d"), true);
-        });
+    var objectPattern;
+    var arrayPattern;
 
-        it("should handle array patterns in variable declarations", function() {
-            var scope = scopeFromPattern(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;
 
-            assert.strictEqual(scope.declares("foo"), true);
-            assert.strictEqual(scope.declares("bar"), true);
-            assert.strictEqual(scope.declares("baz"), true);
-        });
+    var objectPattern;
+    var arrayPattern;
 
-        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);
-        });
-    });
+    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;
-    }
+  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);
+  });
+});
 
-    var thisExpr = b.thisExpression();
+describe("types.visit", function() {
+  var objProp;
 
-    it("should allow defining an .at method", function() {
-        assert.strictEqual(types.defineMethod("at", at), void 0);
-        assert.strictEqual(thisExpr.loc, null);
+  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?
+        }
+      });
 
-        thisExpr.at(b.sourceLocation(
-            b.position(1, 0),
-            b.position(1, 4)
-        ));
+      assert.ok(false, "should have thrown an exception");
 
-        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);
-    });
+    } catch (err) {
+      assert.strictEqual(
+        err.message,
+        "Must either call this.traverse or return false in visitIdentifier"
+      );
+    }
+  });
 
-    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);
-    });
-});
+  it("should support this.traverse", function() {
+    var idNames = [];
 
-describe("types.visit", function() {
-    var objProp;
+    types.visit(objProp, {
+      visitMemberExpression: function(path) {
+        this.traverse(path, {
+          visitIdentifier: function(path) {
+            idNames.push("*" + path.value.name + "*");
+            return false;
+          }
+        });
 
-    beforeEach(function() {
-        objProp = b.memberExpression(
-            b.identifier("object"),
-            b.identifier("property"),
-            false
-        );
-    });
+        path.get("object", "name").replace("asdfasdf");
+        path.get("property", "name").replace("zxcvzxcv");
 
-    it("should be identical to PathVisitor.visit", function() {
-        assert.strictEqual(types.visit, PathVisitor.visit);
-    });
+        this.visit(path.get("property"));
+      },
 
-    it("should work with no visitors", function() {
-        var foo = b.identifier("foo");
-        assert.strictEqual(types.visit(foo), foo);
+      visitIdentifier: function(path) {
+        idNames.push(path.value.name);
+        return false;
+      }
     });
 
-    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;
-            }
-        });
+    assert.deepEqual(idNames, ["*object*", "*property*", "zxcvzxcv"]);
+
+    idNames.length = 0;
 
-        n.Identifier.assert(bar);
-        assert.strictEqual(bar.name, "bar");
+    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;
+          }
+        });
+      }
     });
 
-    it("should complain about missing this.traverse", function() {
-        try {
-            types.visit(objProp, {
-                visitIdentifier: function(path) {
-                    // buh?
-                }
-            });
+    assert.deepEqual(idNames, ["asdfasdf", "zxcvzxcv"]);
+  });
 
-            assert.ok(false, "should have thrown an exception");
+  it("should support this.replace", function() {
+    var seqExpr = b.sequenceExpression([
+      b.literal("asdf"),
+      b.identifier("zxcv"),
+      b.thisExpression()
+    ]);
 
-        } catch (err) {
-            assert.strictEqual(
-                err.message,
-                "Must either call this.traverse or return false in visitIdentifier"
-            );
-        }
+    types.visit(seqExpr, {
+      visitIdentifier: function(path) {
+        assert.strictEqual(path.value.name, "zxcv");
+        path.replace(
+          b.identifier("foo"),
+          b.identifier("bar")
+        );
+        return false;
+      }
     });
 
-    it("should support this.traverse", function() {
-        var idNames = [];
+    assert.strictEqual(seqExpr.expressions.length, 4);
 
-        types.visit(objProp, {
-            visitMemberExpression: function(path) {
-                this.traverse(path, {
-                    visitIdentifier: function(path) {
-                        idNames.push("*" + path.value.name + "*");
-                        return false;
-                    }
-                });
+    var foo = seqExpr.expressions[1];
+    n.Identifier.assert(foo);
+    assert.strictEqual(foo.name, "foo");
 
-                path.get("object", "name").replace("asdfasdf");
-                path.get("property", "name").replace("zxcvzxcv");
+    var bar = seqExpr.expressions[2];
+    n.Identifier.assert(bar);
+    assert.strictEqual(bar.name, "bar");
 
-                this.visit(path.get("property"));
-            },
+    types.visit(seqExpr, {
+      visitIdentifier: function(path) {
+        if (path.value.name === "foo") {
+          path.replace(path.value, path.value);
+        }
 
-            visitIdentifier: function(path) {
-                idNames.push(path.value.name);
-                return false;
-            }
-        });
+        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.strictEqual(seqExpr.expressions.length, 5);
 
-        assert.deepEqual(idNames, ["asdfasdf", "zxcvzxcv"]);
-    });
+    var foo = seqExpr.expressions[1];
+    n.Identifier.assert(foo);
+    assert.strictEqual(foo.name, "foo");
 
-    it("should support this.replace", function() {
-        var seqExpr = b.sequenceExpression([
-            b.literal("asdf"),
-            b.identifier("zxcv"),
-            b.thisExpression()
-        ]);
+    var foo = seqExpr.expressions[2];
+    n.Identifier.assert(foo);
+    assert.strictEqual(foo.name, "foo");
 
-        types.visit(seqExpr, {
-            visitIdentifier: function(path) {
-                assert.strictEqual(path.value.name, "zxcv");
-                path.replace(
-                    b.identifier("foo"),
-                    b.identifier("bar")
-                );
-                return false;
-            }
-        });
+    var bar = seqExpr.expressions[3];
+    n.Identifier.assert(bar);
+    assert.strictEqual(bar.name, "bar");
 
-        assert.strictEqual(seqExpr.expressions.length, 4);
+    types.visit(seqExpr, {
+      visitLiteral: function(path) {
+        path.replace();
+        return false;
+      },
 
-        var foo = seqExpr.expressions[1];
-        n.Identifier.assert(foo);
-        assert.strictEqual(foo.name, "foo");
+      visitIdentifier: function(path) {
+        if (path.value.name === "bar") {
+          path.replace();
+        }
 
-        var bar = seqExpr.expressions[2];
-        n.Identifier.assert(bar);
-        assert.strictEqual(bar.name, "bar");
+        return false;
+      }
+    });
 
-        types.visit(seqExpr, {
-            visitIdentifier: function(path) {
-                if (path.value.name === "foo") {
-                    path.replace(path.value, path.value);
-                }
+    assert.strictEqual(seqExpr.expressions.length, 3);
 
-                return false;
-            }
-        });
+    var first = seqExpr.expressions[0];
+    n.Identifier.assert(first);
+    assert.strictEqual(first.name, "foo");
 
-        assert.strictEqual(seqExpr.expressions.length, 5);
+    var second = seqExpr.expressions[1];
+    assert.strictEqual(second, first);
 
-        var foo = seqExpr.expressions[1];
-        n.Identifier.assert(foo);
-        assert.strictEqual(foo.name, "foo");
+    var third = seqExpr.expressions[2];
+    n.ThisExpression.assert(third);
+  });
 
-        var foo = seqExpr.expressions[2];
-        n.Identifier.assert(foo);
-        assert.strictEqual(foo.name, "foo");
+  it("should reuse old VisitorContext objects", function() {
+    var objectContext;
+    var propertyContext;
 
-        var bar = seqExpr.expressions[3];
-        n.Identifier.assert(bar);
-        assert.strictEqual(bar.name, "bar");
+    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()]
+    );
 
-        types.visit(seqExpr, {
-            visitLiteral: function(path) {
-                path.replace();
-                return false;
-            },
+    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);
+      };
+    }
 
-            visitIdentifier: function(path) {
-                if (path.value.name === "bar") {
-                    path.replace();
-                }
+    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]);
+      }
+    }
 
-                return false;
-            }
-        });
+    check(nodes);
 
-        assert.strictEqual(seqExpr.expressions.length, 3);
+    check(expressions,
+          callExpr,
+          callExpr.callee,
+          callExpr.callee.object.body.body[0].argument,
+          callExpr.arguments[0]);
 
-        var first = seqExpr.expressions[0];
-        n.Identifier.assert(first);
-        assert.strictEqual(first.name, "foo");
+    check(identifiers,
+          callExpr.callee.object.id,
+          foo,
+          bar,
+          foo,
+          bar,
+          callExpr.callee.property);
 
-        var second = seqExpr.expressions[1];
-        assert.strictEqual(second, first);
+    check(statements,
+          callExpr.callee.object.body);
 
-        var third = seqExpr.expressions[2];
-        n.ThisExpression.assert(third);
-    });
+    check(returnStatements,
+          callExpr.callee.object.body.body[0]);
 
-    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;
-                }
-            }
-        });
+    check(functions,
+          callExpr.callee.object);
+  });
 
-        assert.ok(objectContext);
-        assert.ok(propertyContext);
-        assert.strictEqual(objectContext, propertyContext);
-    });
+  it("should replace this.currentPath with returned value", function() {
+    assert.strictEqual(objProp.computed, false);
 
-    it("should dispatch to closest visitSupertype method", function() {
-        var foo = b.identifier("foo");
-        var bar = b.identifier("bar");
-        var callExpr = b.callExpression(
+    types.visit(objProp, {
+      visitIdentifier: function(path) {
+        if (path.value.name === "property") {
+          path.parent.get("computed").replace(true);
+          return 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(),
+              b.identifier("toString"),
+              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);
+        this.traverse(path);
+      },
 
-        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);
+      visitThisExpression: function(path) {
+        return b.identifier("self");
+      }
     });
 
-    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);
+    assert.strictEqual(objProp.computed, true);
+    n.CallExpression.assert(objProp.property);
 
-        var callee = objProp.property.callee;
-        n.MemberExpression.assert(callee);
+    var callee = objProp.property.callee;
+    n.MemberExpression.assert(callee);
 
-        n.Identifier.assert(callee.object);
-        assert.strictEqual(callee.object.name, "self");
+    n.Identifier.assert(callee.object);
+    assert.strictEqual(callee.object.name, "self");
 
-        n.Identifier.assert(callee.property);
-        assert.strictEqual(callee.property.name, "toString");
+    n.Identifier.assert(callee.property);
+    assert.strictEqual(callee.property.name, "toString");
 
-        assert.deepEqual(objProp.property.arguments, []);
-    });
+    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]
-        });
+  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 first = path.get("elements", 0);
+    assert.strictEqual(first.name, 0);
 
-        var second = path.get("elements", 1);
-        assert.strictEqual(second.name, 1);
+    var second = path.get("elements", 1);
+    assert.strictEqual(second.name, 1);
 
-        var third = path.get("elements", 2);
-        assert.strictEqual(third.name, 2);
+    var third = path.get("elements", 2);
+    assert.strictEqual(third.name, 2);
 
-        assert.strictEqual(path.get("elements", "length").value, 3);
+    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(), 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(), 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);
-    });
+    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();
-        });
+  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();
-        });
-    });
+  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");
-        });
-    });
+  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]
-        });
+  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 first = path.get("elements", 0);
+    assert.strictEqual(first.name, 0);
 
-        var second = path.get("elements", 1);
-        assert.strictEqual(second.name, 1);
+    var second = path.get("elements", 1);
+    assert.strictEqual(second.name, 1);
 
-        var third = path.get("elements", 2);
-        assert.strictEqual(third.name, 2);
+    var third = path.get("elements", 2);
+    assert.strictEqual(third.name, 2);
 
-        assert.strictEqual(path.get("elements", "length").value, 3);
+    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(), 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(), 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);
-    });
+    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();
-        });
+  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]
-        });
+  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]);
+    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 + 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(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);
-    });
+    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);
-        });
+  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]
-        );
+  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", 3), fooPath);
+    assert.strictEqual(fooPath.value.value, "foo");
 
-        assert.strictEqual(path.get("expressions", 4), truePath);
-        assert.strictEqual(truePath.value.value, true);
-    });
+    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);
-        });
+  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]
-        );
+  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", 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", 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);
+    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]
-        );
-    });
+    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);
-        });
+  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));
-        }
+  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 });
+    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);
-            });
+      assert.throws(function() {
+        types.astNodesAreEquivalent.assert(ast1, ast2);
+      });
 
-            var problemPath = [];
-            types.astNodesAreEquivalent(parse(src1), parse(src2), problemPath);
-            assert.notStrictEqual(problemPath.length, 0);
+      var problemPath = [];
+      types.astNodesAreEquivalent(parse(src1), parse(src2), problemPath);
+      assert.notStrictEqual(problemPath.length, 0);
 
-            var a = ast1;
-            var b = ast2;
+      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];
-            });
+      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);
-        }
+      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"));
-    });
+    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;
+  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);
+    n.Literal.assert(regExp);
+    isRegExp.assert(regExp.value);
 
-        var regex = types.getFieldValue(regExp, "regex");
+    var regex = types.getFieldValue(regExp, "regex");
 
-        regex.flags = regex.flags.split("").sort().join("");
+    regex.flags = regex.flags.split("").sort().join("");
 
-        assert.deepEqual(regex, {
-            pattern: "x*",
-            flags: "gim"
-        });
-
-        types.Type.fromObject({
-            pattern: isString,
-            flags: isString
-        }).assert(regex);
+    assert.deepEqual(regex, {
+      pattern: "x*",
+      flags: "gim"
     });
 
-    it("should typecheck with explicit .regex field", function() {
-        var stringLiteral = b.literal("asdf");
-        assert.strictEqual(stringLiteral.regex, null);
-        n.Literal.assert(stringLiteral, true);
+    types.Type.fromObject({
+      pattern: isString,
+      flags: isString
+    }).assert(regex);
+  });
 
-        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);
+  it("should typecheck with explicit .regex field", function() {
+    var stringLiteral = b.literal("asdf");
+    assert.strictEqual(stringLiteral.regex, null);
+    n.Literal.assert(stringLiteral, true);
 
-        regExpLiteral.regex.pattern = 1234;
-        assert.strictEqual(n.Literal.check(regExpLiteral, true), false);
-    });
+    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);
+    }
 
-describe("MemberExpression", function() {
-    it("should set computed flag to false by default", function(){
-        var memberExpression = b.memberExpression(
-            b.identifier('foo'),
-            b.identifier('bar')
-        )
+    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);
+      }
+    }
 
-        assert.strictEqual(memberExpression.computed, false)
-    });
+    function checkExp(exp) {
+      BigIntLiteral.assert(exp, true);
 
-    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(
+        exp.extra.rawValue,
+        exp.value
+      );
 
-        assert.strictEqual(memberExpression.computed, false)
-    });
+      assert.strictEqual(
+        exp.extra.raw,
+        exp.value + "n"
+      );
 
-    it("should set computed flag to true if property is a literal", function(){
-        var memberExpression = b.memberExpression(
-            b.identifier('foo'),
-            b.literal('bar')
-        )
+      delete exp.extra;
 
-        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'))
-        )
+      BigIntLiteral.assert(exp, true);
 
-        assert.strictEqual(memberExpression.computed, true)
-    });
+      var extra = types.getFieldValue(exp, "extra");
 
-    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(
+        extra.rawValue,
+        exp.value
+      );
 
-        assert.strictEqual(memberExpression.computed, true)
-    });
+      assert.strictEqual(
+        extra.raw,
+        exp.value + "n"
+      );
+    }
 
-    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
-        )
+    check("0n");
+    check("12345n");
+    check("0b101011101n");
+    check("0xFFF123n");
+    check("0xfff123n");
+    check("728374682736419273912879879610912837401293846n");
+    check("0xc00cda0a30d6312b54c55789befdea84f5949d92n");
+    check("0o16432n");
+  });
+});
 
-        assert.strictEqual(memberExpression.computed, true);
-    });
+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);
+  });
 });

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