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