[Pkg-javascript-commits] [node-ast-types] 01/03: Imported Upstream version 0.9.0
Julien Puydt
julien.puydt at laposte.net
Wed Aug 17 05:42:13 UTC 2016
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 fee62b53cb1f83aaae74d4ff2aa5f01d094e2e13
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Wed Aug 17 07:30:59 2016 +0200
Imported Upstream version 0.9.0
---
.travis.yml | 1 +
def/babel.js | 212 ++++----
def/core.js | 730 ++++++++++++++--------------
def/e4x.js | 170 +++----
def/es6.js | 426 ++++++++--------
def/es7.js | 54 ++-
def/esprima.js | 110 ++---
def/flow.js | 541 +++++++++++----------
def/jsx.js | 159 +++---
def/mozilla.js | 86 ++--
fork.js | 46 ++
lib/equiv.js | 272 +++++------
lib/node-path.js | 782 ++++++++++++++---------------
lib/path-visitor.js | 683 +++++++++++++-------------
lib/path.js | 577 +++++++++++-----------
lib/scope.js | 560 ++++++++++-----------
lib/shared.js | 79 +--
lib/types.js | 1349 ++++++++++++++++++++++++++-------------------------
main.js | 48 +-
package.json | 4 +-
test/run.js | 12 +-
21 files changed, 3505 insertions(+), 3396 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 6875ba4..4bce056 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
language: node_js
node_js:
+ - "6.0"
- "5.0"
- "4.0"
- "iojs"
diff --git a/def/babel.js b/def/babel.js
index 608ffbc..3d9352b 100644
--- a/def/babel.js
+++ b/def/babel.js
@@ -1,105 +1,107 @@
-require("./es7");
-
-var types = require("../lib/types");
-var defaults = require("../lib/shared").defaults;
-var def = types.Type.def;
-var or = types.Type.or;
-
-def("Noop")
- .bases("Node")
- .build();
-
-def("DoExpression")
- .bases("Expression")
- .build("body")
- .field("body", [def("Statement")]);
-
-def("Super")
- .bases("Expression")
- .build();
-
-def("BindExpression")
- .bases("Expression")
- .build("object", "callee")
- .field("object", or(def("Expression"), null))
- .field("callee", def("Expression"));
-
-def("Decorator")
- .bases("Node")
- .build("expression")
- .field("expression", def("Expression"));
-
-def("Property")
- .field("decorators",
- or([def("Decorator")], null),
- defaults["null"]);
-
-def("MethodDefinition")
- .field("decorators",
- or([def("Decorator")], null),
- defaults["null"]);
-
-def("MetaProperty")
- .bases("Expression")
- .build("meta", "property")
- .field("meta", def("Identifier"))
- .field("property", def("Identifier"));
-
-def("ParenthesizedExpression")
- .bases("Expression")
- .build("expression")
- .field("expression", def("Expression"));
-
-def("ImportSpecifier")
- .bases("ModuleSpecifier")
- .build("imported", "local")
- .field("imported", def("Identifier"));
-
-def("ImportDefaultSpecifier")
- .bases("ModuleSpecifier")
- .build("local");
-
-def("ImportNamespaceSpecifier")
- .bases("ModuleSpecifier")
- .build("local");
-
-def("ExportDefaultDeclaration")
- .bases("Declaration")
- .build("declaration")
- .field("declaration", or(def("Declaration"), def("Expression")));
-
-def("ExportNamedDeclaration")
- .bases("Declaration")
- .build("declaration", "specifiers", "source")
- .field("declaration", or(def("Declaration"), null))
- .field("specifiers", [def("ExportSpecifier")], defaults.emptyArray)
- .field("source", or(def("Literal"), null), defaults["null"]);
-
-def("ExportSpecifier")
- .bases("ModuleSpecifier")
- .build("local", "exported")
- .field("exported", def("Identifier"));
-
-def("ExportNamespaceSpecifier")
- .bases("Specifier")
- .build("exported")
- .field("exported", def("Identifier"));
-
-def("ExportDefaultSpecifier")
- .bases("Specifier")
- .build("exported")
- .field("exported", def("Identifier"));
-
-def("ExportAllDeclaration")
- .bases("Declaration")
- .build("exported", "source")
- .field("exported", or(def("Identifier"), null))
- .field("source", def("Literal"));
-
-def("CommentBlock")
- .bases("Comment")
- .build("value", /*optional:*/ "leading", "trailing");
-
-def("CommentLine")
- .bases("Comment")
- .build("value", /*optional:*/ "leading", "trailing");
+module.exports = function (fork) {
+ fork.use(require("./es7"));
+
+ var types = fork.use(require("../lib/types"));
+ var defaults = fork.use(require("../lib/shared")).defaults;
+ var def = types.Type.def;
+ var or = types.Type.or;
+
+ def("Noop")
+ .bases("Node")
+ .build();
+
+ def("DoExpression")
+ .bases("Expression")
+ .build("body")
+ .field("body", [def("Statement")]);
+
+ def("Super")
+ .bases("Expression")
+ .build();
+
+ def("BindExpression")
+ .bases("Expression")
+ .build("object", "callee")
+ .field("object", or(def("Expression"), null))
+ .field("callee", def("Expression"));
+
+ def("Decorator")
+ .bases("Node")
+ .build("expression")
+ .field("expression", def("Expression"));
+
+ def("Property")
+ .field("decorators",
+ or([def("Decorator")], null),
+ defaults["null"]);
+
+ def("MethodDefinition")
+ .field("decorators",
+ or([def("Decorator")], null),
+ defaults["null"]);
+
+ def("MetaProperty")
+ .bases("Expression")
+ .build("meta", "property")
+ .field("meta", def("Identifier"))
+ .field("property", def("Identifier"));
+
+ def("ParenthesizedExpression")
+ .bases("Expression")
+ .build("expression")
+ .field("expression", def("Expression"));
+
+ def("ImportSpecifier")
+ .bases("ModuleSpecifier")
+ .build("imported", "local")
+ .field("imported", def("Identifier"));
+
+ def("ImportDefaultSpecifier")
+ .bases("ModuleSpecifier")
+ .build("local");
+
+ def("ImportNamespaceSpecifier")
+ .bases("ModuleSpecifier")
+ .build("local");
+
+ def("ExportDefaultDeclaration")
+ .bases("Declaration")
+ .build("declaration")
+ .field("declaration", or(def("Declaration"), def("Expression")));
+
+ def("ExportNamedDeclaration")
+ .bases("Declaration")
+ .build("declaration", "specifiers", "source")
+ .field("declaration", or(def("Declaration"), null))
+ .field("specifiers", [def("ExportSpecifier")], defaults.emptyArray)
+ .field("source", or(def("Literal"), null), defaults["null"]);
+
+ def("ExportSpecifier")
+ .bases("ModuleSpecifier")
+ .build("local", "exported")
+ .field("exported", def("Identifier"));
+
+ def("ExportNamespaceSpecifier")
+ .bases("Specifier")
+ .build("exported")
+ .field("exported", def("Identifier"));
+
+ def("ExportDefaultSpecifier")
+ .bases("Specifier")
+ .build("exported")
+ .field("exported", def("Identifier"));
+
+ def("ExportAllDeclaration")
+ .bases("Declaration")
+ .build("exported", "source")
+ .field("exported", or(def("Identifier"), null))
+ .field("source", def("Literal"));
+
+ def("CommentBlock")
+ .bases("Comment")
+ .build("value", /*optional:*/ "leading", "trailing");
+
+ def("CommentLine")
+ .bases("Comment")
+ .build("value", /*optional:*/ "leading", "trailing");
+};
\ No newline at end of file
diff --git a/def/core.js b/def/core.js
index 2942c4b..800b317 100644
--- a/def/core.js
+++ b/def/core.js
@@ -1,367 +1,369 @@
-var types = require("../lib/types");
-var Type = types.Type;
-var def = Type.def;
-var or = Type.or;
-var shared = require("../lib/shared");
-var defaults = shared.defaults;
-var geq = shared.geq;
-
-// Abstract supertype of all syntactic entities that are allowed to have a
-// .loc field.
-def("Printable")
- .field("loc", or(
- def("SourceLocation"),
- null
- ), defaults["null"], true);
-
-def("Node")
- .bases("Printable")
- .field("type", String)
- .field("comments", or(
- [def("Comment")],
- null
- ), defaults["null"], true);
-
-def("SourceLocation")
- .build("start", "end", "source")
- .field("start", def("Position"))
- .field("end", def("Position"))
- .field("source", or(String, null), defaults["null"]);
-
-def("Position")
- .build("line", "column")
- .field("line", geq(1))
- .field("column", geq(0));
-
-def("File")
- .bases("Node")
- .build("program")
- .field("program", def("Program"));
-
-def("Program")
- .bases("Node")
- .build("body")
- .field("body", [def("Statement")]);
-
-def("Function")
- .bases("Node")
- .field("id", or(def("Identifier"), null), defaults["null"])
- .field("params", [def("Pattern")])
- .field("body", def("BlockStatement"));
-
-def("Statement").bases("Node");
+module.exports = function (fork) {
+ var types = fork.use(require("../lib/types"));
+ var Type = types.Type;
+ var def = Type.def;
+ var or = Type.or;
+ var shared = fork.use(require("../lib/shared"));
+ var defaults = shared.defaults;
+ var geq = shared.geq;
+
+ // Abstract supertype of all syntactic entities that are allowed to have a
+ // .loc field.
+ def("Printable")
+ .field("loc", or(
+ def("SourceLocation"),
+ null
+ ), defaults["null"], true);
+
+ def("Node")
+ .bases("Printable")
+ .field("type", String)
+ .field("comments", or(
+ [def("Comment")],
+ null
+ ), defaults["null"], true);
+
+ def("SourceLocation")
+ .build("start", "end", "source")
+ .field("start", def("Position"))
+ .field("end", def("Position"))
+ .field("source", or(String, null), defaults["null"]);
+
+ def("Position")
+ .build("line", "column")
+ .field("line", geq(1))
+ .field("column", geq(0));
+
+ def("File")
+ .bases("Node")
+ .build("program")
+ .field("program", def("Program"));
+
+ def("Program")
+ .bases("Node")
+ .build("body")
+ .field("body", [def("Statement")]);
+
+ def("Function")
+ .bases("Node")
+ .field("id", or(def("Identifier"), null), defaults["null"])
+ .field("params", [def("Pattern")])
+ .field("body", def("BlockStatement"));
+
+ def("Statement").bases("Node");
// The empty .build() here means that an EmptyStatement can be constructed
// (i.e. it's not abstract) but that it needs no arguments.
-def("EmptyStatement").bases("Statement").build();
-
-def("BlockStatement")
- .bases("Statement")
- .build("body")
- .field("body", [def("Statement")]);
-
-// TODO Figure out how to silently coerce Expressions to
-// ExpressionStatements where a Statement was expected.
-def("ExpressionStatement")
- .bases("Statement")
- .build("expression")
- .field("expression", def("Expression"));
-
-def("IfStatement")
- .bases("Statement")
- .build("test", "consequent", "alternate")
- .field("test", def("Expression"))
- .field("consequent", def("Statement"))
- .field("alternate", or(def("Statement"), null), defaults["null"]);
-
-def("LabeledStatement")
- .bases("Statement")
- .build("label", "body")
- .field("label", def("Identifier"))
- .field("body", def("Statement"));
-
-def("BreakStatement")
- .bases("Statement")
- .build("label")
- .field("label", or(def("Identifier"), null), defaults["null"]);
-
-def("ContinueStatement")
- .bases("Statement")
- .build("label")
- .field("label", or(def("Identifier"), null), defaults["null"]);
-
-def("WithStatement")
- .bases("Statement")
- .build("object", "body")
- .field("object", def("Expression"))
- .field("body", def("Statement"));
-
-def("SwitchStatement")
- .bases("Statement")
- .build("discriminant", "cases", "lexical")
- .field("discriminant", def("Expression"))
- .field("cases", [def("SwitchCase")])
- .field("lexical", Boolean, defaults["false"]);
-
-def("ReturnStatement")
- .bases("Statement")
- .build("argument")
- .field("argument", or(def("Expression"), null));
-
-def("ThrowStatement")
- .bases("Statement")
- .build("argument")
- .field("argument", def("Expression"));
-
-def("TryStatement")
- .bases("Statement")
- .build("block", "handler", "finalizer")
- .field("block", def("BlockStatement"))
- .field("handler", or(def("CatchClause"), null), function() {
- return this.handlers && this.handlers[0] || null;
- })
- .field("handlers", [def("CatchClause")], function() {
- return this.handler ? [this.handler] : [];
- }, true) // Indicates this field is hidden from eachField iteration.
- .field("guardedHandlers", [def("CatchClause")], defaults.emptyArray)
- .field("finalizer", or(def("BlockStatement"), null), defaults["null"]);
-
-def("CatchClause")
- .bases("Node")
- .build("param", "guard", "body")
- .field("param", def("Pattern"))
- .field("guard", or(def("Expression"), null), defaults["null"])
- .field("body", def("BlockStatement"));
-
-def("WhileStatement")
- .bases("Statement")
- .build("test", "body")
- .field("test", def("Expression"))
- .field("body", def("Statement"));
-
-def("DoWhileStatement")
- .bases("Statement")
- .build("body", "test")
- .field("body", def("Statement"))
- .field("test", def("Expression"));
-
-def("ForStatement")
- .bases("Statement")
- .build("init", "test", "update", "body")
- .field("init", or(
- def("VariableDeclaration"),
- def("Expression"),
- null))
- .field("test", or(def("Expression"), null))
- .field("update", or(def("Expression"), null))
- .field("body", def("Statement"));
-
-def("ForInStatement")
- .bases("Statement")
- .build("left", "right", "body")
- .field("left", or(
- def("VariableDeclaration"),
- def("Expression")))
- .field("right", def("Expression"))
- .field("body", def("Statement"));
-
-def("DebuggerStatement").bases("Statement").build();
-
-def("Declaration").bases("Statement");
-
-def("FunctionDeclaration")
- .bases("Function", "Declaration")
- .build("id", "params", "body")
- .field("id", def("Identifier"));
-
-def("FunctionExpression")
- .bases("Function", "Expression")
- .build("id", "params", "body");
-
-def("VariableDeclaration")
- .bases("Declaration")
- .build("kind", "declarations")
- .field("kind", or("var", "let", "const"))
- .field("declarations", [def("VariableDeclarator")]);
-
-def("VariableDeclarator")
- .bases("Node")
- .build("id", "init")
- .field("id", def("Pattern"))
- .field("init", or(def("Expression"), null));
-
-// TODO Are all Expressions really Patterns?
-def("Expression").bases("Node", "Pattern");
-
-def("ThisExpression").bases("Expression").build();
-
-def("ArrayExpression")
- .bases("Expression")
- .build("elements")
- .field("elements", [or(def("Expression"), null)]);
-
-def("ObjectExpression")
- .bases("Expression")
- .build("properties")
- .field("properties", [def("Property")]);
-
-// TODO Not in the Mozilla Parser API, but used by Esprima.
-def("Property")
- .bases("Node") // Want to be able to visit Property Nodes.
- .build("kind", "key", "value")
- .field("kind", or("init", "get", "set"))
- .field("key", or(def("Literal"), def("Identifier")))
- .field("value", def("Expression"));
-
-def("SequenceExpression")
- .bases("Expression")
- .build("expressions")
- .field("expressions", [def("Expression")]);
-
-var UnaryOperator = or(
- "-", "+", "!", "~",
- "typeof", "void", "delete");
-
-def("UnaryExpression")
- .bases("Expression")
- .build("operator", "argument", "prefix")
- .field("operator", UnaryOperator)
- .field("argument", def("Expression"))
- // Esprima doesn't bother with this field, presumably because it's
- // always true for unary operators.
- .field("prefix", Boolean, defaults["true"]);
-
-var BinaryOperator = or(
- "==", "!=", "===", "!==",
- "<", "<=", ">", ">=",
- "<<", ">>", ">>>",
- "+", "-", "*", "/", "%",
- "&", // TODO Missing from the Parser API.
- "|", "^", "in",
- "instanceof", "..");
-
-def("BinaryExpression")
- .bases("Expression")
- .build("operator", "left", "right")
- .field("operator", BinaryOperator)
- .field("left", def("Expression"))
- .field("right", def("Expression"));
-
-var AssignmentOperator = or(
- "=", "+=", "-=", "*=", "/=", "%=",
- "<<=", ">>=", ">>>=",
- "|=", "^=", "&=");
-
-def("AssignmentExpression")
- .bases("Expression")
- .build("operator", "left", "right")
- .field("operator", AssignmentOperator)
- .field("left", def("Pattern"))
- .field("right", def("Expression"));
-
-var UpdateOperator = or("++", "--");
-
-def("UpdateExpression")
- .bases("Expression")
- .build("operator", "argument", "prefix")
- .field("operator", UpdateOperator)
- .field("argument", def("Expression"))
- .field("prefix", Boolean);
-
-var LogicalOperator = or("||", "&&");
-
-def("LogicalExpression")
- .bases("Expression")
- .build("operator", "left", "right")
- .field("operator", LogicalOperator)
- .field("left", def("Expression"))
- .field("right", def("Expression"));
-
-def("ConditionalExpression")
- .bases("Expression")
- .build("test", "consequent", "alternate")
- .field("test", def("Expression"))
- .field("consequent", def("Expression"))
- .field("alternate", def("Expression"));
-
-def("NewExpression")
- .bases("Expression")
- .build("callee", "arguments")
- .field("callee", def("Expression"))
- // The Mozilla Parser API gives this type as [or(def("Expression"),
- // null)], but null values don't really make sense at the call site.
- // TODO Report this nonsense.
- .field("arguments", [def("Expression")]);
-
-def("CallExpression")
- .bases("Expression")
- .build("callee", "arguments")
- .field("callee", def("Expression"))
- // See comment for NewExpression above.
- .field("arguments", [def("Expression")]);
-
-def("MemberExpression")
- .bases("Expression")
- .build("object", "property", "computed")
- .field("object", def("Expression"))
- .field("property", or(def("Identifier"), def("Expression")))
- .field("computed", Boolean, function(){
- var type = this.property.type;
- if (type === 'Literal' ||
- type === 'MemberExpression' ||
- type === 'BinaryExpression') {
- return true;
- }
- return false;
- });
-
-def("Pattern").bases("Node");
-
-def("SwitchCase")
- .bases("Node")
- .build("test", "consequent")
- .field("test", or(def("Expression"), null))
- .field("consequent", [def("Statement")]);
-
-def("Identifier")
- // But aren't Expressions and Patterns already Nodes? TODO Report this.
- .bases("Node", "Expression", "Pattern")
- .build("name")
- .field("name", String);
-
-def("Literal")
- // But aren't Expressions already Nodes? TODO Report this.
- .bases("Node", "Expression")
- .build("value")
- .field("value", or(String, Boolean, null, Number, RegExp))
- .field("regex", or({
- pattern: String,
- flags: String
- }, null), function() {
- if (this.value instanceof RegExp) {
- var flags = "";
-
- if (this.value.ignoreCase) flags += "i";
- if (this.value.multiline) flags += "m";
- if (this.value.global) flags += "g";
-
- return {
- pattern: this.value.source,
- flags: flags
- };
- }
-
- return null;
- });
-
-// Abstract (non-buildable) comment supertype. Not a Node.
-def("Comment")
- .bases("Printable")
- .field("value", String)
- // A .leading comment comes before the node, whereas a .trailing
- // comment comes after it. These two fields should not both be true,
- // but they might both be false when the comment falls inside a node
- // and the node has no children for the comment to lead or trail,
- // e.g. { /*dangling*/ }.
- .field("leading", Boolean, defaults["true"])
- .field("trailing", Boolean, defaults["false"]);
+ def("EmptyStatement").bases("Statement").build();
+
+ def("BlockStatement")
+ .bases("Statement")
+ .build("body")
+ .field("body", [def("Statement")]);
+
+ // TODO Figure out how to silently coerce Expressions to
+ // ExpressionStatements where a Statement was expected.
+ def("ExpressionStatement")
+ .bases("Statement")
+ .build("expression")
+ .field("expression", def("Expression"));
+
+ def("IfStatement")
+ .bases("Statement")
+ .build("test", "consequent", "alternate")
+ .field("test", def("Expression"))
+ .field("consequent", def("Statement"))
+ .field("alternate", or(def("Statement"), null), defaults["null"]);
+
+ def("LabeledStatement")
+ .bases("Statement")
+ .build("label", "body")
+ .field("label", def("Identifier"))
+ .field("body", def("Statement"));
+
+ def("BreakStatement")
+ .bases("Statement")
+ .build("label")
+ .field("label", or(def("Identifier"), null), defaults["null"]);
+
+ def("ContinueStatement")
+ .bases("Statement")
+ .build("label")
+ .field("label", or(def("Identifier"), null), defaults["null"]);
+
+ def("WithStatement")
+ .bases("Statement")
+ .build("object", "body")
+ .field("object", def("Expression"))
+ .field("body", def("Statement"));
+
+ def("SwitchStatement")
+ .bases("Statement")
+ .build("discriminant", "cases", "lexical")
+ .field("discriminant", def("Expression"))
+ .field("cases", [def("SwitchCase")])
+ .field("lexical", Boolean, defaults["false"]);
+
+ def("ReturnStatement")
+ .bases("Statement")
+ .build("argument")
+ .field("argument", or(def("Expression"), null));
+
+ def("ThrowStatement")
+ .bases("Statement")
+ .build("argument")
+ .field("argument", def("Expression"));
+
+ def("TryStatement")
+ .bases("Statement")
+ .build("block", "handler", "finalizer")
+ .field("block", def("BlockStatement"))
+ .field("handler", or(def("CatchClause"), null), function () {
+ return this.handlers && this.handlers[0] || null;
+ })
+ .field("handlers", [def("CatchClause")], function () {
+ return this.handler ? [this.handler] : [];
+ }, true) // Indicates this field is hidden from eachField iteration.
+ .field("guardedHandlers", [def("CatchClause")], defaults.emptyArray)
+ .field("finalizer", or(def("BlockStatement"), null), defaults["null"]);
+
+ def("CatchClause")
+ .bases("Node")
+ .build("param", "guard", "body")
+ .field("param", def("Pattern"))
+ .field("guard", or(def("Expression"), null), defaults["null"])
+ .field("body", def("BlockStatement"));
+
+ def("WhileStatement")
+ .bases("Statement")
+ .build("test", "body")
+ .field("test", def("Expression"))
+ .field("body", def("Statement"));
+
+ def("DoWhileStatement")
+ .bases("Statement")
+ .build("body", "test")
+ .field("body", def("Statement"))
+ .field("test", def("Expression"));
+
+ def("ForStatement")
+ .bases("Statement")
+ .build("init", "test", "update", "body")
+ .field("init", or(
+ def("VariableDeclaration"),
+ def("Expression"),
+ null))
+ .field("test", or(def("Expression"), null))
+ .field("update", or(def("Expression"), null))
+ .field("body", def("Statement"));
+
+ def("ForInStatement")
+ .bases("Statement")
+ .build("left", "right", "body")
+ .field("left", or(
+ def("VariableDeclaration"),
+ def("Expression")))
+ .field("right", def("Expression"))
+ .field("body", def("Statement"));
+
+ def("DebuggerStatement").bases("Statement").build();
+
+ def("Declaration").bases("Statement");
+
+ def("FunctionDeclaration")
+ .bases("Function", "Declaration")
+ .build("id", "params", "body")
+ .field("id", def("Identifier"));
+
+ def("FunctionExpression")
+ .bases("Function", "Expression")
+ .build("id", "params", "body");
+
+ def("VariableDeclaration")
+ .bases("Declaration")
+ .build("kind", "declarations")
+ .field("kind", or("var", "let", "const"))
+ .field("declarations", [def("VariableDeclarator")]);
+
+ def("VariableDeclarator")
+ .bases("Node")
+ .build("id", "init")
+ .field("id", def("Pattern"))
+ .field("init", or(def("Expression"), null));
+
+ // TODO Are all Expressions really Patterns?
+ def("Expression").bases("Node", "Pattern");
+
+ def("ThisExpression").bases("Expression").build();
+
+ def("ArrayExpression")
+ .bases("Expression")
+ .build("elements")
+ .field("elements", [or(def("Expression"), null)]);
+
+ def("ObjectExpression")
+ .bases("Expression")
+ .build("properties")
+ .field("properties", [def("Property")]);
+
+ // TODO Not in the Mozilla Parser API, but used by Esprima.
+ def("Property")
+ .bases("Node") // Want to be able to visit Property Nodes.
+ .build("kind", "key", "value")
+ .field("kind", or("init", "get", "set"))
+ .field("key", or(def("Literal"), def("Identifier")))
+ .field("value", def("Expression"));
+
+ def("SequenceExpression")
+ .bases("Expression")
+ .build("expressions")
+ .field("expressions", [def("Expression")]);
+
+ var UnaryOperator = or(
+ "-", "+", "!", "~",
+ "typeof", "void", "delete");
+
+ def("UnaryExpression")
+ .bases("Expression")
+ .build("operator", "argument", "prefix")
+ .field("operator", UnaryOperator)
+ .field("argument", def("Expression"))
+ // Esprima doesn't bother with this field, presumably because it's
+ // always true for unary operators.
+ .field("prefix", Boolean, defaults["true"]);
+
+ var BinaryOperator = or(
+ "==", "!=", "===", "!==",
+ "<", "<=", ">", ">=",
+ "<<", ">>", ">>>",
+ "+", "-", "*", "/", "%",
+ "&", // TODO Missing from the Parser API.
+ "|", "^", "in",
+ "instanceof", "..");
+
+ def("BinaryExpression")
+ .bases("Expression")
+ .build("operator", "left", "right")
+ .field("operator", BinaryOperator)
+ .field("left", def("Expression"))
+ .field("right", def("Expression"));
+
+ var AssignmentOperator = or(
+ "=", "+=", "-=", "*=", "/=", "%=",
+ "<<=", ">>=", ">>>=",
+ "|=", "^=", "&=");
+
+ def("AssignmentExpression")
+ .bases("Expression")
+ .build("operator", "left", "right")
+ .field("operator", AssignmentOperator)
+ .field("left", def("Pattern"))
+ .field("right", def("Expression"));
+
+ var UpdateOperator = or("++", "--");
+
+ def("UpdateExpression")
+ .bases("Expression")
+ .build("operator", "argument", "prefix")
+ .field("operator", UpdateOperator)
+ .field("argument", def("Expression"))
+ .field("prefix", Boolean);
+
+ var LogicalOperator = or("||", "&&");
+
+ def("LogicalExpression")
+ .bases("Expression")
+ .build("operator", "left", "right")
+ .field("operator", LogicalOperator)
+ .field("left", def("Expression"))
+ .field("right", def("Expression"));
+
+ def("ConditionalExpression")
+ .bases("Expression")
+ .build("test", "consequent", "alternate")
+ .field("test", def("Expression"))
+ .field("consequent", def("Expression"))
+ .field("alternate", def("Expression"));
+
+ def("NewExpression")
+ .bases("Expression")
+ .build("callee", "arguments")
+ .field("callee", def("Expression"))
+ // The Mozilla Parser API gives this type as [or(def("Expression"),
+ // null)], but null values don't really make sense at the call site.
+ // TODO Report this nonsense.
+ .field("arguments", [def("Expression")]);
+
+ def("CallExpression")
+ .bases("Expression")
+ .build("callee", "arguments")
+ .field("callee", def("Expression"))
+ // See comment for NewExpression above.
+ .field("arguments", [def("Expression")]);
+
+ def("MemberExpression")
+ .bases("Expression")
+ .build("object", "property", "computed")
+ .field("object", def("Expression"))
+ .field("property", or(def("Identifier"), def("Expression")))
+ .field("computed", Boolean, function () {
+ var type = this.property.type;
+ if (type === 'Literal' ||
+ type === 'MemberExpression' ||
+ type === 'BinaryExpression') {
+ return true;
+ }
+ return false;
+ });
+
+ def("Pattern").bases("Node");
+
+ def("SwitchCase")
+ .bases("Node")
+ .build("test", "consequent")
+ .field("test", or(def("Expression"), null))
+ .field("consequent", [def("Statement")]);
+
+ def("Identifier")
+ // But aren't Expressions and Patterns already Nodes? TODO Report this.
+ .bases("Node", "Expression", "Pattern")
+ .build("name")
+ .field("name", String);
+
+ def("Literal")
+ // But aren't Expressions already Nodes? TODO Report this.
+ .bases("Node", "Expression")
+ .build("value")
+ .field("value", or(String, Boolean, null, Number, RegExp))
+ .field("regex", or({
+ pattern: String,
+ flags: String
+ }, null), function () {
+ if (this.value instanceof RegExp) {
+ var flags = "";
+
+ if (this.value.ignoreCase) flags += "i";
+ if (this.value.multiline) flags += "m";
+ if (this.value.global) flags += "g";
+
+ return {
+ pattern: this.value.source,
+ flags: flags
+ };
+ }
+
+ return null;
+ });
+
+ // Abstract (non-buildable) comment supertype. Not a Node.
+ def("Comment")
+ .bases("Printable")
+ .field("value", String)
+ // A .leading comment comes before the node, whereas a .trailing
+ // comment comes after it. These two fields should not both be true,
+ // but they might both be false when the comment falls inside a node
+ // and the node has no children for the comment to lead or trail,
+ // e.g. { /*dangling*/ }.
+ .field("leading", Boolean, defaults["true"])
+ .field("trailing", Boolean, defaults["false"]);
+};
\ No newline at end of file
diff --git a/def/e4x.js b/def/e4x.js
index 22ac0ff..59403eb 100644
--- a/def/e4x.js
+++ b/def/e4x.js
@@ -1,84 +1,86 @@
-require("./core");
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-
-// Note that none of these types are buildable because the Mozilla Parser
-// API doesn't specify any builder functions, and nobody uses E4X anymore.
-
-def("XMLDefaultDeclaration")
- .bases("Declaration")
- .field("namespace", def("Expression"));
-
-def("XMLAnyName").bases("Expression");
-
-def("XMLQualifiedIdentifier")
- .bases("Expression")
- .field("left", or(def("Identifier"), def("XMLAnyName")))
- .field("right", or(def("Identifier"), def("Expression")))
- .field("computed", Boolean);
-
-def("XMLFunctionQualifiedIdentifier")
- .bases("Expression")
- .field("right", or(def("Identifier"), def("Expression")))
- .field("computed", Boolean);
-
-def("XMLAttributeSelector")
- .bases("Expression")
- .field("attribute", def("Expression"));
-
-def("XMLFilterExpression")
- .bases("Expression")
- .field("left", def("Expression"))
- .field("right", def("Expression"));
-
-def("XMLElement")
- .bases("XML", "Expression")
- .field("contents", [def("XML")]);
-
-def("XMLList")
- .bases("XML", "Expression")
- .field("contents", [def("XML")]);
-
-def("XML").bases("Node");
-
-def("XMLEscape")
- .bases("XML")
- .field("expression", def("Expression"));
-
-def("XMLText")
- .bases("XML")
- .field("text", String);
-
-def("XMLStartTag")
- .bases("XML")
- .field("contents", [def("XML")]);
-
-def("XMLEndTag")
- .bases("XML")
- .field("contents", [def("XML")]);
-
-def("XMLPointTag")
- .bases("XML")
- .field("contents", [def("XML")]);
-
-def("XMLName")
- .bases("XML")
- .field("contents", or(String, [def("XML")]));
-
-def("XMLAttribute")
- .bases("XML")
- .field("value", String);
-
-def("XMLCdata")
- .bases("XML")
- .field("contents", String);
-
-def("XMLComment")
- .bases("XML")
- .field("contents", String);
-
-def("XMLProcessingInstruction")
- .bases("XML")
- .field("target", String)
- .field("contents", or(String, null));
+module.exports = function (fork) {
+ fork.use(require("./core"));
+ var types = fork.use(require("../lib/types"));
+ var def = types.Type.def;
+ var or = types.Type.or;
+
+ // Note that none of these types are buildable because the Mozilla Parser
+ // API doesn't specify any builder functions, and nobody uses E4X anymore.
+
+ def("XMLDefaultDeclaration")
+ .bases("Declaration")
+ .field("namespace", def("Expression"));
+
+ def("XMLAnyName").bases("Expression");
+
+ def("XMLQualifiedIdentifier")
+ .bases("Expression")
+ .field("left", or(def("Identifier"), def("XMLAnyName")))
+ .field("right", or(def("Identifier"), def("Expression")))
+ .field("computed", Boolean);
+
+ def("XMLFunctionQualifiedIdentifier")
+ .bases("Expression")
+ .field("right", or(def("Identifier"), def("Expression")))
+ .field("computed", Boolean);
+
+ def("XMLAttributeSelector")
+ .bases("Expression")
+ .field("attribute", def("Expression"));
+
+ def("XMLFilterExpression")
+ .bases("Expression")
+ .field("left", def("Expression"))
+ .field("right", def("Expression"));
+
+ def("XMLElement")
+ .bases("XML", "Expression")
+ .field("contents", [def("XML")]);
+
+ def("XMLList")
+ .bases("XML", "Expression")
+ .field("contents", [def("XML")]);
+
+ def("XML").bases("Node");
+
+ def("XMLEscape")
+ .bases("XML")
+ .field("expression", def("Expression"));
+
+ def("XMLText")
+ .bases("XML")
+ .field("text", String);
+
+ def("XMLStartTag")
+ .bases("XML")
+ .field("contents", [def("XML")]);
+
+ def("XMLEndTag")
+ .bases("XML")
+ .field("contents", [def("XML")]);
+
+ def("XMLPointTag")
+ .bases("XML")
+ .field("contents", [def("XML")]);
+
+ def("XMLName")
+ .bases("XML")
+ .field("contents", or(String, [def("XML")]));
+
+ def("XMLAttribute")
+ .bases("XML")
+ .field("value", String);
+
+ def("XMLCdata")
+ .bases("XML")
+ .field("contents", String);
+
+ def("XMLComment")
+ .bases("XML")
+ .field("contents", String);
+
+ def("XMLProcessingInstruction")
+ .bases("XML")
+ .field("target", String)
+ .field("contents", or(String, null));
+};
\ No newline at end of file
diff --git a/def/es6.js b/def/es6.js
index b73bc07..284fa54 100644
--- a/def/es6.js
+++ b/def/es6.js
@@ -1,217 +1,219 @@
-require("./core");
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-var defaults = require("../lib/shared").defaults;
-
-def("Function")
- .field("generator", Boolean, defaults["false"])
- .field("expression", Boolean, defaults["false"])
- .field("defaults", [or(def("Expression"), null)], defaults.emptyArray)
- // TODO This could be represented as a RestElement in .params.
- .field("rest", or(def("Identifier"), null), defaults["null"]);
-
-// The ESTree way of representing a ...rest parameter.
-def("RestElement")
- .bases("Pattern")
- .build("argument")
- .field("argument", def("Pattern"));
-
-def("SpreadElementPattern")
- .bases("Pattern")
- .build("argument")
- .field("argument", def("Pattern"));
-
-def("FunctionDeclaration")
- .build("id", "params", "body", "generator", "expression");
-
-def("FunctionExpression")
- .build("id", "params", "body", "generator", "expression");
-
-// The Parser API calls this ArrowExpression, but Esprima and all other
-// actual parsers use ArrowFunctionExpression.
-def("ArrowFunctionExpression")
- .bases("Function", "Expression")
- .build("params", "body", "expression")
- // The forced null value here is compatible with the overridden
- // definition of the "id" field in the Function interface.
- .field("id", null, defaults["null"])
- // Arrow function bodies are allowed to be expressions.
- .field("body", or(def("BlockStatement"), def("Expression")))
- // The current spec forbids arrow generators, so I have taken the
- // liberty of enforcing that. TODO Report this.
- .field("generator", false, defaults["false"]);
-
-def("YieldExpression")
- .bases("Expression")
- .build("argument", "delegate")
- .field("argument", or(def("Expression"), null))
- .field("delegate", Boolean, defaults["false"]);
-
-def("GeneratorExpression")
- .bases("Expression")
- .build("body", "blocks", "filter")
- .field("body", def("Expression"))
- .field("blocks", [def("ComprehensionBlock")])
- .field("filter", or(def("Expression"), null));
-
-def("ComprehensionExpression")
- .bases("Expression")
- .build("body", "blocks", "filter")
- .field("body", def("Expression"))
- .field("blocks", [def("ComprehensionBlock")])
- .field("filter", or(def("Expression"), null));
-
-def("ComprehensionBlock")
- .bases("Node")
- .build("left", "right", "each")
- .field("left", def("Pattern"))
- .field("right", def("Expression"))
- .field("each", Boolean);
-
-def("Property")
- .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
- .field("value", or(def("Expression"), def("Pattern")))
- .field("method", Boolean, defaults["false"])
- .field("shorthand", Boolean, defaults["false"])
- .field("computed", Boolean, defaults["false"]);
-
-def("PropertyPattern")
- .bases("Pattern")
- .build("key", "pattern")
- .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
- .field("pattern", def("Pattern"))
- .field("computed", Boolean, defaults["false"]);
-
-def("ObjectPattern")
- .bases("Pattern")
- .build("properties")
- .field("properties", [or(def("PropertyPattern"), def("Property"))]);
-
-def("ArrayPattern")
- .bases("Pattern")
- .build("elements")
- .field("elements", [or(def("Pattern"), null)]);
-
-def("MethodDefinition")
- .bases("Declaration")
- .build("kind", "key", "value", "static")
- .field("kind", or("constructor", "method", "get", "set"))
- .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
- .field("value", def("Function"))
- .field("computed", Boolean, defaults["false"])
- .field("static", Boolean, defaults["false"]);
-
-def("SpreadElement")
- .bases("Node")
- .build("argument")
- .field("argument", def("Expression"));
-
-def("ArrayExpression")
- .field("elements", [or(
+module.exports = function (fork) {
+ fork.use(require("./core"));
+ var types = fork.use(require("../lib/types"));
+ var def = types.Type.def;
+ var or = types.Type.or;
+ var defaults = fork.use(require("../lib/shared")).defaults;
+
+ def("Function")
+ .field("generator", Boolean, defaults["false"])
+ .field("expression", Boolean, defaults["false"])
+ .field("defaults", [or(def("Expression"), null)], defaults.emptyArray)
+ // TODO This could be represented as a RestElement in .params.
+ .field("rest", or(def("Identifier"), null), defaults["null"]);
+
+ // The ESTree way of representing a ...rest parameter.
+ def("RestElement")
+ .bases("Pattern")
+ .build("argument")
+ .field("argument", def("Pattern"));
+
+ def("SpreadElementPattern")
+ .bases("Pattern")
+ .build("argument")
+ .field("argument", def("Pattern"));
+
+ def("FunctionDeclaration")
+ .build("id", "params", "body", "generator", "expression");
+
+ def("FunctionExpression")
+ .build("id", "params", "body", "generator", "expression");
+
+ // The Parser API calls this ArrowExpression, but Esprima and all other
+ // actual parsers use ArrowFunctionExpression.
+ def("ArrowFunctionExpression")
+ .bases("Function", "Expression")
+ .build("params", "body", "expression")
+ // The forced null value here is compatible with the overridden
+ // definition of the "id" field in the Function interface.
+ .field("id", null, defaults["null"])
+ // Arrow function bodies are allowed to be expressions.
+ .field("body", or(def("BlockStatement"), def("Expression")))
+ // The current spec forbids arrow generators, so I have taken the
+ // liberty of enforcing that. TODO Report this.
+ .field("generator", false, defaults["false"]);
+
+ def("YieldExpression")
+ .bases("Expression")
+ .build("argument", "delegate")
+ .field("argument", or(def("Expression"), null))
+ .field("delegate", Boolean, defaults["false"]);
+
+ def("GeneratorExpression")
+ .bases("Expression")
+ .build("body", "blocks", "filter")
+ .field("body", def("Expression"))
+ .field("blocks", [def("ComprehensionBlock")])
+ .field("filter", or(def("Expression"), null));
+
+ def("ComprehensionExpression")
+ .bases("Expression")
+ .build("body", "blocks", "filter")
+ .field("body", def("Expression"))
+ .field("blocks", [def("ComprehensionBlock")])
+ .field("filter", or(def("Expression"), null));
+
+ def("ComprehensionBlock")
+ .bases("Node")
+ .build("left", "right", "each")
+ .field("left", def("Pattern"))
+ .field("right", def("Expression"))
+ .field("each", Boolean);
+
+ def("Property")
+ .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
+ .field("value", or(def("Expression"), def("Pattern")))
+ .field("method", Boolean, defaults["false"])
+ .field("shorthand", Boolean, defaults["false"])
+ .field("computed", Boolean, defaults["false"]);
+
+ def("PropertyPattern")
+ .bases("Pattern")
+ .build("key", "pattern")
+ .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
+ .field("pattern", def("Pattern"))
+ .field("computed", Boolean, defaults["false"]);
+
+ def("ObjectPattern")
+ .bases("Pattern")
+ .build("properties")
+ .field("properties", [or(def("PropertyPattern"), def("Property"))]);
+
+ def("ArrayPattern")
+ .bases("Pattern")
+ .build("elements")
+ .field("elements", [or(def("Pattern"), null)]);
+
+ def("MethodDefinition")
+ .bases("Declaration")
+ .build("kind", "key", "value", "static")
+ .field("kind", or("constructor", "method", "get", "set"))
+ .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
+ .field("value", def("Function"))
+ .field("computed", Boolean, defaults["false"])
+ .field("static", Boolean, defaults["false"]);
+
+ def("SpreadElement")
+ .bases("Node")
+ .build("argument")
+ .field("argument", def("Expression"));
+
+ def("ArrayExpression")
+ .field("elements", [or(
def("Expression"),
def("SpreadElement"),
def("RestElement"),
null
- )]);
-
-def("NewExpression")
- .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
-
-def("CallExpression")
- .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
-
-// Note: this node type is *not* an AssignmentExpression with a Pattern on
-// the left-hand side! The existing AssignmentExpression type already
-// supports destructuring assignments. AssignmentPattern nodes may appear
-// wherever a Pattern is allowed, and the right-hand side represents a
-// default value to be destructured against the left-hand side, if no
-// value is otherwise provided. For example: default parameter values.
-def("AssignmentPattern")
- .bases("Pattern")
- .build("left", "right")
- .field("left", def("Pattern"))
- .field("right", def("Expression"));
-
-var ClassBodyElement = or(
- def("MethodDefinition"),
- def("VariableDeclarator"),
- def("ClassPropertyDefinition"),
+ )]);
+
+ def("NewExpression")
+ .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
+
+ def("CallExpression")
+ .field("arguments", [or(def("Expression"), def("SpreadElement"))]);
+
+ // Note: this node type is *not* an AssignmentExpression with a Pattern on
+ // the left-hand side! The existing AssignmentExpression type already
+ // supports destructuring assignments. AssignmentPattern nodes may appear
+ // wherever a Pattern is allowed, and the right-hand side represents a
+ // default value to be destructured against the left-hand side, if no
+ // value is otherwise provided. For example: default parameter values.
+ def("AssignmentPattern")
+ .bases("Pattern")
+ .build("left", "right")
+ .field("left", def("Pattern"))
+ .field("right", def("Expression"));
+
+ var ClassBodyElement = or(
+ def("MethodDefinition"),
+ def("VariableDeclarator"),
+ def("ClassPropertyDefinition"),
+ def("ClassProperty")
+ );
+
def("ClassProperty")
-);
-
-def("ClassProperty")
- .bases("Declaration")
- .build("key")
- .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
- .field("computed", Boolean, defaults["false"]);
-
-def("ClassPropertyDefinition") // static property
- .bases("Declaration")
- .build("definition")
- // Yes, Virginia, circular definitions are permitted.
- .field("definition", ClassBodyElement);
-
-def("ClassBody")
- .bases("Declaration")
- .build("body")
- .field("body", [ClassBodyElement]);
-
-def("ClassDeclaration")
- .bases("Declaration")
- .build("id", "body", "superClass")
- .field("id", or(def("Identifier"), null))
- .field("body", def("ClassBody"))
- .field("superClass", or(def("Expression"), null), defaults["null"]);
-
-def("ClassExpression")
- .bases("Expression")
- .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
-// introduced for definitional convenience.
-def("Specifier").bases("Node");
-
-// This supertype is shared/abused by both def/babel.js and
-// def/esprima.js. In the future, it will be possible to load only one set
-// of definitions appropriate for a given parser, but until then we must
-// rely on default functions to reconcile the conflicting AST formats.
-def("ModuleSpecifier")
- .bases("Specifier")
- // This local field is used by Babel/Acorn. It should not technically
- // be optional in the Babel/Acorn AST format, but it must be optional
- // in the Esprima AST format.
- .field("local", or(def("Identifier"), null), defaults["null"])
- // The id and name fields are used by Esprima. The id field should not
- // technically be optional in the Esprima AST format, but it must be
- // optional in the Babel/Acorn AST format.
- .field("id", or(def("Identifier"), null), defaults["null"])
- .field("name", or(def("Identifier"), null), defaults["null"]);
-
-def("TaggedTemplateExpression")
- .bases("Expression")
- .build("tag", "quasi")
- .field("tag", def("Expression"))
- .field("quasi", def("TemplateLiteral"));
-
-def("TemplateLiteral")
- .bases("Expression")
- .build("quasis", "expressions")
- .field("quasis", [def("TemplateElement")])
- .field("expressions", [def("Expression")]);
-
-def("TemplateElement")
- .bases("Node")
- .build("value", "tail")
- .field("value", {"cooked": String, "raw": String})
- .field("tail", Boolean);
+ .bases("Declaration")
+ .build("key")
+ .field("key", or(def("Literal"), def("Identifier"), def("Expression")))
+ .field("computed", Boolean, defaults["false"]);
+
+ def("ClassPropertyDefinition") // static property
+ .bases("Declaration")
+ .build("definition")
+ // Yes, Virginia, circular definitions are permitted.
+ .field("definition", ClassBodyElement);
+
+ def("ClassBody")
+ .bases("Declaration")
+ .build("body")
+ .field("body", [ClassBodyElement]);
+
+ def("ClassDeclaration")
+ .bases("Declaration")
+ .build("id", "body", "superClass")
+ .field("id", or(def("Identifier"), null))
+ .field("body", def("ClassBody"))
+ .field("superClass", or(def("Expression"), null), defaults["null"]);
+
+ def("ClassExpression")
+ .bases("Expression")
+ .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
+ // introduced for definitional convenience.
+ def("Specifier").bases("Node");
+
+ // This supertype is shared/abused by both def/babel.js and
+ // def/esprima.js. In the future, it will be possible to load only one set
+ // of definitions appropriate for a given parser, but until then we must
+ // rely on default functions to reconcile the conflicting AST formats.
+ def("ModuleSpecifier")
+ .bases("Specifier")
+ // This local field is used by Babel/Acorn. It should not technically
+ // be optional in the Babel/Acorn AST format, but it must be optional
+ // in the Esprima AST format.
+ .field("local", or(def("Identifier"), null), defaults["null"])
+ // The id and name fields are used by Esprima. The id field should not
+ // technically be optional in the Esprima AST format, but it must be
+ // optional in the Babel/Acorn AST format.
+ .field("id", or(def("Identifier"), null), defaults["null"])
+ .field("name", or(def("Identifier"), null), defaults["null"]);
+
+ def("TaggedTemplateExpression")
+ .bases("Expression")
+ .build("tag", "quasi")
+ .field("tag", def("Expression"))
+ .field("quasi", def("TemplateLiteral"));
+
+ def("TemplateLiteral")
+ .bases("Expression")
+ .build("quasis", "expressions")
+ .field("quasis", [def("TemplateElement")])
+ .field("expressions", [def("Expression")]);
+
+ def("TemplateElement")
+ .bases("Node")
+ .build("value", "tail")
+ .field("value", {"cooked": String, "raw": String})
+ .field("tail", Boolean);
+};
diff --git a/def/es7.js b/def/es7.js
index e9c50bd..7760df6 100644
--- a/def/es7.js
+++ b/def/es7.js
@@ -1,36 +1,38 @@
-require("./es6");
+module.exports = function (fork) {
+ fork.use(require('./es6'));
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-var builtin = types.builtInTypes;
-var defaults = 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("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("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"]);
+ def("AwaitExpression")
+ .bases("Expression")
+ .build("argument", "all")
+ .field("argument", or(def("Expression"), null))
+ .field("all", Boolean, defaults["false"]);
+};
\ No newline at end of file
diff --git a/def/esprima.js b/def/esprima.js
index a27e38f..c0bc3e6 100644
--- a/def/esprima.js
+++ b/def/esprima.js
@@ -1,96 +1,98 @@
-require("./es7");
+module.exports = function (fork) {
+ fork.use(require("./es7"));
-var types = require("../lib/types");
-var defaults = 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("VariableDeclaration")
+ .field("declarations", [or(
def("VariableDeclarator"),
def("Identifier") // Esprima deviation.
- )]);
+ )]);
-def("Property")
- .field("value", or(
+ def("Property")
+ .field("value", or(
def("Expression"),
def("Pattern") // Esprima deviation.
- ));
+ ));
-def("ArrayPattern")
- .field("elements", [or(
+ def("ArrayPattern")
+ .field("elements", [or(
def("Pattern"),
def("SpreadElement"),
null
- )]);
+ )]);
-def("ObjectPattern")
- .field("properties", [or(
+ 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");
+ def("ExportSpecifier")
+ .bases("ModuleSpecifier")
+ .build("id", "name");
// export <*> from ...;
-def("ExportBatchSpecifier")
- .bases("Specifier")
- .build();
+ 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("ImportSpecifier")
+ .bases("ModuleSpecifier")
+ .build("id", "name");
// import <* as id> from ...;
-def("ImportNamespaceSpecifier")
- .bases("ModuleSpecifier")
- .build("id");
+ def("ImportNamespaceSpecifier")
+ .bases("ModuleSpecifier")
+ .build("id");
// import <id> from ...;
-def("ImportDefaultSpecifier")
- .bases("ModuleSpecifier")
- .build("id");
+ def("ImportDefaultSpecifier")
+ .bases("ModuleSpecifier")
+ .build("id");
-def("ExportDeclaration")
- .bases("Declaration")
- .build("default", "declaration", "specifiers", "source")
- .field("default", Boolean)
- .field("declaration", or(
+ 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(
+ ))
+ .field("specifiers", [or(
def("ExportSpecifier"),
def("ExportBatchSpecifier")
- )], defaults.emptyArray)
- .field("source", or(
+ )], defaults.emptyArray)
+ .field("source", or(
def("Literal"),
null
- ), defaults["null"]);
+ ), defaults["null"]);
-def("ImportDeclaration")
- .bases("Declaration")
- .build("specifiers", "source")
- .field("specifiers", [or(
+ def("ImportDeclaration")
+ .bases("Declaration")
+ .build("specifiers", "source")
+ .field("specifiers", [or(
def("ImportSpecifier"),
def("ImportNamespaceSpecifier"),
def("ImportDefaultSpecifier")
- )], defaults.emptyArray)
- .field("source", def("Literal"));
+ )], defaults.emptyArray)
+ .field("source", def("Literal"));
-def("Block")
- .bases("Comment")
- .build("value", /*optional:*/ "leading", "trailing");
+ def("Block")
+ .bases("Comment")
+ .build("value", /*optional:*/ "leading", "trailing");
-def("Line")
- .bases("Comment")
- .build("value", /*optional:*/ "leading", "trailing");
+ def("Line")
+ .bases("Comment")
+ .build("value", /*optional:*/ "leading", "trailing");
+};
\ No newline at end of file
diff --git a/def/flow.js b/def/flow.js
index b7774a6..513322f 100644
--- a/def/flow.js
+++ b/def/flow.js
@@ -1,269 +1,290 @@
-require("./es7");
-
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-var defaults = require("../lib/shared").defaults;
-
-// Type Annotations
-def("Type").bases("Node");
-
-def("AnyTypeAnnotation")
- .bases("Type")
- .build();
-
-def("MixedTypeAnnotation")
- .bases("Type")
- .build();
-
-def("VoidTypeAnnotation")
- .bases("Type")
- .build();
-
-def("NumberTypeAnnotation")
- .bases("Type")
- .build();
-
-def("NumberLiteralTypeAnnotation")
- .bases("Type")
- .build("value", "raw")
- .field("value", Number)
- .field("raw", String);
-
-def("StringTypeAnnotation")
- .bases("Type")
- .build();
-
-def("StringLiteralTypeAnnotation")
- .bases("Type")
- .build("value", "raw")
- .field("value", String)
- .field("raw", String);
-
-def("BooleanTypeAnnotation")
- .bases("Type")
- .build();
-
-def("BooleanLiteralTypeAnnotation")
- .bases("Type")
- .build("value", "raw")
- .field("value", Boolean)
- .field("raw", String);
-
-def("TypeAnnotation")
- .bases("Node")
- .build("typeAnnotation")
- .field("typeAnnotation", def("Type"));
-
-def("NullableTypeAnnotation")
- .bases("Type")
- .build("typeAnnotation")
- .field("typeAnnotation", def("Type"));
-
-def("NullLiteralTypeAnnotation")
- .bases("Type")
- .build();
-
-def("ThisTypeAnnotation")
- .bases("Type")
- .build();
-
-def("FunctionTypeAnnotation")
- .bases("Type")
- .build("params", "returnType", "rest", "typeParameters")
- .field("params", [def("FunctionTypeParam")])
- .field("returnType", def("Type"))
- .field("rest", or(def("FunctionTypeParam"), null))
- .field("typeParameters", or(def("TypeParameterDeclaration"), null));
-
-def("FunctionTypeParam")
- .bases("Node")
- .build("name", "typeAnnotation", "optional")
- .field("name", def("Identifier"))
- .field("typeAnnotation", def("Type"))
- .field("optional", Boolean);
-
-def("ArrayTypeAnnotation")
- .bases("Type")
- .build("elementType")
- .field("elementType", def("Type"));
-
-def("ObjectTypeAnnotation")
- .bases("Type")
- .build("properties")
- .field("properties", [def("ObjectTypeProperty")])
- .field("indexers", [def("ObjectTypeIndexer")], defaults.emptyArray)
- .field("callProperties",
- [def("ObjectTypeCallProperty")],
- defaults.emptyArray);
-
-def("ObjectTypeProperty")
- .bases("Node")
- .build("key", "value", "optional")
- .field("key", or(def("Literal"), def("Identifier")))
- .field("value", def("Type"))
- .field("optional", Boolean);
-
-def("ObjectTypeIndexer")
- .bases("Node")
- .build("id", "key", "value")
- .field("id", def("Identifier"))
- .field("key", def("Type"))
- .field("value", def("Type"));
-
-def("ObjectTypeCallProperty")
- .bases("Node")
- .build("value")
- .field("value", def("FunctionTypeAnnotation"))
- .field("static", Boolean, defaults["false"]);
-
-def("QualifiedTypeIdentifier")
- .bases("Node")
- .build("qualification", "id")
- .field("qualification",
- or(def("Identifier"),
- def("QualifiedTypeIdentifier")))
- .field("id", def("Identifier"));
-
-def("GenericTypeAnnotation")
- .bases("Type")
- .build("id", "typeParameters")
- .field("id", or(def("Identifier"), def("QualifiedTypeIdentifier")))
- .field("typeParameters", or(def("TypeParameterInstantiation"), null));
-
-def("MemberTypeAnnotation")
- .bases("Type")
- .build("object", "property")
- .field("object", def("Identifier"))
- .field("property",
- or(def("MemberTypeAnnotation"),
- def("GenericTypeAnnotation")));
-
-def("UnionTypeAnnotation")
- .bases("Type")
- .build("types")
- .field("types", [def("Type")]);
-
-def("IntersectionTypeAnnotation")
- .bases("Type")
- .build("types")
- .field("types", [def("Type")]);
-
-def("TypeofTypeAnnotation")
- .bases("Type")
- .build("argument")
- .field("argument", def("Type"));
-
-def("Identifier")
- .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
-
-def("TypeParameterDeclaration")
- .bases("Node")
- .build("params")
- .field("params", [def("Identifier")]);
-
-def("TypeParameterInstantiation")
- .bases("Node")
- .build("params")
- .field("params", [def("Type")]);
-
-def("Function")
- .field("returnType",
- or(def("TypeAnnotation"), null),
- defaults["null"])
- .field("typeParameters",
- or(def("TypeParameterDeclaration"), null),
- defaults["null"]);
-
-def("ClassProperty")
- .build("key", "value", "typeAnnotation", "static")
- .field("value", or(def("Expression"), null))
- .field("typeAnnotation", or(def("TypeAnnotation"), null))
- .field("static", Boolean, defaults["false"]);
-
-def("ClassImplements")
- .field("typeParameters",
- or(def("TypeParameterInstantiation"), null),
- defaults["null"]);
-
-def("InterfaceDeclaration")
- .bases("Declaration")
- .build("id", "body", "extends")
- .field("id", def("Identifier"))
- .field("typeParameters",
- or(def("TypeParameterDeclaration"), null),
- defaults["null"])
- .field("body", def("ObjectTypeAnnotation"))
- .field("extends", [def("InterfaceExtends")]);
-
-def("DeclareInterface")
- .bases("InterfaceDeclaration")
- .build("id", "body", "extends");
-
-def("InterfaceExtends")
- .bases("Node")
- .build("id")
- .field("id", def("Identifier"))
- .field("typeParameters", or(def("TypeParameterInstantiation"), null));
-
-def("TypeAlias")
- .bases("Declaration")
- .build("id", "typeParameters", "right")
- .field("id", def("Identifier"))
- .field("typeParameters", or(def("TypeParameterDeclaration"), null))
- .field("right", def("Type"));
-
-def("DeclareTypeAlias")
- .bases("TypeAlias")
- .build("id", "typeParameters", "right");
-
-def("TypeCastExpression")
- .bases("Expression")
- .build("expression", "typeAnnotation")
- .field("expression", def("Expression"))
- .field("typeAnnotation", def("TypeAnnotation"));
-
-def("TupleTypeAnnotation")
- .bases("Type")
- .build("types")
- .field("types", [def("Type")]);
-
-def("DeclareVariable")
- .bases("Statement")
- .build("id")
- .field("id", def("Identifier"));
-
-def("DeclareFunction")
- .bases("Statement")
- .build("id")
- .field("id", def("Identifier"));
-
-def("DeclareClass")
- .bases("InterfaceDeclaration")
- .build("id");
-
-def("DeclareModule")
- .bases("Statement")
- .build("id", "body")
- .field("id", or(def("Identifier"), def("Literal")))
- .field("body", def("BlockStatement"));
-
-def("DeclareExportDeclaration")
- .bases("Declaration")
- .build("default", "declaration", "specifiers", "source")
- .field("default", Boolean)
- .field("declaration", or(
+module.exports = function (fork) {
+ fork.use(require("./es7"));
+
+ var types = fork.use(require("../lib/types"));
+ var def = types.Type.def;
+ var or = types.Type.or;
+ var defaults = fork.use(require("../lib/shared")).defaults;
+
+ // Type Annotations
+ def("Type").bases("Node");
+
+ def("AnyTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("MixedTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("VoidTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("NumberTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("NumberLiteralTypeAnnotation")
+ .bases("Type")
+ .build("value", "raw")
+ .field("value", Number)
+ .field("raw", String);
+
+ def("StringTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("StringLiteralTypeAnnotation")
+ .bases("Type")
+ .build("value", "raw")
+ .field("value", String)
+ .field("raw", String);
+
+ def("BooleanTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("BooleanLiteralTypeAnnotation")
+ .bases("Type")
+ .build("value", "raw")
+ .field("value", Boolean)
+ .field("raw", String);
+
+ def("TypeAnnotation")
+ .bases("Node")
+ .build("typeAnnotation")
+ .field("typeAnnotation", def("Type"));
+
+ def("NullableTypeAnnotation")
+ .bases("Type")
+ .build("typeAnnotation")
+ .field("typeAnnotation", def("Type"));
+
+ def("NullLiteralTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("NullTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("ThisTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("ExistsTypeAnnotation")
+ .bases("Type")
+ .build();
+
+ def("FunctionTypeAnnotation")
+ .bases("Type")
+ .build("params", "returnType", "rest", "typeParameters")
+ .field("params", [def("FunctionTypeParam")])
+ .field("returnType", def("Type"))
+ .field("rest", or(def("FunctionTypeParam"), null))
+ .field("typeParameters", or(def("TypeParameterDeclaration"), null));
+
+ def("FunctionTypeParam")
+ .bases("Node")
+ .build("name", "typeAnnotation", "optional")
+ .field("name", def("Identifier"))
+ .field("typeAnnotation", def("Type"))
+ .field("optional", Boolean);
+
+ def("ArrayTypeAnnotation")
+ .bases("Type")
+ .build("elementType")
+ .field("elementType", def("Type"));
+
+ def("ObjectTypeAnnotation")
+ .bases("Type")
+ .build("properties", "indexers", "callProperties")
+ .field("properties", [def("ObjectTypeProperty")])
+ .field("indexers", [def("ObjectTypeIndexer")], defaults.emptyArray)
+ .field("callProperties",
+ [def("ObjectTypeCallProperty")],
+ defaults.emptyArray);
+
+ def("ObjectTypeProperty")
+ .bases("Node")
+ .build("key", "value", "optional")
+ .field("key", or(def("Literal"), def("Identifier")))
+ .field("value", def("Type"))
+ .field("optional", Boolean);
+
+ def("ObjectTypeIndexer")
+ .bases("Node")
+ .build("id", "key", "value")
+ .field("id", def("Identifier"))
+ .field("key", def("Type"))
+ .field("value", def("Type"));
+
+ def("ObjectTypeCallProperty")
+ .bases("Node")
+ .build("value")
+ .field("value", def("FunctionTypeAnnotation"))
+ .field("static", Boolean, defaults["false"]);
+
+ def("QualifiedTypeIdentifier")
+ .bases("Node")
+ .build("qualification", "id")
+ .field("qualification",
+ or(def("Identifier"),
+ def("QualifiedTypeIdentifier")))
+ .field("id", def("Identifier"));
+
+ def("GenericTypeAnnotation")
+ .bases("Type")
+ .build("id", "typeParameters")
+ .field("id", or(def("Identifier"), def("QualifiedTypeIdentifier")))
+ .field("typeParameters", or(def("TypeParameterInstantiation"), null));
+
+ def("MemberTypeAnnotation")
+ .bases("Type")
+ .build("object", "property")
+ .field("object", def("Identifier"))
+ .field("property",
+ or(def("MemberTypeAnnotation"),
+ def("GenericTypeAnnotation")));
+
+ def("UnionTypeAnnotation")
+ .bases("Type")
+ .build("types")
+ .field("types", [def("Type")]);
+
+ def("IntersectionTypeAnnotation")
+ .bases("Type")
+ .build("types")
+ .field("types", [def("Type")]);
+
+ def("TypeofTypeAnnotation")
+ .bases("Type")
+ .build("argument")
+ .field("argument", def("Type"));
+
+ def("Identifier")
+ .field("typeAnnotation", or(def("TypeAnnotation"), null), defaults["null"]);
+
+ def("TypeParameterDeclaration")
+ .bases("Node")
+ .build("params")
+ .field("params", [def("TypeParameter")]);
+
+ def("TypeParameterInstantiation")
+ .bases("Node")
+ .build("params")
+ .field("params", [def("Type")]);
+
+ def("TypeParameter")
+ .bases("Type")
+ .build("name", "variance", "bound")
+ .field("name", String)
+ .field("variance",
+ or("plus", "minus", null),
+ defaults["null"])
+ .field("bound",
+ or(def("TypeAnnotation"), null),
+ defaults["null"]);
+
+ def("Function")
+ .field("returnType",
+ or(def("TypeAnnotation"), null),
+ defaults["null"])
+ .field("typeParameters",
+ or(def("TypeParameterDeclaration"), null),
+ defaults["null"]);
+
+ def("ClassProperty")
+ .build("key", "value", "typeAnnotation", "static")
+ .field("value", or(def("Expression"), null))
+ .field("typeAnnotation", or(def("TypeAnnotation"), null))
+ .field("static", Boolean, defaults["false"]);
+
+ def("ClassImplements")
+ .field("typeParameters",
+ or(def("TypeParameterInstantiation"), null),
+ defaults["null"]);
+
+ def("InterfaceDeclaration")
+ .bases("Declaration")
+ .build("id", "body", "extends")
+ .field("id", def("Identifier"))
+ .field("typeParameters",
+ or(def("TypeParameterDeclaration"), null),
+ defaults["null"])
+ .field("body", def("ObjectTypeAnnotation"))
+ .field("extends", [def("InterfaceExtends")]);
+
+ def("DeclareInterface")
+ .bases("InterfaceDeclaration")
+ .build("id", "body", "extends");
+
+ def("InterfaceExtends")
+ .bases("Node")
+ .build("id")
+ .field("id", def("Identifier"))
+ .field("typeParameters", or(def("TypeParameterInstantiation"), null));
+
+ def("TypeAlias")
+ .bases("Declaration")
+ .build("id", "typeParameters", "right")
+ .field("id", def("Identifier"))
+ .field("typeParameters", or(def("TypeParameterDeclaration"), null))
+ .field("right", def("Type"));
+
+ def("DeclareTypeAlias")
+ .bases("TypeAlias")
+ .build("id", "typeParameters", "right");
+
+ def("TypeCastExpression")
+ .bases("Expression")
+ .build("expression", "typeAnnotation")
+ .field("expression", def("Expression"))
+ .field("typeAnnotation", def("TypeAnnotation"));
+
+ def("TupleTypeAnnotation")
+ .bases("Type")
+ .build("types")
+ .field("types", [def("Type")]);
+
+ def("DeclareVariable")
+ .bases("Statement")
+ .build("id")
+ .field("id", def("Identifier"));
+
+ def("DeclareFunction")
+ .bases("Statement")
+ .build("id")
+ .field("id", def("Identifier"));
+
+ def("DeclareClass")
+ .bases("InterfaceDeclaration")
+ .build("id");
+
+ def("DeclareModule")
+ .bases("Statement")
+ .build("id", "body")
+ .field("id", or(def("Identifier"), def("Literal")))
+ .field("body", def("BlockStatement"));
+
+ def("DeclareExportDeclaration")
+ .bases("Declaration")
+ .build("default", "declaration", "specifiers", "source")
+ .field("default", Boolean)
+ .field("declaration", or(
def("DeclareVariable"),
def("DeclareFunction"),
def("DeclareClass"),
def("Type"), // Implies default.
null
- ))
- .field("specifiers", [or(
+ ))
+ .field("specifiers", [or(
def("ExportSpecifier"),
def("ExportBatchSpecifier")
- )], defaults.emptyArray)
- .field("source", or(
+ )], defaults.emptyArray)
+ .field("source", or(
def("Literal"),
null
- ), defaults["null"]);
+ ), defaults["null"]);
+};
\ No newline at end of file
diff --git a/def/jsx.js b/def/jsx.js
index 18fa4ea..52656ce 100644
--- a/def/jsx.js
+++ b/def/jsx.js
@@ -1,100 +1,103 @@
-require("./es7");
+module.exports = function (fork) {
+ fork.use(require("./es7"));
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-var defaults = require("../lib/shared").defaults;
+ var types = fork.use(require("../lib/types"));
+ var def = types.Type.def;
+ var or = types.Type.or;
+ var defaults = fork.use(require("../lib/shared")).defaults;
-def("JSXAttribute")
- .bases("Node")
- .build("name", "value")
- .field("name", or(def("JSXIdentifier"), def("JSXNamespacedName")))
- .field("value", or(
+ def("JSXAttribute")
+ .bases("Node")
+ .build("name", "value")
+ .field("name", or(def("JSXIdentifier"), def("JSXNamespacedName")))
+ .field("value", or(
def("Literal"), // attr="value"
def("JSXExpressionContainer"), // attr={value}
null // attr= or just attr
- ), defaults["null"]);
+ ), defaults["null"]);
-def("JSXIdentifier")
- .bases("Identifier")
- .build("name")
- .field("name", String);
+ def("JSXIdentifier")
+ .bases("Identifier")
+ .build("name")
+ .field("name", String);
-def("JSXNamespacedName")
- .bases("Node")
- .build("namespace", "name")
- .field("namespace", def("JSXIdentifier"))
- .field("name", def("JSXIdentifier"));
+ def("JSXNamespacedName")
+ .bases("Node")
+ .build("namespace", "name")
+ .field("namespace", def("JSXIdentifier"))
+ .field("name", def("JSXIdentifier"));
-def("JSXMemberExpression")
- .bases("MemberExpression")
- .build("object", "property")
- .field("object", or(def("JSXIdentifier"), def("JSXMemberExpression")))
- .field("property", def("JSXIdentifier"))
- .field("computed", Boolean, defaults.false);
-
-var JSXElementName = or(
- def("JSXIdentifier"),
- def("JSXNamespacedName"),
def("JSXMemberExpression")
-);
+ .bases("MemberExpression")
+ .build("object", "property")
+ .field("object", or(def("JSXIdentifier"), def("JSXMemberExpression")))
+ .field("property", def("JSXIdentifier"))
+ .field("computed", Boolean, defaults.false);
-def("JSXSpreadAttribute")
- .bases("Node")
- .build("argument")
- .field("argument", def("Expression"));
+ var JSXElementName = or(
+ def("JSXIdentifier"),
+ def("JSXNamespacedName"),
+ def("JSXMemberExpression")
+ );
-var JSXAttributes = [or(
- def("JSXAttribute"),
def("JSXSpreadAttribute")
-)];
+ .bases("Node")
+ .build("argument")
+ .field("argument", def("Expression"));
+
+ var JSXAttributes = [or(
+ def("JSXAttribute"),
+ def("JSXSpreadAttribute")
+ )];
-def("JSXExpressionContainer")
- .bases("Expression")
- .build("expression")
- .field("expression", def("Expression"));
+ def("JSXExpressionContainer")
+ .bases("Expression")
+ .build("expression")
+ .field("expression", def("Expression"));
-def("JSXElement")
- .bases("Expression")
- .build("openingElement", "closingElement", "children")
- .field("openingElement", def("JSXOpeningElement"))
- .field("closingElement", or(def("JSXClosingElement"), null), defaults["null"])
- .field("children", [or(
+ def("JSXElement")
+ .bases("Expression")
+ .build("openingElement", "closingElement", "children")
+ .field("openingElement", def("JSXOpeningElement"))
+ .field("closingElement", or(def("JSXClosingElement"), null), defaults["null"])
+ .field("children", [or(
def("JSXElement"),
def("JSXExpressionContainer"),
def("JSXText"),
def("Literal") // TODO Esprima should return JSXText instead.
- )], defaults.emptyArray)
- .field("name", JSXElementName, function() {
- // Little-known fact: the `this` object inside a default function
- // is none other than the partially-built object itself, and any
- // fields initialized directly from builder function arguments
- // (like openingElement, closingElement, and children) are
- // guaranteed to be available.
- return this.openingElement.name;
- }, true) // hidden from traversal
- .field("selfClosing", Boolean, function() {
- return this.openingElement.selfClosing;
- }, true) // hidden from traversal
- .field("attributes", JSXAttributes, function() {
- return this.openingElement.attributes;
- }, true); // hidden from traversal
+ )], defaults.emptyArray)
+ .field("name", JSXElementName, function () {
+ // Little-known fact: the `this` object inside a default function
+ // is none other than the partially-built object itself, and any
+ // fields initialized directly from builder function arguments
+ // (like openingElement, closingElement, and children) are
+ // guaranteed to be available.
+ return this.openingElement.name;
+ }, true) // hidden from traversal
+ .field("selfClosing", Boolean, function () {
+ return this.openingElement.selfClosing;
+ }, true) // hidden from traversal
+ .field("attributes", JSXAttributes, function () {
+ return this.openingElement.attributes;
+ }, true); // hidden from traversal
+
+ def("JSXOpeningElement")
+ .bases("Node") // TODO Does this make sense? Can't really be an JSXElement.
+ .build("name", "attributes", "selfClosing")
+ .field("name", JSXElementName)
+ .field("attributes", JSXAttributes, defaults.emptyArray)
+ .field("selfClosing", Boolean, defaults["false"]);
-def("JSXOpeningElement")
- .bases("Node") // TODO Does this make sense? Can't really be an JSXElement.
- .build("name", "attributes", "selfClosing")
- .field("name", JSXElementName)
- .field("attributes", JSXAttributes, defaults.emptyArray)
- .field("selfClosing", Boolean, defaults["false"]);
+ def("JSXClosingElement")
+ .bases("Node") // TODO Same concern.
+ .build("name")
+ .field("name", JSXElementName);
-def("JSXClosingElement")
- .bases("Node") // TODO Same concern.
- .build("name")
- .field("name", JSXElementName);
+ def("JSXText")
+ .bases("Literal")
+ .build("value")
+ .field("value", String);
-def("JSXText")
- .bases("Literal")
- .build("value")
- .field("value", String);
+ def("JSXEmptyExpression").bases("Expression").build();
-def("JSXEmptyExpression").bases("Expression").build();
+};
\ No newline at end of file
diff --git a/def/mozilla.js b/def/mozilla.js
index 2861ae9..7636152 100644
--- a/def/mozilla.js
+++ b/def/mozilla.js
@@ -1,49 +1,51 @@
-require("./core");
-var types = require("../lib/types");
-var def = types.Type.def;
-var or = types.Type.or;
-var shared = require("../lib/shared");
-var geq = shared.geq;
-var defaults = shared.defaults;
+module.exports = function (fork) {
+ fork.use(require("./core"));
+ var types = fork.use(require("../lib/types"));
+ var def = types.Type.def;
+ var or = types.Type.or;
+ var shared = fork.use(require("../lib/shared"));
+ var geq = shared.geq;
+ var defaults = shared.defaults;
-def("Function")
- // SpiderMonkey allows expression closures: function(x) x+1
- .field("body", or(def("BlockStatement"), def("Expression")));
+ def("Function")
+ // SpiderMonkey allows expression closures: function(x) x+1
+ .field("body", or(def("BlockStatement"), def("Expression")));
-def("ForInStatement")
- .build("left", "right", "body", "each")
- .field("each", Boolean, defaults["false"]);
+ def("ForInStatement")
+ .build("left", "right", "body", "each")
+ .field("each", Boolean, defaults["false"]);
-def("ForOfStatement")
- .bases("Statement")
- .build("left", "right", "body")
- .field("left", or(
- def("VariableDeclaration"),
- def("Expression")))
- .field("right", def("Expression"))
- .field("body", def("Statement"));
+ def("ForOfStatement")
+ .bases("Statement")
+ .build("left", "right", "body")
+ .field("left", or(
+ def("VariableDeclaration"),
+ def("Expression")))
+ .field("right", def("Expression"))
+ .field("body", def("Statement"));
-def("LetStatement")
- .bases("Statement")
- .build("head", "body")
- // TODO Deviating from the spec by reusing VariableDeclarator here.
- .field("head", [def("VariableDeclarator")])
- .field("body", def("Statement"));
+ def("LetStatement")
+ .bases("Statement")
+ .build("head", "body")
+ // TODO Deviating from the spec by reusing VariableDeclarator here.
+ .field("head", [def("VariableDeclarator")])
+ .field("body", def("Statement"));
-def("LetExpression")
- .bases("Expression")
- .build("head", "body")
- // TODO Deviating from the spec by reusing VariableDeclarator here.
- .field("head", [def("VariableDeclarator")])
- .field("body", def("Expression"));
+ def("LetExpression")
+ .bases("Expression")
+ .build("head", "body")
+ // TODO Deviating from the spec by reusing VariableDeclarator here.
+ .field("head", [def("VariableDeclarator")])
+ .field("body", def("Expression"));
-def("GraphExpression")
- .bases("Expression")
- .build("index", "expression")
- .field("index", geq(0))
- .field("expression", def("Literal"));
+ def("GraphExpression")
+ .bases("Expression")
+ .build("index", "expression")
+ .field("index", geq(0))
+ .field("expression", def("Literal"));
-def("GraphIndexExpression")
- .bases("Expression")
- .build("index")
- .field("index", geq(0));
+ def("GraphIndexExpression")
+ .bases("Expression")
+ .build("index")
+ .field("index", geq(0));
+};
\ No newline at end of file
diff --git a/fork.js b/fork.js
new file mode 100644
index 0000000..e94f5cc
--- /dev/null
+++ b/fork.js
@@ -0,0 +1,46 @@
+module.exports = function (defs) {
+ var used = [];
+ var usedResult = [];
+ var fork = {};
+
+ function use(plugin) {
+ var idx = used.indexOf(plugin);
+ if (idx === -1) {
+ idx = used.length;
+ used.push(plugin);
+ usedResult[idx] = plugin(fork);
+ }
+ return usedResult[idx];
+ }
+
+ fork.use = use;
+
+ var types = use(require('./lib/types'));
+
+ defs.forEach(use);
+
+ types.finalize();
+
+ var exports = {
+ Type: types.Type,
+ builtInTypes: types.builtInTypes,
+ namedTypes: types.namedTypes,
+ builders: types.builders,
+ defineMethod: types.defineMethod,
+ getFieldNames: types.getFieldNames,
+ getFieldValue: types.getFieldValue,
+ eachField: types.eachField,
+ someField: types.someField,
+ getSupertypeNames: types.getSupertypeNames,
+ astNodesAreEquivalent: use(require("./lib/equiv")),
+ finalize: types.finalize,
+ Path: use(require('./lib/path')),
+ NodePath: use(require("./lib/node-path")),
+ PathVisitor: use(require("./lib/path-visitor")),
+ use: use
+ };
+
+ exports.visit = exports.PathVisitor.visit;
+
+ return exports;
+};
\ No newline at end of file
diff --git a/lib/equiv.js b/lib/equiv.js
index 6167577..230ac1f 100644
--- a/lib/equiv.js
+++ b/lib/equiv.js
@@ -1,146 +1,102 @@
-var types = require("../main");
-var getFieldNames = types.getFieldNames;
-var getFieldValue = types.getFieldValue;
-var isArray = types.builtInTypes.array;
-var isObject = types.builtInTypes.object;
-var isDate = types.builtInTypes.Date;
-var isRegExp = types.builtInTypes.RegExp;
-var hasOwn = Object.prototype.hasOwnProperty;
-
-function astNodesAreEquivalent(a, b, problemPath) {
- if (isArray.check(problemPath)) {
- problemPath.length = 0;
- } else {
- problemPath = null;
- }
-
- return areEquivalent(a, b, problemPath);
-}
-
-astNodesAreEquivalent.assert = function(a, b) {
- var problemPath = [];
- if (!astNodesAreEquivalent(a, b, problemPath)) {
- if (problemPath.length === 0) {
- if (a !== b) {
- throw new Error("Nodes must be equal");
- }
+module.exports = function (fork) {
+ var types = fork.use(require('../lib/types'));
+ var getFieldNames = types.getFieldNames;
+ var getFieldValue = types.getFieldValue;
+ var isArray = types.builtInTypes.array;
+ var isObject = types.builtInTypes.object;
+ var isDate = types.builtInTypes.Date;
+ var isRegExp = types.builtInTypes.RegExp;
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ function astNodesAreEquivalent(a, b, problemPath) {
+ if (isArray.check(problemPath)) {
+ problemPath.length = 0;
} else {
- throw new Error(
- "Nodes differ in the following path: " +
- problemPath.map(subscriptForProperty).join("")
- );
+ problemPath = null;
}
- }
-};
-function subscriptForProperty(property) {
- if (/[_$a-z][_$a-z0-9]*/i.test(property)) {
- return "." + property;
+ return areEquivalent(a, b, problemPath);
}
- return "[" + JSON.stringify(property) + "]";
-}
-function areEquivalent(a, b, problemPath) {
- if (a === b) {
- return true;
- }
-
- if (isArray.check(a)) {
- return arraysAreEquivalent(a, b, problemPath);
- }
-
- if (isObject.check(a)) {
- return objectsAreEquivalent(a, b, problemPath);
- }
-
- if (isDate.check(a)) {
- return isDate.check(b) && (+a === +b);
- }
-
- if (isRegExp.check(a)) {
- return isRegExp.check(b) && (
- a.source === b.source &&
- a.global === b.global &&
- a.multiline === b.multiline &&
- a.ignoreCase === b.ignoreCase
- );
- }
-
- return a == b;
-}
-
-function arraysAreEquivalent(a, b, problemPath) {
- isArray.assert(a);
- var aLength = a.length;
+ astNodesAreEquivalent.assert = function (a, b) {
+ var problemPath = [];
+ if (!astNodesAreEquivalent(a, b, problemPath)) {
+ if (problemPath.length === 0) {
+ if (a !== b) {
+ throw new Error("Nodes must be equal");
+ }
+ } else {
+ throw new Error(
+ "Nodes differ in the following path: " +
+ problemPath.map(subscriptForProperty).join("")
+ );
+ }
+ }
+ };
- if (!isArray.check(b) || b.length !== aLength) {
- if (problemPath) {
- problemPath.push("length");
+ function subscriptForProperty(property) {
+ if (/[_$a-z][_$a-z0-9]*/i.test(property)) {
+ return "." + property;
}
- return false;
+ return "[" + JSON.stringify(property) + "]";
}
- for (var i = 0; i < aLength; ++i) {
- if (problemPath) {
- problemPath.push(i);
+ function areEquivalent(a, b, problemPath) {
+ if (a === b) {
+ return true;
}
- if (i in a !== i in b) {
- return false;
+ if (isArray.check(a)) {
+ return arraysAreEquivalent(a, b, problemPath);
}
- if (!areEquivalent(a[i], b[i], problemPath)) {
- return false;
+ if (isObject.check(a)) {
+ return objectsAreEquivalent(a, b, problemPath);
}
- if (problemPath) {
- var problemPathTail = problemPath.pop();
- if (problemPathTail !== i) {
- throw new Error("" + problemPathTail);
- }
+ if (isDate.check(a)) {
+ return isDate.check(b) && (+a === +b);
}
- }
-
- return true;
-}
-function objectsAreEquivalent(a, b, problemPath) {
- isObject.assert(a);
- if (!isObject.check(b)) {
- return false;
- }
-
- // Fast path for a common property of AST nodes.
- if (a.type !== b.type) {
- if (problemPath) {
- problemPath.push("type");
+ if (isRegExp.check(a)) {
+ return isRegExp.check(b) && (
+ a.source === b.source &&
+ a.global === b.global &&
+ a.multiline === b.multiline &&
+ a.ignoreCase === b.ignoreCase
+ );
}
- return false;
- }
- var aNames = getFieldNames(a);
- var aNameCount = aNames.length;
+ return a == b;
+ }
- var bNames = getFieldNames(b);
- var bNameCount = bNames.length;
+ function arraysAreEquivalent(a, b, problemPath) {
+ isArray.assert(a);
+ var aLength = a.length;
- if (aNameCount === bNameCount) {
- for (var i = 0; i < aNameCount; ++i) {
- var name = aNames[i];
- var aChild = getFieldValue(a, name);
- var bChild = getFieldValue(b, name);
+ if (!isArray.check(b) || b.length !== aLength) {
+ if (problemPath) {
+ problemPath.push("length");
+ }
+ return false;
+ }
+ for (var i = 0; i < aLength; ++i) {
if (problemPath) {
- problemPath.push(name);
+ problemPath.push(i);
}
- if (!areEquivalent(aChild, bChild, problemPath)) {
+ if (i in a !== i in b) {
+ return false;
+ }
+
+ if (!areEquivalent(a[i], b[i], problemPath)) {
return false;
}
if (problemPath) {
var problemPathTail = problemPath.pop();
- if (problemPathTail !== name) {
+ if (problemPathTail !== i) {
throw new Error("" + problemPathTail);
}
}
@@ -149,36 +105,82 @@ function objectsAreEquivalent(a, b, problemPath) {
return true;
}
- if (!problemPath) {
- return false;
- }
+ function objectsAreEquivalent(a, b, problemPath) {
+ isObject.assert(a);
+ if (!isObject.check(b)) {
+ return false;
+ }
- // Since aNameCount !== bNameCount, we need to find some name that's
- // missing in aNames but present in bNames, or vice-versa.
+ // Fast path for a common property of AST nodes.
+ if (a.type !== b.type) {
+ if (problemPath) {
+ problemPath.push("type");
+ }
+ return false;
+ }
- var seenNames = Object.create(null);
+ var aNames = getFieldNames(a);
+ var aNameCount = aNames.length;
- for (i = 0; i < aNameCount; ++i) {
- seenNames[aNames[i]] = true;
- }
+ var bNames = getFieldNames(b);
+ var bNameCount = bNames.length;
- for (i = 0; i < bNameCount; ++i) {
- name = bNames[i];
+ if (aNameCount === bNameCount) {
+ for (var i = 0; i < aNameCount; ++i) {
+ var name = aNames[i];
+ var aChild = getFieldValue(a, name);
+ var bChild = getFieldValue(b, name);
- if (!hasOwn.call(seenNames, name)) {
- problemPath.push(name);
+ if (problemPath) {
+ problemPath.push(name);
+ }
+
+ if (!areEquivalent(aChild, bChild, problemPath)) {
+ return false;
+ }
+
+ if (problemPath) {
+ var problemPathTail = problemPath.pop();
+ if (problemPathTail !== name) {
+ throw new Error("" + problemPathTail);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ if (!problemPath) {
return false;
}
- delete seenNames[name];
- }
+ // Since aNameCount !== bNameCount, we need to find some name that's
+ // missing in aNames but present in bNames, or vice-versa.
- for (name in seenNames) {
- problemPath.push(name);
- break;
- }
+ var seenNames = Object.create(null);
- return false;
-}
+ for (i = 0; i < aNameCount; ++i) {
+ seenNames[aNames[i]] = true;
+ }
+
+ for (i = 0; i < bNameCount; ++i) {
+ name = bNames[i];
-module.exports = astNodesAreEquivalent;
+ if (!hasOwn.call(seenNames, name)) {
+ problemPath.push(name);
+ return false;
+ }
+
+ delete seenNames[name];
+ }
+
+ for (name in seenNames) {
+ problemPath.push(name);
+ break;
+ }
+
+ return false;
+ }
+
+ return astNodesAreEquivalent;
+};
diff --git a/lib/node-path.js b/lib/node-path.js
index fbb79ea..3270734 100644
--- a/lib/node-path.js
+++ b/lib/node-path.js
@@ -1,474 +1,476 @@
-var types = require("./types");
-var n = types.namedTypes;
-var b = types.builders;
-var isNumber = types.builtInTypes.number;
-var isArray = types.builtInTypes.array;
-var Path = require("./path");
-var Scope = require("./scope");
-
-function NodePath(value, parentPath, name) {
- if (!(this instanceof NodePath)) {
- throw new Error("NodePath constructor cannot be invoked without 'new'");
- }
- Path.call(this, value, parentPath, name);
-}
-
-var NPp = NodePath.prototype = Object.create(Path.prototype, {
- constructor: {
- value: NodePath,
- enumerable: false,
- writable: true,
- configurable: true
- }
-});
-
-Object.defineProperties(NPp, {
- node: {
- get: function() {
- Object.defineProperty(this, "node", {
- configurable: true, // Enable deletion.
- value: this._computeNode()
- });
-
- return this.node;
+module.exports = function (fork) {
+ var types = fork.use(require("./types"));
+ var n = types.namedTypes;
+ var b = types.builders;
+ var isNumber = types.builtInTypes.number;
+ var isArray = types.builtInTypes.array;
+ var Path = fork.use(require("./path"));
+ var Scope = fork.use(require("./scope"));
+
+ function NodePath(value, parentPath, name) {
+ if (!(this instanceof NodePath)) {
+ throw new Error("NodePath constructor cannot be invoked without 'new'");
}
- },
-
- parent: {
- get: function() {
- Object.defineProperty(this, "parent", {
- configurable: true, // Enable deletion.
- value: this._computeParent()
- });
+ Path.call(this, value, parentPath, name);
+ }
- return this.parent;
+ var NPp = NodePath.prototype = Object.create(Path.prototype, {
+ constructor: {
+ value: NodePath,
+ enumerable: false,
+ writable: true,
+ configurable: true
}
- },
+ });
- scope: {
- get: function() {
- Object.defineProperty(this, "scope", {
- configurable: true, // Enable deletion.
- value: this._computeScope()
- });
+ Object.defineProperties(NPp, {
+ node: {
+ get: function () {
+ Object.defineProperty(this, "node", {
+ configurable: true, // Enable deletion.
+ value: this._computeNode()
+ });
- return this.scope;
- }
- }
-});
+ return this.node;
+ }
+ },
-NPp.replace = function() {
- delete this.node;
- delete this.parent;
- delete this.scope;
- return Path.prototype.replace.apply(this, arguments);
-};
+ parent: {
+ get: function () {
+ Object.defineProperty(this, "parent", {
+ configurable: true, // Enable deletion.
+ value: this._computeParent()
+ });
-NPp.prune = function() {
- var remainingNodePath = this.parent;
+ return this.parent;
+ }
+ },
- this.replace();
+ scope: {
+ get: function () {
+ Object.defineProperty(this, "scope", {
+ configurable: true, // Enable deletion.
+ value: this._computeScope()
+ });
- return cleanUpNodesAfterPrune(remainingNodePath);
-};
+ return this.scope;
+ }
+ }
+ });
-// The value of the first ancestor Path whose value is a Node.
-NPp._computeNode = function() {
- var value = this.value;
- if (n.Node.check(value)) {
- return value;
- }
+ NPp.replace = function () {
+ delete this.node;
+ delete this.parent;
+ delete this.scope;
+ return Path.prototype.replace.apply(this, arguments);
+ };
- var pp = this.parentPath;
- return pp && pp.node || null;
-};
+ NPp.prune = function () {
+ var remainingNodePath = this.parent;
-// The first ancestor Path whose value is a Node distinct from this.node.
-NPp._computeParent = function() {
- var value = this.value;
- var pp = this.parentPath;
+ this.replace();
- if (!n.Node.check(value)) {
- while (pp && !n.Node.check(pp.value)) {
- pp = pp.parentPath;
- }
+ return cleanUpNodesAfterPrune(remainingNodePath);
+ };
- if (pp) {
- pp = pp.parentPath;
+ // The value of the first ancestor Path whose value is a Node.
+ NPp._computeNode = function () {
+ var value = this.value;
+ if (n.Node.check(value)) {
+ return value;
}
- }
- while (pp && !n.Node.check(pp.value)) {
- pp = pp.parentPath;
- }
-
- return pp || null;
-};
-
-// The closest enclosing scope that governs this node.
-NPp._computeScope = function() {
- var value = this.value;
- var pp = this.parentPath;
- var scope = pp && pp.scope;
+ var pp = this.parentPath;
+ return pp && pp.node || null;
+ };
- if (n.Node.check(value) &&
- Scope.isEstablishedBy(value)) {
- scope = new Scope(this, scope);
- }
+ // The first ancestor Path whose value is a Node distinct from this.node.
+ NPp._computeParent = function () {
+ var value = this.value;
+ var pp = this.parentPath;
- return scope || null;
-};
+ if (!n.Node.check(value)) {
+ while (pp && !n.Node.check(pp.value)) {
+ pp = pp.parentPath;
+ }
-NPp.getValueProperty = function(name) {
- return types.getFieldValue(this.value, name);
-};
+ if (pp) {
+ pp = pp.parentPath;
+ }
+ }
-/**
- * Determine whether this.node needs to be wrapped in parentheses in order
- * for a parser to reproduce the same local AST structure.
- *
- * For instance, in the expression `(1 + 2) * 3`, the BinaryExpression
- * whose operator is "+" needs parentheses, because `1 + 2 * 3` would
- * parse differently.
- *
- * If assumeExpressionContext === true, we don't worry about edge cases
- * like an anonymous FunctionExpression appearing lexically first in its
- * enclosing statement and thus needing parentheses to avoid being parsed
- * as a FunctionDeclaration with a missing name.
- */
-NPp.needsParens = function(assumeExpressionContext) {
- var pp = this.parentPath;
- if (!pp) {
- return false;
- }
+ while (pp && !n.Node.check(pp.value)) {
+ pp = pp.parentPath;
+ }
- var node = this.value;
+ return pp || null;
+ };
- // Only expressions need parentheses.
- if (!n.Expression.check(node)) {
- return false;
- }
+ // The closest enclosing scope that governs this node.
+ NPp._computeScope = function () {
+ var value = this.value;
+ var pp = this.parentPath;
+ var scope = pp && pp.scope;
- // Identifiers never need parentheses.
- if (node.type === "Identifier") {
- return false;
- }
+ if (n.Node.check(value) &&
+ Scope.isEstablishedBy(value)) {
+ scope = new Scope(this, scope);
+ }
- while (!n.Node.check(pp.value)) {
- pp = pp.parentPath;
+ return scope || null;
+ };
+
+ NPp.getValueProperty = function (name) {
+ return types.getFieldValue(this.value, name);
+ };
+
+ /**
+ * Determine whether this.node needs to be wrapped in parentheses in order
+ * for a parser to reproduce the same local AST structure.
+ *
+ * For instance, in the expression `(1 + 2) * 3`, the BinaryExpression
+ * whose operator is "+" needs parentheses, because `1 + 2 * 3` would
+ * parse differently.
+ *
+ * If assumeExpressionContext === true, we don't worry about edge cases
+ * like an anonymous FunctionExpression appearing lexically first in its
+ * enclosing statement and thus needing parentheses to avoid being parsed
+ * as a FunctionDeclaration with a missing name.
+ */
+ NPp.needsParens = function (assumeExpressionContext) {
+ var pp = this.parentPath;
if (!pp) {
return false;
}
- }
- var parent = pp.value;
-
- switch (node.type) {
- case "UnaryExpression":
- case "SpreadElement":
- case "SpreadProperty":
- return parent.type === "MemberExpression"
- && this.name === "object"
- && parent.object === node;
-
- case "BinaryExpression":
- case "LogicalExpression":
- switch (parent.type) {
- case "CallExpression":
- return this.name === "callee"
- && parent.callee === node;
-
- case "UnaryExpression":
- case "SpreadElement":
- case "SpreadProperty":
- return true;
-
- case "MemberExpression":
- return this.name === "object"
- && parent.object === node;
+ var node = this.value;
- case "BinaryExpression":
- case "LogicalExpression":
- var po = parent.operator;
- var pp = PRECEDENCE[po];
- var no = node.operator;
- var np = PRECEDENCE[no];
-
- if (pp > np) {
- return true;
- }
-
- if (pp === np && this.name === "right") {
- if (parent.right !== node) {
- throw new Error("Nodes must be equal");
- }
- return true;
- }
-
- default:
+ // Only expressions need parentheses.
+ if (!n.Expression.check(node)) {
return false;
}
- case "SequenceExpression":
- switch (parent.type) {
- case "ForStatement":
- // Although parentheses wouldn't hurt around sequence
- // expressions in the head of for loops, traditional style
- // dictates that e.g. i++, j++ should not be wrapped with
- // parentheses.
+ // Identifiers never need parentheses.
+ if (node.type === "Identifier") {
return false;
-
- case "ExpressionStatement":
- return this.name !== "expression";
-
- default:
- // Otherwise err on the side of overparenthesization, adding
- // explicit exceptions above if this proves overzealous.
- return true;
}
- case "YieldExpression":
- switch (parent.type) {
- case "BinaryExpression":
- case "LogicalExpression":
- case "UnaryExpression":
- case "SpreadElement":
- case "SpreadProperty":
- case "CallExpression":
- case "MemberExpression":
- case "NewExpression":
- case "ConditionalExpression":
- case "YieldExpression":
- return true;
-
- default:
- return false;
+ while (!n.Node.check(pp.value)) {
+ pp = pp.parentPath;
+ if (!pp) {
+ return false;
+ }
}
- case "Literal":
- return parent.type === "MemberExpression"
- && isNumber.check(node.value)
- && this.name === "object"
- && parent.object === node;
-
- case "AssignmentExpression":
- case "ConditionalExpression":
- switch (parent.type) {
- case "UnaryExpression":
- case "SpreadElement":
- case "SpreadProperty":
- case "BinaryExpression":
- case "LogicalExpression":
- return true;
-
- case "CallExpression":
- return this.name === "callee"
- && parent.callee === node;
+ var parent = pp.value;
+
+ switch (node.type) {
+ case "UnaryExpression":
+ case "SpreadElement":
+ case "SpreadProperty":
+ return parent.type === "MemberExpression"
+ && this.name === "object"
+ && parent.object === node;
+
+ case "BinaryExpression":
+ case "LogicalExpression":
+ switch (parent.type) {
+ case "CallExpression":
+ return this.name === "callee"
+ && parent.callee === node;
+
+ case "UnaryExpression":
+ case "SpreadElement":
+ case "SpreadProperty":
+ return true;
+
+ case "MemberExpression":
+ return this.name === "object"
+ && parent.object === node;
+
+ case "BinaryExpression":
+ case "LogicalExpression":
+ var po = parent.operator;
+ var pp = PRECEDENCE[po];
+ var no = node.operator;
+ var np = PRECEDENCE[no];
+
+ if (pp > np) {
+ return true;
+ }
+
+ if (pp === np && this.name === "right") {
+ if (parent.right !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ return true;
+ }
+
+ default:
+ return false;
+ }
- case "ConditionalExpression":
- return this.name === "test"
- && parent.test === node;
+ case "SequenceExpression":
+ switch (parent.type) {
+ case "ForStatement":
+ // Although parentheses wouldn't hurt around sequence
+ // expressions in the head of for loops, traditional style
+ // dictates that e.g. i++, j++ should not be wrapped with
+ // parentheses.
+ return false;
+
+ case "ExpressionStatement":
+ return this.name !== "expression";
+
+ default:
+ // Otherwise err on the side of overparenthesization, adding
+ // explicit exceptions above if this proves overzealous.
+ return true;
+ }
- case "MemberExpression":
- return this.name === "object"
- && parent.object === node;
+ case "YieldExpression":
+ switch (parent.type) {
+ case "BinaryExpression":
+ case "LogicalExpression":
+ case "UnaryExpression":
+ case "SpreadElement":
+ case "SpreadProperty":
+ case "CallExpression":
+ case "MemberExpression":
+ case "NewExpression":
+ case "ConditionalExpression":
+ case "YieldExpression":
+ return true;
+
+ default:
+ return false;
+ }
- default:
- return false;
- }
+ case "Literal":
+ return parent.type === "MemberExpression"
+ && isNumber.check(node.value)
+ && this.name === "object"
+ && parent.object === node;
+
+ case "AssignmentExpression":
+ case "ConditionalExpression":
+ switch (parent.type) {
+ case "UnaryExpression":
+ case "SpreadElement":
+ case "SpreadProperty":
+ case "BinaryExpression":
+ case "LogicalExpression":
+ return true;
+
+ case "CallExpression":
+ return this.name === "callee"
+ && parent.callee === node;
+
+ case "ConditionalExpression":
+ return this.name === "test"
+ && parent.test === node;
+
+ case "MemberExpression":
+ return this.name === "object"
+ && parent.object === node;
+
+ default:
+ return false;
+ }
- default:
- if (parent.type === "NewExpression" &&
- this.name === "callee" &&
- parent.callee === node) {
- return containsCallExpression(node);
+ default:
+ if (parent.type === "NewExpression" &&
+ this.name === "callee" &&
+ parent.callee === node) {
+ return containsCallExpression(node);
+ }
}
- }
- if (assumeExpressionContext !== true &&
- !this.canBeFirstInStatement() &&
- this.firstInStatement())
- return true;
-
- return false;
-};
+ if (assumeExpressionContext !== true &&
+ !this.canBeFirstInStatement() &&
+ this.firstInStatement())
+ return true;
-function isBinary(node) {
- return n.BinaryExpression.check(node)
- || n.LogicalExpression.check(node);
-}
-
-function isUnaryLike(node) {
- return n.UnaryExpression.check(node)
- // I considered making SpreadElement and SpreadProperty subtypes
- // of UnaryExpression, but they're not really Expression nodes.
- || (n.SpreadElement && n.SpreadElement.check(node))
- || (n.SpreadProperty && n.SpreadProperty.check(node));
-}
-
-var PRECEDENCE = {};
-[["||"],
- ["&&"],
- ["|"],
- ["^"],
- ["&"],
- ["==", "===", "!=", "!=="],
- ["<", ">", "<=", ">=", "in", "instanceof"],
- [">>", "<<", ">>>"],
- ["+", "-"],
- ["*", "/", "%"]
-].forEach(function(tier, i) {
- tier.forEach(function(op) {
- PRECEDENCE[op] = i;
- });
-});
+ return false;
+ };
-function containsCallExpression(node) {
- if (n.CallExpression.check(node)) {
- return true;
+ function isBinary(node) {
+ return n.BinaryExpression.check(node)
+ || n.LogicalExpression.check(node);
}
- if (isArray.check(node)) {
- return node.some(containsCallExpression);
+ function isUnaryLike(node) {
+ return n.UnaryExpression.check(node)
+ // I considered making SpreadElement and SpreadProperty subtypes
+ // of UnaryExpression, but they're not really Expression nodes.
+ || (n.SpreadElement && n.SpreadElement.check(node))
+ || (n.SpreadProperty && n.SpreadProperty.check(node));
}
- if (n.Node.check(node)) {
- return types.someField(node, function(name, child) {
- return containsCallExpression(child);
+ var PRECEDENCE = {};
+ [["||"],
+ ["&&"],
+ ["|"],
+ ["^"],
+ ["&"],
+ ["==", "===", "!=", "!=="],
+ ["<", ">", "<=", ">=", "in", "instanceof"],
+ [">>", "<<", ">>>"],
+ ["+", "-"],
+ ["*", "/", "%"]
+ ].forEach(function (tier, i) {
+ tier.forEach(function (op) {
+ PRECEDENCE[op] = i;
});
- }
+ });
- return false;
-}
+ function containsCallExpression(node) {
+ if (n.CallExpression.check(node)) {
+ return true;
+ }
-NPp.canBeFirstInStatement = function() {
- var node = this.node;
- return !n.FunctionExpression.check(node)
- && !n.ObjectExpression.check(node);
-};
+ if (isArray.check(node)) {
+ return node.some(containsCallExpression);
+ }
-NPp.firstInStatement = function() {
- return firstInStatement(this);
-};
+ if (n.Node.check(node)) {
+ return types.someField(node, function (name, child) {
+ return containsCallExpression(child);
+ });
+ }
-function firstInStatement(path) {
- for (var node, parent; path.parent; path = path.parent) {
- node = path.node;
- parent = path.parent.node;
+ return false;
+ }
- if (n.BlockStatement.check(parent) &&
- path.parent.name === "body" &&
- path.name === 0) {
- if (parent.body[0] !== node) {
- throw new Error("Nodes must be equal");
+ NPp.canBeFirstInStatement = function () {
+ var node = this.node;
+ return !n.FunctionExpression.check(node)
+ && !n.ObjectExpression.check(node);
+ };
+
+ NPp.firstInStatement = function () {
+ return firstInStatement(this);
+ };
+
+ function firstInStatement(path) {
+ for (var node, parent; path.parent; path = path.parent) {
+ node = path.node;
+ parent = path.parent.node;
+
+ if (n.BlockStatement.check(parent) &&
+ path.parent.name === "body" &&
+ path.name === 0) {
+ if (parent.body[0] !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ return true;
}
- return true;
- }
- if (n.ExpressionStatement.check(parent) &&
- path.name === "expression") {
- if (parent.expression !== node) {
- throw new Error("Nodes must be equal");
+ if (n.ExpressionStatement.check(parent) &&
+ path.name === "expression") {
+ if (parent.expression !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ return true;
}
- return true;
- }
- if (n.SequenceExpression.check(parent) &&
- path.parent.name === "expressions" &&
- path.name === 0) {
- if (parent.expressions[0] !== node) {
- throw new Error("Nodes must be equal");
+ if (n.SequenceExpression.check(parent) &&
+ path.parent.name === "expressions" &&
+ path.name === 0) {
+ if (parent.expressions[0] !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
- }
- if (n.CallExpression.check(parent) &&
- path.name === "callee") {
- if (parent.callee !== node) {
- throw new Error("Nodes must be equal");
+ if (n.CallExpression.check(parent) &&
+ path.name === "callee") {
+ if (parent.callee !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
- }
- if (n.MemberExpression.check(parent) &&
- path.name === "object") {
- if (parent.object !== node) {
- throw new Error("Nodes must be equal");
+ if (n.MemberExpression.check(parent) &&
+ path.name === "object") {
+ if (parent.object !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
- }
- if (n.ConditionalExpression.check(parent) &&
- path.name === "test") {
- if (parent.test !== node) {
- throw new Error("Nodes must be equal");
+ if (n.ConditionalExpression.check(parent) &&
+ path.name === "test") {
+ if (parent.test !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
- }
- if (isBinary(parent) &&
- path.name === "left") {
- if (parent.left !== node) {
- throw new Error("Nodes must be equal");
+ if (isBinary(parent) &&
+ path.name === "left") {
+ if (parent.left !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
- }
- if (n.UnaryExpression.check(parent) &&
- !parent.prefix &&
- path.name === "argument") {
- if (parent.argument !== node) {
- throw new Error("Nodes must be equal");
+ if (n.UnaryExpression.check(parent) &&
+ !parent.prefix &&
+ path.name === "argument") {
+ if (parent.argument !== node) {
+ throw new Error("Nodes must be equal");
+ }
+ continue;
}
- continue;
+
+ return false;
}
- return false;
+ return true;
}
- return true;
-}
-
-/**
- * Pruning certain nodes will result in empty or incomplete nodes, here we clean those nodes up.
- */
-function cleanUpNodesAfterPrune(remainingNodePath) {
- if (n.VariableDeclaration.check(remainingNodePath.node)) {
- var declarations = remainingNodePath.get('declarations').value;
- if (!declarations || declarations.length === 0) {
- return remainingNodePath.prune();
- }
- } else if (n.ExpressionStatement.check(remainingNodePath.node)) {
- if (!remainingNodePath.get('expression').value) {
- return remainingNodePath.prune();
+ /**
+ * Pruning certain nodes will result in empty or incomplete nodes, here we clean those nodes up.
+ */
+ function cleanUpNodesAfterPrune(remainingNodePath) {
+ if (n.VariableDeclaration.check(remainingNodePath.node)) {
+ var declarations = remainingNodePath.get('declarations').value;
+ if (!declarations || declarations.length === 0) {
+ return remainingNodePath.prune();
+ }
+ } else if (n.ExpressionStatement.check(remainingNodePath.node)) {
+ if (!remainingNodePath.get('expression').value) {
+ return remainingNodePath.prune();
+ }
+ } else if (n.IfStatement.check(remainingNodePath.node)) {
+ cleanUpIfStatementAfterPrune(remainingNodePath);
}
- } else if (n.IfStatement.check(remainingNodePath.node)) {
- cleanUpIfStatementAfterPrune(remainingNodePath);
+
+ return remainingNodePath;
}
- return remainingNodePath;
-}
+ function cleanUpIfStatementAfterPrune(ifStatement) {
+ var testExpression = ifStatement.get('test').value;
+ var alternate = ifStatement.get('alternate').value;
+ var consequent = ifStatement.get('consequent').value;
-function cleanUpIfStatementAfterPrune(ifStatement) {
- var testExpression = ifStatement.get('test').value;
- var alternate = ifStatement.get('alternate').value;
- var consequent = ifStatement.get('consequent').value;
+ if (!consequent && !alternate) {
+ var testExpressionStatement = b.expressionStatement(testExpression);
- if (!consequent && !alternate) {
- var testExpressionStatement = b.expressionStatement(testExpression);
+ ifStatement.replace(testExpressionStatement);
+ } else if (!consequent && alternate) {
+ var negatedTestExpression = b.unaryExpression('!', testExpression, true);
- ifStatement.replace(testExpressionStatement);
- } else if (!consequent && alternate) {
- var negatedTestExpression = b.unaryExpression('!', testExpression, true);
+ if (n.UnaryExpression.check(testExpression) && testExpression.operator === '!') {
+ negatedTestExpression = testExpression.argument;
+ }
- if (n.UnaryExpression.check(testExpression) && testExpression.operator === '!') {
- negatedTestExpression = testExpression.argument;
+ ifStatement.get("test").replace(negatedTestExpression);
+ ifStatement.get("consequent").replace(alternate);
+ ifStatement.get("alternate").replace();
}
-
- ifStatement.get("test").replace(negatedTestExpression);
- ifStatement.get("consequent").replace(alternate);
- ifStatement.get("alternate").replace();
}
-}
-module.exports = NodePath;
+ return NodePath;
+};
diff --git a/lib/path-visitor.js b/lib/path-visitor.js
index cfe1441..d6b50fa 100644
--- a/lib/path-visitor.js
+++ b/lib/path-visitor.js
@@ -1,419 +1,422 @@
-var types = require("./types");
-var NodePath = require("./node-path");
-var Printable = types.namedTypes.Printable;
-var isArray = types.builtInTypes.array;
-var isObject = types.builtInTypes.object;
-var isFunction = types.builtInTypes.function;
var hasOwn = Object.prototype.hasOwnProperty;
-var undefined;
-function PathVisitor() {
- if (!(this instanceof PathVisitor)) {
- throw new Error(
- "PathVisitor constructor cannot be invoked without 'new'"
- );
- }
-
- // Permanent state.
- this._reusableContextStack = [];
+module.exports = function (fork) {
+ var types = fork.use(require("./types"));
+ var NodePath = fork.use(require("./node-path"));
+ var Printable = types.namedTypes.Printable;
+ var isArray = types.builtInTypes.array;
+ var isObject = types.builtInTypes.object;
+ var isFunction = types.builtInTypes.function;
+ var undefined;
- this._methodNameTable = computeMethodNameTable(this);
- this._shouldVisitComments =
- hasOwn.call(this._methodNameTable, "Block") ||
- hasOwn.call(this._methodNameTable, "Line");
+ function PathVisitor() {
+ if (!(this instanceof PathVisitor)) {
+ throw new Error(
+ "PathVisitor constructor cannot be invoked without 'new'"
+ );
+ }
- this.Context = makeContextConstructor(this);
+ // Permanent state.
+ this._reusableContextStack = [];
- // State reset every time PathVisitor.prototype.visit is called.
- this._visiting = false;
- this._changeReported = false;
-}
+ this._methodNameTable = computeMethodNameTable(this);
+ this._shouldVisitComments =
+ hasOwn.call(this._methodNameTable, "Block") ||
+ hasOwn.call(this._methodNameTable, "Line");
-function computeMethodNameTable(visitor) {
- var typeNames = Object.create(null);
+ this.Context = makeContextConstructor(this);
- for (var methodName in visitor) {
- if (/^visit[A-Z]/.test(methodName)) {
- typeNames[methodName.slice("visit".length)] = true;
- }
+ // State reset every time PathVisitor.prototype.visit is called.
+ this._visiting = false;
+ this._changeReported = false;
}
- var supertypeTable = types.computeSupertypeLookupTable(typeNames);
- var methodNameTable = Object.create(null);
+ function computeMethodNameTable(visitor) {
+ var typeNames = Object.create(null);
- var typeNames = Object.keys(supertypeTable);
- var typeNameCount = typeNames.length;
- for (var i = 0; i < typeNameCount; ++i) {
- var typeName = typeNames[i];
- methodName = "visit" + supertypeTable[typeName];
- if (isFunction.check(visitor[methodName])) {
- methodNameTable[typeName] = methodName;
+ for (var methodName in visitor) {
+ if (/^visit[A-Z]/.test(methodName)) {
+ typeNames[methodName.slice("visit".length)] = true;
+ }
}
- }
- return methodNameTable;
-}
+ var supertypeTable = types.computeSupertypeLookupTable(typeNames);
+ var methodNameTable = Object.create(null);
-PathVisitor.fromMethodsObject = function fromMethodsObject(methods) {
- if (methods instanceof PathVisitor) {
- return methods;
- }
+ var typeNames = Object.keys(supertypeTable);
+ var typeNameCount = typeNames.length;
+ for (var i = 0; i < typeNameCount; ++i) {
+ var typeName = typeNames[i];
+ methodName = "visit" + supertypeTable[typeName];
+ if (isFunction.check(visitor[methodName])) {
+ methodNameTable[typeName] = methodName;
+ }
+ }
- if (!isObject.check(methods)) {
- // An empty visitor?
- return new PathVisitor;
+ return methodNameTable;
}
- function Visitor() {
- if (!(this instanceof Visitor)) {
- throw new Error(
- "Visitor constructor cannot be invoked without 'new'"
- );
+ PathVisitor.fromMethodsObject = function fromMethodsObject(methods) {
+ if (methods instanceof PathVisitor) {
+ return methods;
}
- PathVisitor.call(this);
- }
- var Vp = Visitor.prototype = Object.create(PVp);
- Vp.constructor = Visitor;
-
- extend(Vp, methods);
- extend(Visitor, PathVisitor);
-
- isFunction.assert(Visitor.fromMethodsObject);
- isFunction.assert(Visitor.visit);
-
- return new Visitor;
-};
-
-function extend(target, source) {
- for (var property in source) {
- if (hasOwn.call(source, property)) {
- target[property] = source[property];
+ if (!isObject.check(methods)) {
+ // An empty visitor?
+ return new PathVisitor;
}
- }
-
- return target;
-}
-
-PathVisitor.visit = function visit(node, methods) {
- return PathVisitor.fromMethodsObject(methods).visit(node);
-};
-
-var PVp = PathVisitor.prototype;
-
-PVp.visit = function() {
- if (this._visiting) {
- throw new Error(
- "Recursively calling visitor.visit(path) resets visitor state. " +
- "Try this.visit(path) or this.traverse(path) instead."
- );
- }
- // Private state that needs to be reset before every traversal.
- this._visiting = true;
- this._changeReported = false;
- this._abortRequested = false;
+ function Visitor() {
+ if (!(this instanceof Visitor)) {
+ throw new Error(
+ "Visitor constructor cannot be invoked without 'new'"
+ );
+ }
+ PathVisitor.call(this);
+ }
- var argc = arguments.length;
- var args = new Array(argc)
- for (var i = 0; i < argc; ++i) {
- args[i] = arguments[i];
- }
+ var Vp = Visitor.prototype = Object.create(PVp);
+ Vp.constructor = Visitor;
- if (!(args[0] instanceof NodePath)) {
- args[0] = new NodePath({ root: args[0] }).get("root");
- }
+ extend(Vp, methods);
+ extend(Visitor, PathVisitor);
- // Called with the same arguments as .visit.
- this.reset.apply(this, args);
+ isFunction.assert(Visitor.fromMethodsObject);
+ isFunction.assert(Visitor.visit);
- try {
- var root = this.visitWithoutReset(args[0]);
- var didNotThrow = true;
- } finally {
- this._visiting = false;
+ return new Visitor;
+ };
- if (!didNotThrow && this._abortRequested) {
- // If this.visitWithoutReset threw an exception and
- // this._abortRequested was set to true, return the root of
- // the AST instead of letting the exception propagate, so that
- // client code does not have to provide a try-catch block to
- // intercept the AbortRequest exception. Other kinds of
- // exceptions will propagate without being intercepted and
- // rethrown by a catch block, so their stacks will accurately
- // reflect the original throwing context.
- return args[0].value;
+ function extend(target, source) {
+ for (var property in source) {
+ if (hasOwn.call(source, property)) {
+ target[property] = source[property];
+ }
}
- }
- return root;
-};
+ return target;
+ }
-PVp.AbortRequest = function AbortRequest() {};
-PVp.abort = function() {
- var visitor = this;
- visitor._abortRequested = true;
- var request = new visitor.AbortRequest();
-
- // If you decide to catch this exception and stop it from propagating,
- // make sure to call its cancel method to avoid silencing other
- // exceptions that might be thrown later in the traversal.
- request.cancel = function() {
- visitor._abortRequested = false;
+ PathVisitor.visit = function visit(node, methods) {
+ return PathVisitor.fromMethodsObject(methods).visit(node);
};
- throw request;
-};
+ var PVp = PathVisitor.prototype;
-PVp.reset = function(path/*, additional arguments */) {
- // Empty stub; may be reassigned or overridden by subclasses.
-};
+ PVp.visit = function () {
+ if (this._visiting) {
+ throw new Error(
+ "Recursively calling visitor.visit(path) resets visitor state. " +
+ "Try this.visit(path) or this.traverse(path) instead."
+ );
+ }
-PVp.visitWithoutReset = function(path) {
- if (this instanceof this.Context) {
- // Since this.Context.prototype === this, there's a chance we
- // might accidentally call context.visitWithoutReset. If that
- // happens, re-invoke the method against context.visitor.
- return this.visitor.visitWithoutReset(path);
- }
+ // Private state that needs to be reset before every traversal.
+ this._visiting = true;
+ this._changeReported = false;
+ this._abortRequested = false;
- if (!(path instanceof NodePath)) {
- throw new Error("");
- }
+ var argc = arguments.length;
+ var args = new Array(argc)
+ for (var i = 0; i < argc; ++i) {
+ args[i] = arguments[i];
+ }
- var value = path.value;
+ if (!(args[0] instanceof NodePath)) {
+ args[0] = new NodePath({root: args[0]}).get("root");
+ }
- var methodName = value &&
- typeof value === "object" &&
- typeof value.type === "string" &&
- this._methodNameTable[value.type];
+ // Called with the same arguments as .visit.
+ this.reset.apply(this, args);
- if (methodName) {
- var context = this.acquireContext(path);
try {
- return context.invokeVisitorMethod(methodName);
+ var root = this.visitWithoutReset(args[0]);
+ var didNotThrow = true;
} finally {
- this.releaseContext(context);
+ this._visiting = false;
+
+ if (!didNotThrow && this._abortRequested) {
+ // If this.visitWithoutReset threw an exception and
+ // this._abortRequested was set to true, return the root of
+ // the AST instead of letting the exception propagate, so that
+ // client code does not have to provide a try-catch block to
+ // intercept the AbortRequest exception. Other kinds of
+ // exceptions will propagate without being intercepted and
+ // rethrown by a catch block, so their stacks will accurately
+ // reflect the original throwing context.
+ return args[0].value;
+ }
}
- } else {
- // If there was no visitor method to call, visit the children of
- // this node generically.
- return visitChildren(path, this);
- }
-};
+ return root;
+ };
-function visitChildren(path, visitor) {
- if (!(path instanceof NodePath)) {
- throw new Error("");
- }
- if (!(visitor instanceof PathVisitor)) {
- throw new Error("");
- }
+ PVp.AbortRequest = function AbortRequest() {};
+ PVp.abort = function () {
+ var visitor = this;
+ visitor._abortRequested = true;
+ var request = new visitor.AbortRequest();
- var value = path.value;
-
- if (isArray.check(value)) {
- path.each(visitor.visitWithoutReset, visitor);
- } else if (!isObject.check(value)) {
- // No children to visit.
- } else {
- var childNames = types.getFieldNames(value);
-
- // The .comments field of the Node type is hidden, so we only
- // visit it if the visitor defines visitBlock or visitLine, and
- // value.comments is defined.
- if (visitor._shouldVisitComments &&
- value.comments &&
- childNames.indexOf("comments") < 0) {
- childNames.push("comments");
- }
+ // If you decide to catch this exception and stop it from propagating,
+ // make sure to call its cancel method to avoid silencing other
+ // exceptions that might be thrown later in the traversal.
+ request.cancel = function () {
+ visitor._abortRequested = false;
+ };
- var childCount = childNames.length;
- var childPaths = [];
+ throw request;
+ };
- for (var i = 0; i < childCount; ++i) {
- var childName = childNames[i];
- if (!hasOwn.call(value, childName)) {
- value[childName] = types.getFieldValue(value, childName);
- }
- childPaths.push(path.get(childName));
- }
+ PVp.reset = function (path/*, additional arguments */) {
+ // Empty stub; may be reassigned or overridden by subclasses.
+ };
- for (var i = 0; i < childCount; ++i) {
- visitor.visitWithoutReset(childPaths[i]);
+ PVp.visitWithoutReset = function (path) {
+ if (this instanceof this.Context) {
+ // Since this.Context.prototype === this, there's a chance we
+ // might accidentally call context.visitWithoutReset. If that
+ // happens, re-invoke the method against context.visitor.
+ return this.visitor.visitWithoutReset(path);
}
- }
-
- return path.value;
-}
-PVp.acquireContext = function(path) {
- if (this._reusableContextStack.length === 0) {
- return new this.Context(path);
- }
- return this._reusableContextStack.pop().reset(path);
-};
+ if (!(path instanceof NodePath)) {
+ throw new Error("");
+ }
-PVp.releaseContext = function(context) {
- if (!(context instanceof this.Context)) {
- throw new Error("");
- }
- this._reusableContextStack.push(context);
- context.currentPath = null;
-};
+ var value = path.value;
-PVp.reportChanged = function() {
- this._changeReported = true;
-};
+ var methodName = value &&
+ typeof value === "object" &&
+ typeof value.type === "string" &&
+ this._methodNameTable[value.type];
-PVp.wasChangeReported = function() {
- return this._changeReported;
-};
+ if (methodName) {
+ var context = this.acquireContext(path);
+ try {
+ return context.invokeVisitorMethod(methodName);
+ } finally {
+ this.releaseContext(context);
+ }
-function makeContextConstructor(visitor) {
- function Context(path) {
- if (!(this instanceof Context)) {
- throw new Error("");
+ } else {
+ // If there was no visitor method to call, visit the children of
+ // this node generically.
+ return visitChildren(path, this);
}
- if (!(this instanceof PathVisitor)) {
+ };
+
+ function visitChildren(path, visitor) {
+ if (!(path instanceof NodePath)) {
throw new Error("");
}
- if (!(path instanceof NodePath)) {
+ if (!(visitor instanceof PathVisitor)) {
throw new Error("");
}
- Object.defineProperty(this, "visitor", {
- value: visitor,
- writable: false,
- enumerable: true,
- configurable: false
- });
-
- this.currentPath = path;
- this.needToCallTraverse = true;
-
- Object.seal(this);
- }
-
- if (!(visitor instanceof PathVisitor)) {
- throw new Error("");
- }
-
- // Note that the visitor object is the prototype of Context.prototype,
- // so all visitor methods are inherited by context objects.
- var Cp = Context.prototype = Object.create(visitor);
+ var value = path.value;
+
+ if (isArray.check(value)) {
+ path.each(visitor.visitWithoutReset, visitor);
+ } else if (!isObject.check(value)) {
+ // No children to visit.
+ } else {
+ var childNames = types.getFieldNames(value);
+
+ // The .comments field of the Node type is hidden, so we only
+ // visit it if the visitor defines visitBlock or visitLine, and
+ // value.comments is defined.
+ if (visitor._shouldVisitComments &&
+ value.comments &&
+ childNames.indexOf("comments") < 0) {
+ childNames.push("comments");
+ }
- Cp.constructor = Context;
- extend(Cp, sharedContextProtoMethods);
+ var childCount = childNames.length;
+ var childPaths = [];
- return Context;
-}
+ for (var i = 0; i < childCount; ++i) {
+ var childName = childNames[i];
+ if (!hasOwn.call(value, childName)) {
+ value[childName] = types.getFieldValue(value, childName);
+ }
+ childPaths.push(path.get(childName));
+ }
-// Every PathVisitor has a different this.Context constructor and
-// this.Context.prototype object, but those prototypes can all use the
-// same reset, invokeVisitorMethod, and traverse function objects.
-var sharedContextProtoMethods = Object.create(null);
+ for (var i = 0; i < childCount; ++i) {
+ visitor.visitWithoutReset(childPaths[i]);
+ }
+ }
-sharedContextProtoMethods.reset =
-function reset(path) {
- if (!(this instanceof this.Context)) {
- throw new Error("");
- }
- if (!(path instanceof NodePath)) {
- throw new Error("");
+ return path.value;
}
- this.currentPath = path;
- this.needToCallTraverse = true;
-
- return this;
-};
+ PVp.acquireContext = function (path) {
+ if (this._reusableContextStack.length === 0) {
+ return new this.Context(path);
+ }
+ return this._reusableContextStack.pop().reset(path);
+ };
-sharedContextProtoMethods.invokeVisitorMethod =
-function invokeVisitorMethod(methodName) {
- if (!(this instanceof this.Context)) {
- throw new Error("");
- }
- if (!(this.currentPath instanceof NodePath)) {
- throw new Error("");
- }
+ PVp.releaseContext = function (context) {
+ if (!(context instanceof this.Context)) {
+ throw new Error("");
+ }
+ this._reusableContextStack.push(context);
+ context.currentPath = null;
+ };
- var result = this.visitor[methodName].call(this, this.currentPath);
+ PVp.reportChanged = function () {
+ this._changeReported = true;
+ };
- if (result === false) {
- // Visitor methods return false to indicate that they have handled
- // their own traversal needs, and we should not complain if
- // this.needToCallTraverse is still true.
- this.needToCallTraverse = false;
+ PVp.wasChangeReported = function () {
+ return this._changeReported;
+ };
- } else if (result !== undefined) {
- // Any other non-undefined value returned from the visitor method
- // is interpreted as a replacement value.
- this.currentPath = this.currentPath.replace(result)[0];
+ function makeContextConstructor(visitor) {
+ function Context(path) {
+ if (!(this instanceof Context)) {
+ throw new Error("");
+ }
+ if (!(this instanceof PathVisitor)) {
+ throw new Error("");
+ }
+ if (!(path instanceof NodePath)) {
+ throw new Error("");
+ }
- if (this.needToCallTraverse) {
- // If this.traverse still hasn't been called, visit the
- // children of the replacement node.
- this.traverse(this.currentPath);
- }
- }
+ Object.defineProperty(this, "visitor", {
+ value: visitor,
+ writable: false,
+ enumerable: true,
+ configurable: false
+ });
- if (this.needToCallTraverse !== false) {
- throw new Error(
- "Must either call this.traverse or return false in " + methodName
- );
- }
+ this.currentPath = path;
+ this.needToCallTraverse = true;
- var path = this.currentPath;
- return path && path.value;
-};
+ Object.seal(this);
+ }
-sharedContextProtoMethods.traverse =
-function traverse(path, newVisitor) {
- if (!(this instanceof this.Context)) {
- throw new Error("");
- }
- if (!(path instanceof NodePath)) {
- throw new Error("");
- }
- if (!(this.currentPath instanceof NodePath)) {
- throw new Error("");
- }
+ if (!(visitor instanceof PathVisitor)) {
+ throw new Error("");
+ }
- this.needToCallTraverse = false;
+ // Note that the visitor object is the prototype of Context.prototype,
+ // so all visitor methods are inherited by context objects.
+ var Cp = Context.prototype = Object.create(visitor);
- return visitChildren(path, PathVisitor.fromMethodsObject(
- newVisitor || this.visitor
- ));
-};
+ Cp.constructor = Context;
+ extend(Cp, sharedContextProtoMethods);
-sharedContextProtoMethods.visit =
-function visit(path, newVisitor) {
- if (!(this instanceof this.Context)) {
- throw new Error("");
- }
- if (!(path instanceof NodePath)) {
- throw new Error("");
- }
- if (!(this.currentPath instanceof NodePath)) {
- throw new Error("");
+ return Context;
}
- this.needToCallTraverse = false;
-
- return PathVisitor.fromMethodsObject(
- newVisitor || this.visitor
- ).visitWithoutReset(path);
-};
+// Every PathVisitor has a different this.Context constructor and
+// this.Context.prototype object, but those prototypes can all use the
+// same reset, invokeVisitorMethod, and traverse function objects.
+ var sharedContextProtoMethods = Object.create(null);
+
+ sharedContextProtoMethods.reset =
+ function reset(path) {
+ if (!(this instanceof this.Context)) {
+ throw new Error("");
+ }
+ if (!(path instanceof NodePath)) {
+ throw new Error("");
+ }
+
+ this.currentPath = path;
+ this.needToCallTraverse = true;
+
+ return this;
+ };
+
+ sharedContextProtoMethods.invokeVisitorMethod =
+ function invokeVisitorMethod(methodName) {
+ if (!(this instanceof this.Context)) {
+ throw new Error("");
+ }
+ if (!(this.currentPath instanceof NodePath)) {
+ throw new Error("");
+ }
+
+ var result = this.visitor[methodName].call(this, this.currentPath);
+
+ if (result === false) {
+ // Visitor methods return false to indicate that they have handled
+ // their own traversal needs, and we should not complain if
+ // this.needToCallTraverse is still true.
+ this.needToCallTraverse = false;
+
+ } else if (result !== undefined) {
+ // Any other non-undefined value returned from the visitor method
+ // is interpreted as a replacement value.
+ this.currentPath = this.currentPath.replace(result)[0];
+
+ if (this.needToCallTraverse) {
+ // If this.traverse still hasn't been called, visit the
+ // children of the replacement node.
+ this.traverse(this.currentPath);
+ }
+ }
+
+ if (this.needToCallTraverse !== false) {
+ throw new Error(
+ "Must either call this.traverse or return false in " + methodName
+ );
+ }
+
+ var path = this.currentPath;
+ return path && path.value;
+ };
+
+ sharedContextProtoMethods.traverse =
+ function traverse(path, newVisitor) {
+ if (!(this instanceof this.Context)) {
+ throw new Error("");
+ }
+ if (!(path instanceof NodePath)) {
+ throw new Error("");
+ }
+ if (!(this.currentPath instanceof NodePath)) {
+ throw new Error("");
+ }
+
+ this.needToCallTraverse = false;
+
+ return visitChildren(path, PathVisitor.fromMethodsObject(
+ newVisitor || this.visitor
+ ));
+ };
+
+ sharedContextProtoMethods.visit =
+ function visit(path, newVisitor) {
+ if (!(this instanceof this.Context)) {
+ throw new Error("");
+ }
+ if (!(path instanceof NodePath)) {
+ throw new Error("");
+ }
+ if (!(this.currentPath instanceof NodePath)) {
+ throw new Error("");
+ }
+
+ this.needToCallTraverse = false;
+
+ return PathVisitor.fromMethodsObject(
+ newVisitor || this.visitor
+ ).visitWithoutReset(path);
+ };
+
+ sharedContextProtoMethods.reportChanged = function reportChanged() {
+ this.visitor.reportChanged();
+ };
-sharedContextProtoMethods.reportChanged = function reportChanged() {
- this.visitor.reportChanged();
-};
+ sharedContextProtoMethods.abort = function abort() {
+ this.needToCallTraverse = false;
+ this.visitor.abort();
+ };
-sharedContextProtoMethods.abort = function abort() {
- this.needToCallTraverse = false;
- this.visitor.abort();
+ return PathVisitor;
};
-
-module.exports = PathVisitor;
diff --git a/lib/path.js b/lib/path.js
index 9601e88..6dbb099 100644
--- a/lib/path.js
+++ b/lib/path.js
@@ -1,366 +1,369 @@
-var Op = Object.prototype;
-var hasOwn = Op.hasOwnProperty;
-var types = require("./types");
-var isArray = types.builtInTypes.array;
-var isNumber = types.builtInTypes.number;
var Ap = Array.prototype;
var slice = Ap.slice;
var map = Ap.map;
+var Op = Object.prototype;
+var hasOwn = Op.hasOwnProperty;
-function Path(value, parentPath, name) {
- if (!(this instanceof Path)) {
- throw new Error("Path constructor cannot be invoked without 'new'");
- }
+module.exports = function (fork) {
+ var types = fork.use(require("./types"));
+ var isArray = types.builtInTypes.array;
+ var isNumber = types.builtInTypes.number;
- if (parentPath) {
- if (!(parentPath instanceof Path)) {
- throw new Error("");
+ function Path(value, parentPath, name) {
+ if (!(this instanceof Path)) {
+ throw new Error("Path constructor cannot be invoked without 'new'");
}
- } else {
- parentPath = null;
- name = null;
- }
- // The value encapsulated by this Path, generally equal to
- // parentPath.value[name] if we have a parentPath.
- this.value = value;
-
- // The immediate parent Path of this Path.
- this.parentPath = parentPath;
-
- // The name of the property of parentPath.value through which this
- // Path's value was reached.
- this.name = name;
-
- // Calling path.get("child") multiple times always returns the same
- // child Path object, for both performance and consistency reasons.
- this.__childCache = null;
-}
-
-var Pp = Path.prototype;
-
-function getChildCache(path) {
- // Lazily create the child cache. This also cheapens cache
- // invalidation, since you can just reset path.__childCache to null.
- return path.__childCache || (path.__childCache = Object.create(null));
-}
-
-function getChildPath(path, name) {
- var cache = getChildCache(path);
- var actualChildValue = path.getValueProperty(name);
- var childPath = cache[name];
- if (!hasOwn.call(cache, name) ||
- // Ensure consistency between cache and reality.
- childPath.value !== actualChildValue) {
- childPath = cache[name] = new path.constructor(
- actualChildValue, path, name
- );
- }
- return childPath;
-}
+ if (parentPath) {
+ if (!(parentPath instanceof Path)) {
+ throw new Error("");
+ }
+ } else {
+ parentPath = null;
+ name = null;
+ }
-// This method is designed to be overridden by subclasses that need to
-// handle missing properties, etc.
-Pp.getValueProperty = function getValueProperty(name) {
- return this.value[name];
-};
+ // The value encapsulated by this Path, generally equal to
+ // parentPath.value[name] if we have a parentPath.
+ this.value = value;
-Pp.get = function get(name) {
- var path = this;
- var names = arguments;
- var count = names.length;
+ // The immediate parent Path of this Path.
+ this.parentPath = parentPath;
- for (var i = 0; i < count; ++i) {
- path = getChildPath(path, names[i]);
- }
+ // The name of the property of parentPath.value through which this
+ // Path's value was reached.
+ this.name = name;
- return path;
-};
+ // Calling path.get("child") multiple times always returns the same
+ // child Path object, for both performance and consistency reasons.
+ this.__childCache = null;
+ }
-Pp.each = function each(callback, context) {
- var childPaths = [];
- var len = this.value.length;
- var i = 0;
+ var Pp = Path.prototype;
- // Collect all the original child paths before invoking the callback.
- for (var i = 0; i < len; ++i) {
- if (hasOwn.call(this.value, i)) {
- childPaths[i] = this.get(i);
- }
+ function getChildCache(path) {
+ // Lazily create the child cache. This also cheapens cache
+ // invalidation, since you can just reset path.__childCache to null.
+ return path.__childCache || (path.__childCache = Object.create(null));
}
- // Invoke the callback on just the original child paths, regardless of
- // any modifications made to the array by the callback. I chose these
- // semantics over cleverly invoking the callback on new elements because
- // this way is much easier to reason about.
- context = context || this;
- for (i = 0; i < len; ++i) {
- if (hasOwn.call(childPaths, i)) {
- callback.call(context, childPaths[i]);
+ function getChildPath(path, name) {
+ var cache = getChildCache(path);
+ var actualChildValue = path.getValueProperty(name);
+ var childPath = cache[name];
+ if (!hasOwn.call(cache, name) ||
+ // Ensure consistency between cache and reality.
+ childPath.value !== actualChildValue) {
+ childPath = cache[name] = new path.constructor(
+ actualChildValue, path, name
+ );
}
+ return childPath;
}
-};
-
-Pp.map = function map(callback, context) {
- var result = [];
- this.each(function(childPath) {
- result.push(callback.call(this, childPath));
- }, context);
-
- return result;
-};
+// This method is designed to be overridden by subclasses that need to
+// handle missing properties, etc.
+ Pp.getValueProperty = function getValueProperty(name) {
+ return this.value[name];
+ };
-Pp.filter = function filter(callback, context) {
- var result = [];
+ Pp.get = function get(name) {
+ var path = this;
+ var names = arguments;
+ var count = names.length;
- this.each(function(childPath) {
- if (callback.call(this, childPath)) {
- result.push(childPath);
+ for (var i = 0; i < count; ++i) {
+ path = getChildPath(path, names[i]);
}
- }, context);
- return result;
-};
-
-function emptyMoves() {}
-function getMoves(path, offset, start, end) {
- isArray.assert(path.value);
+ return path;
+ };
- if (offset === 0) {
- return emptyMoves;
- }
+ Pp.each = function each(callback, context) {
+ var childPaths = [];
+ var len = this.value.length;
+ var i = 0;
- var length = path.value.length;
- if (length < 1) {
- return emptyMoves;
- }
+ // Collect all the original child paths before invoking the callback.
+ for (var i = 0; i < len; ++i) {
+ if (hasOwn.call(this.value, i)) {
+ childPaths[i] = this.get(i);
+ }
+ }
- var argc = arguments.length;
- if (argc === 2) {
- start = 0;
- end = length;
- } else if (argc === 3) {
- start = Math.max(start, 0);
- end = length;
- } else {
- start = Math.max(start, 0);
- end = Math.min(end, length);
- }
+ // Invoke the callback on just the original child paths, regardless of
+ // any modifications made to the array by the callback. I chose these
+ // semantics over cleverly invoking the callback on new elements because
+ // this way is much easier to reason about.
+ context = context || this;
+ for (i = 0; i < len; ++i) {
+ if (hasOwn.call(childPaths, i)) {
+ callback.call(context, childPaths[i]);
+ }
+ }
+ };
- isNumber.assert(start);
- isNumber.assert(end);
+ Pp.map = function map(callback, context) {
+ var result = [];
- var moves = Object.create(null);
- var cache = getChildCache(path);
+ this.each(function (childPath) {
+ result.push(callback.call(this, childPath));
+ }, context);
- for (var i = start; i < end; ++i) {
- if (hasOwn.call(path.value, i)) {
- var childPath = path.get(i);
- if (childPath.name !== i) {
- throw new Error("");
- }
- var newIndex = i + offset;
- childPath.name = newIndex;
- moves[newIndex] = childPath;
- delete cache[i];
- }
- }
+ return result;
+ };
- delete cache.length;
+ Pp.filter = function filter(callback, context) {
+ var result = [];
- return function() {
- for (var newIndex in moves) {
- var childPath = moves[newIndex];
- if (childPath.name !== +newIndex) {
- throw new Error("");
+ this.each(function (childPath) {
+ if (callback.call(this, childPath)) {
+ result.push(childPath);
}
- cache[newIndex] = childPath;
- path.value[newIndex] = childPath.value;
- }
+ }, context);
+
+ return result;
};
-}
-Pp.shift = function shift() {
- var move = getMoves(this, -1);
- var result = this.value.shift();
- move();
- return result;
-};
+ function emptyMoves() {}
+ function getMoves(path, offset, start, end) {
+ isArray.assert(path.value);
-Pp.unshift = function unshift(node) {
- var move = getMoves(this, arguments.length);
- var result = this.value.unshift.apply(this.value, arguments);
- move();
- return result;
-};
+ if (offset === 0) {
+ return emptyMoves;
+ }
-Pp.push = function push(node) {
- isArray.assert(this.value);
- delete getChildCache(this).length
- return this.value.push.apply(this.value, arguments);
-};
+ var length = path.value.length;
+ if (length < 1) {
+ return emptyMoves;
+ }
-Pp.pop = function pop() {
- isArray.assert(this.value);
- var cache = getChildCache(this);
- delete cache[this.value.length - 1];
- delete cache.length;
- return this.value.pop();
-};
+ var argc = arguments.length;
+ if (argc === 2) {
+ start = 0;
+ end = length;
+ } else if (argc === 3) {
+ start = Math.max(start, 0);
+ end = length;
+ } else {
+ start = Math.max(start, 0);
+ end = Math.min(end, length);
+ }
-Pp.insertAt = function insertAt(index, node) {
- var argc = arguments.length;
- var move = getMoves(this, argc - 1, index);
- if (move === emptyMoves) {
- return this;
- }
+ isNumber.assert(start);
+ isNumber.assert(end);
+
+ var moves = Object.create(null);
+ var cache = getChildCache(path);
+
+ for (var i = start; i < end; ++i) {
+ if (hasOwn.call(path.value, i)) {
+ var childPath = path.get(i);
+ if (childPath.name !== i) {
+ throw new Error("");
+ }
+ var newIndex = i + offset;
+ childPath.name = newIndex;
+ moves[newIndex] = childPath;
+ delete cache[i];
+ }
+ }
- index = Math.max(index, 0);
+ delete cache.length;
- for (var i = 1; i < argc; ++i) {
- this.value[index + i - 1] = arguments[i];
+ return function () {
+ for (var newIndex in moves) {
+ var childPath = moves[newIndex];
+ if (childPath.name !== +newIndex) {
+ throw new Error("");
+ }
+ cache[newIndex] = childPath;
+ path.value[newIndex] = childPath.value;
+ }
+ };
}
- move();
+ Pp.shift = function shift() {
+ var move = getMoves(this, -1);
+ var result = this.value.shift();
+ move();
+ return result;
+ };
- return this;
-};
+ Pp.unshift = function unshift(node) {
+ var move = getMoves(this, arguments.length);
+ var result = this.value.unshift.apply(this.value, arguments);
+ move();
+ return result;
+ };
-Pp.insertBefore = function insertBefore(node) {
- var pp = this.parentPath;
- var argc = arguments.length;
- var insertAtArgs = [this.name];
- for (var i = 0; i < argc; ++i) {
- insertAtArgs.push(arguments[i]);
- }
- return pp.insertAt.apply(pp, insertAtArgs);
-};
+ Pp.push = function push(node) {
+ isArray.assert(this.value);
+ delete getChildCache(this).length
+ return this.value.push.apply(this.value, arguments);
+ };
-Pp.insertAfter = function insertAfter(node) {
- var pp = this.parentPath;
- var argc = arguments.length;
- var insertAtArgs = [this.name + 1];
- for (var i = 0; i < argc; ++i) {
- insertAtArgs.push(arguments[i]);
- }
- return pp.insertAt.apply(pp, insertAtArgs);
-};
+ Pp.pop = function pop() {
+ isArray.assert(this.value);
+ var cache = getChildCache(this);
+ delete cache[this.value.length - 1];
+ delete cache.length;
+ return this.value.pop();
+ };
-function repairRelationshipWithParent(path) {
- if (!(path instanceof Path)) {
- throw new Error("");
- }
+ Pp.insertAt = function insertAt(index, node) {
+ var argc = arguments.length;
+ var move = getMoves(this, argc - 1, index);
+ if (move === emptyMoves) {
+ return this;
+ }
- var pp = path.parentPath;
- if (!pp) {
- // Orphan paths have no relationship to repair.
- return path;
- }
+ index = Math.max(index, 0);
- var parentValue = pp.value;
- var parentCache = getChildCache(pp);
-
- // Make sure parentCache[path.name] is populated.
- if (parentValue[path.name] === path.value) {
- parentCache[path.name] = path;
- } else if (isArray.check(parentValue)) {
- // Something caused path.name to become out of date, so attempt to
- // recover by searching for path.value in parentValue.
- var i = parentValue.indexOf(path.value);
- if (i >= 0) {
- parentCache[path.name = i] = path;
+ for (var i = 1; i < argc; ++i) {
+ this.value[index + i - 1] = arguments[i];
}
- } else {
- // If path.value disagrees with parentValue[path.name], and
- // path.name is not an array index, let path.value become the new
- // parentValue[path.name] and update parentCache accordingly.
- parentValue[path.name] = path.value;
- parentCache[path.name] = path;
- }
- if (parentValue[path.name] !== path.value) {
- throw new Error("");
- }
- if (path.parentPath.get(path.name) !== path) {
- throw new Error("");
- }
+ move();
- return path;
-}
+ return this;
+ };
-Pp.replace = function replace(replacement) {
- var results = [];
- var parentValue = this.parentPath.value;
- var parentCache = getChildCache(this.parentPath);
- var count = arguments.length;
+ Pp.insertBefore = function insertBefore(node) {
+ var pp = this.parentPath;
+ var argc = arguments.length;
+ var insertAtArgs = [this.name];
+ for (var i = 0; i < argc; ++i) {
+ insertAtArgs.push(arguments[i]);
+ }
+ return pp.insertAt.apply(pp, insertAtArgs);
+ };
- repairRelationshipWithParent(this);
+ Pp.insertAfter = function insertAfter(node) {
+ var pp = this.parentPath;
+ var argc = arguments.length;
+ var insertAtArgs = [this.name + 1];
+ for (var i = 0; i < argc; ++i) {
+ insertAtArgs.push(arguments[i]);
+ }
+ return pp.insertAt.apply(pp, insertAtArgs);
+ };
- if (isArray.check(parentValue)) {
- var originalLength = parentValue.length;
- var move = getMoves(this.parentPath, count - 1, this.name + 1);
+ function repairRelationshipWithParent(path) {
+ if (!(path instanceof Path)) {
+ throw new Error("");
+ }
- var spliceArgs = [this.name, 1];
- for (var i = 0; i < count; ++i) {
- spliceArgs.push(arguments[i]);
+ var pp = path.parentPath;
+ if (!pp) {
+ // Orphan paths have no relationship to repair.
+ return path;
}
- var splicedOut = parentValue.splice.apply(parentValue, spliceArgs);
+ var parentValue = pp.value;
+ var parentCache = getChildCache(pp);
+
+ // Make sure parentCache[path.name] is populated.
+ if (parentValue[path.name] === path.value) {
+ parentCache[path.name] = path;
+ } else if (isArray.check(parentValue)) {
+ // Something caused path.name to become out of date, so attempt to
+ // recover by searching for path.value in parentValue.
+ var i = parentValue.indexOf(path.value);
+ if (i >= 0) {
+ parentCache[path.name = i] = path;
+ }
+ } else {
+ // If path.value disagrees with parentValue[path.name], and
+ // path.name is not an array index, let path.value become the new
+ // parentValue[path.name] and update parentCache accordingly.
+ parentValue[path.name] = path.value;
+ parentCache[path.name] = path;
+ }
- if (splicedOut[0] !== this.value) {
+ if (parentValue[path.name] !== path.value) {
throw new Error("");
}
- if (parentValue.length !== (originalLength - 1 + count)) {
+ if (path.parentPath.get(path.name) !== path) {
throw new Error("");
}
- move();
+ return path;
+ }
- if (count === 0) {
- delete this.value;
- delete parentCache[this.name];
- this.__childCache = null;
+ Pp.replace = function replace(replacement) {
+ var results = [];
+ var parentValue = this.parentPath.value;
+ var parentCache = getChildCache(this.parentPath);
+ var count = arguments.length;
- } else {
- if (parentValue[this.name] !== replacement) {
+ repairRelationshipWithParent(this);
+
+ if (isArray.check(parentValue)) {
+ var originalLength = parentValue.length;
+ var move = getMoves(this.parentPath, count - 1, this.name + 1);
+
+ var spliceArgs = [this.name, 1];
+ for (var i = 0; i < count; ++i) {
+ spliceArgs.push(arguments[i]);
+ }
+
+ var splicedOut = parentValue.splice.apply(parentValue, spliceArgs);
+
+ if (splicedOut[0] !== this.value) {
+ throw new Error("");
+ }
+ if (parentValue.length !== (originalLength - 1 + count)) {
throw new Error("");
}
- if (this.value !== replacement) {
- this.value = replacement;
+ move();
+
+ if (count === 0) {
+ delete this.value;
+ delete parentCache[this.name];
this.__childCache = null;
- }
- for (i = 0; i < count; ++i) {
- results.push(this.parentPath.get(this.name + i));
+ } else {
+ if (parentValue[this.name] !== replacement) {
+ throw new Error("");
+ }
+
+ if (this.value !== replacement) {
+ this.value = replacement;
+ this.__childCache = null;
+ }
+
+ for (i = 0; i < count; ++i) {
+ results.push(this.parentPath.get(this.name + i));
+ }
+
+ if (results[0] !== this) {
+ throw new Error("");
+ }
}
- if (results[0] !== this) {
- throw new Error("");
+ } else if (count === 1) {
+ if (this.value !== replacement) {
+ this.__childCache = null;
}
- }
+ this.value = parentValue[this.name] = replacement;
+ results.push(this);
- } else if (count === 1) {
- if (this.value !== replacement) {
+ } else if (count === 0) {
+ delete parentValue[this.name];
+ delete this.value;
this.__childCache = null;
- }
- this.value = parentValue[this.name] = replacement;
- results.push(this);
- } else if (count === 0) {
- delete parentValue[this.name];
- delete this.value;
- this.__childCache = null;
+ // Leave this path cached as parentCache[this.name], even though
+ // it no longer has a value defined.
- // Leave this path cached as parentCache[this.name], even though
- // it no longer has a value defined.
+ } else {
+ throw new Error("Could not replace path");
+ }
- } else {
- throw new Error("Could not replace path");
- }
+ return results;
+ };
- return results;
+ return Path;
};
-
-module.exports = Path;
diff --git a/lib/scope.js b/lib/scope.js
index f4c7b9d..1f98fb4 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -1,330 +1,350 @@
-var types = require("./types");
-var Type = types.Type;
-var namedTypes = types.namedTypes;
-var Node = namedTypes.Node;
-var Expression = namedTypes.Expression;
-var isArray = types.builtInTypes.array;
var hasOwn = Object.prototype.hasOwnProperty;
-var b = types.builders;
-function Scope(path, parentScope) {
- if (!(this instanceof Scope)) {
- throw new Error("Scope constructor cannot be invoked without 'new'");
- }
- if (!(path instanceof require("./node-path"))) {
- throw new Error("");
- }
- ScopeType.assert(path.value);
+module.exports = function (fork) {
+ var types = fork.use(require("./types"));
+ var Type = types.Type;
+ var namedTypes = types.namedTypes;
+ var Node = namedTypes.Node;
+ var Expression = namedTypes.Expression;
+ var isArray = types.builtInTypes.array;
+ var b = types.builders;
+
+ function Scope(path, parentScope) {
+ if (!(this instanceof Scope)) {
+ throw new Error("Scope constructor cannot be invoked without 'new'");
+ }
+ if (!(path instanceof fork.use(require("./node-path")))) {
+ throw new Error("");
+ }
+ ScopeType.assert(path.value);
- var depth;
+ var depth;
- if (parentScope) {
- if (!(parentScope instanceof Scope)) {
- throw new Error("");
+ if (parentScope) {
+ if (!(parentScope instanceof Scope)) {
+ throw new Error("");
+ }
+ depth = parentScope.depth + 1;
+ } else {
+ parentScope = null;
+ depth = 0;
}
- depth = parentScope.depth + 1;
- } else {
- parentScope = null;
- depth = 0;
+
+ Object.defineProperties(this, {
+ path: { value: path },
+ node: { value: path.value },
+ isGlobal: { value: !parentScope, enumerable: true },
+ depth: { value: depth },
+ parent: { value: parentScope },
+ bindings: { value: {} },
+ types: { value: {} },
+ });
}
- Object.defineProperties(this, {
- path: { value: path },
- node: { value: path.value },
- isGlobal: { value: !parentScope, enumerable: true },
- depth: { value: depth },
- parent: { value: parentScope },
- bindings: { value: {} },
- types: { value: {} },
- });
-}
-
-var scopeTypes = [
- // Program nodes introduce global scopes.
- namedTypes.Program,
-
- // Function is the supertype of FunctionExpression,
- // FunctionDeclaration, ArrowExpression, etc.
- namedTypes.Function,
-
- // In case you didn't know, the caught parameter shadows any variable
- // of the same name in an outer scope.
- namedTypes.CatchClause
-];
-
-var ScopeType = Type.or.apply(Type, scopeTypes);
-
-Scope.isEstablishedBy = function(node) {
- return ScopeType.check(node);
-};
+ var scopeTypes = [
+ // Program nodes introduce global scopes.
+ namedTypes.Program,
+
+ // Function is the supertype of FunctionExpression,
+ // FunctionDeclaration, ArrowExpression, etc.
+ namedTypes.Function,
+
+ // In case you didn't know, the caught parameter shadows any variable
+ // of the same name in an outer scope.
+ namedTypes.CatchClause
+ ];
-var Sp = Scope.prototype;
+ var ScopeType = Type.or.apply(Type, scopeTypes);
+
+ Scope.isEstablishedBy = function(node) {
+ return ScopeType.check(node);
+ };
+
+ var Sp = Scope.prototype;
// Will be overridden after an instance lazily calls scanScope.
-Sp.didScan = false;
+ Sp.didScan = false;
-Sp.declares = function(name) {
- this.scan();
- return hasOwn.call(this.bindings, name);
-};
+ Sp.declares = function(name) {
+ this.scan();
+ return hasOwn.call(this.bindings, name);
+ };
-Sp.declaresType = function(name) {
- this.scan();
- return hasOwn.call(this.types, name);
-};
+ Sp.declaresType = function(name) {
+ this.scan();
+ return hasOwn.call(this.types, name);
+ };
-Sp.declareTemporary = function(prefix) {
- if (prefix) {
- if (!/^[a-z$_]/i.test(prefix)) {
- throw new Error("");
+ Sp.declareTemporary = function(prefix) {
+ if (prefix) {
+ if (!/^[a-z$_]/i.test(prefix)) {
+ throw new Error("");
+ }
+ } else {
+ prefix = "t$";
}
- } else {
- prefix = "t$";
- }
- // Include this.depth in the name to make sure the name does not
- // collide with any variables in nested/enclosing scopes.
- prefix += this.depth.toString(36) + "$";
+ // Include this.depth in the name to make sure the name does not
+ // collide with any variables in nested/enclosing scopes.
+ prefix += this.depth.toString(36) + "$";
- this.scan();
+ this.scan();
- var index = 0;
- while (this.declares(prefix + index)) {
- ++index;
- }
+ var index = 0;
+ while (this.declares(prefix + index)) {
+ ++index;
+ }
- var name = prefix + index;
- return this.bindings[name] = types.builders.identifier(name);
-};
+ var name = prefix + index;
+ return this.bindings[name] = types.builders.identifier(name);
+ };
-Sp.injectTemporary = function(identifier, init) {
- identifier || (identifier = this.declareTemporary());
+ Sp.injectTemporary = function(identifier, init) {
+ identifier || (identifier = this.declareTemporary());
- var bodyPath = this.path.get("body");
- if (namedTypes.BlockStatement.check(bodyPath.value)) {
- bodyPath = bodyPath.get("body");
- }
+ var bodyPath = this.path.get("body");
+ if (namedTypes.BlockStatement.check(bodyPath.value)) {
+ bodyPath = bodyPath.get("body");
+ }
- bodyPath.unshift(
- b.variableDeclaration(
+ bodyPath.unshift(
+ b.variableDeclaration(
"var",
[b.variableDeclarator(identifier, init || null)]
- )
- );
+ )
+ );
- return identifier;
-};
+ return identifier;
+ };
-Sp.scan = function(force) {
- if (force || !this.didScan) {
- for (var name in this.bindings) {
- // Empty out this.bindings, just in cases.
- delete this.bindings[name];
+ Sp.scan = function(force) {
+ if (force || !this.didScan) {
+ for (var name in this.bindings) {
+ // Empty out this.bindings, just in cases.
+ delete this.bindings[name];
+ }
+ scanScope(this.path, this.bindings, this.types);
+ this.didScan = true;
}
- scanScope(this.path, this.bindings, this.types);
- this.didScan = true;
- }
-};
+ };
-Sp.getBindings = function () {
- this.scan();
- return this.bindings;
-};
+ Sp.getBindings = function () {
+ this.scan();
+ return this.bindings;
+ };
-Sp.getTypes = function () {
- this.scan();
- return this.types;
-};
+ Sp.getTypes = function () {
+ this.scan();
+ return this.types;
+ };
-function scanScope(path, bindings, scopeTypes) {
- var node = path.value;
- ScopeType.assert(node);
+ function scanScope(path, bindings, scopeTypes) {
+ var node = path.value;
+ ScopeType.assert(node);
- if (namedTypes.CatchClause.check(node)) {
- // A catch clause establishes a new scope but the only variable
- // bound in that scope is the catch parameter. Any other
- // declarations create bindings in the outer scope.
- addPattern(path.get("param"), bindings);
+ if (namedTypes.CatchClause.check(node)) {
+ // A catch clause establishes a new scope but the only variable
+ // bound in that scope is the catch parameter. Any other
+ // declarations create bindings in the outer scope.
+ addPattern(path.get("param"), bindings);
- } else {
- recursiveScanScope(path, bindings, scopeTypes);
+ } else {
+ recursiveScanScope(path, bindings, scopeTypes);
+ }
}
-}
-function recursiveScanScope(path, bindings, scopeTypes) {
- var node = path.value;
+ function recursiveScanScope(path, bindings, scopeTypes) {
+ var node = path.value;
- if (path.parent &&
- namedTypes.FunctionExpression.check(path.parent.node) &&
- path.parent.node.id) {
- addPattern(path.parent.get("id"), bindings);
- }
-
- if (!node) {
- // None of the remaining cases matter if node is falsy.
+ if (path.parent &&
+ namedTypes.FunctionExpression.check(path.parent.node) &&
+ path.parent.node.id) {
+ addPattern(path.parent.get("id"), bindings);
+ }
- } else if (isArray.check(node)) {
- path.each(function(childPath) {
- recursiveScanChild(childPath, bindings, scopeTypes);
- });
+ if (!node) {
+ // None of the remaining cases matter if node is falsy.
+
+ } else if (isArray.check(node)) {
+ path.each(function(childPath) {
+ recursiveScanChild(childPath, bindings, scopeTypes);
+ });
+
+ } else if (namedTypes.Function.check(node)) {
+ path.get("params").each(function(paramPath) {
+ addPattern(paramPath, bindings);
+ });
+
+ recursiveScanChild(path.get("body"), bindings, scopeTypes);
+
+ } else if (namedTypes.TypeAlias && namedTypes.TypeAlias.check(node)) {
+ addTypePattern(path.get("id"), scopeTypes);
+
+ } else if (namedTypes.VariableDeclarator.check(node)) {
+ addPattern(path.get("id"), bindings);
+ recursiveScanChild(path.get("init"), bindings, scopeTypes);
+
+ } else if (node.type === "ImportSpecifier" ||
+ node.type === "ImportNamespaceSpecifier" ||
+ node.type === "ImportDefaultSpecifier") {
+ addPattern(
+ // Esprima used to use the .name field to refer to the local
+ // binding identifier for ImportSpecifier nodes, but .id for
+ // ImportNamespaceSpecifier and ImportDefaultSpecifier nodes.
+ // ESTree/Acorn/ESpree use .local for all three node types.
+ path.get(node.local ? "local" :
+ node.name ? "name" : "id"),
+ bindings
+ );
+
+ } else if (Node.check(node) && !Expression.check(node)) {
+ types.eachField(node, function(name, child) {
+ var childPath = path.get(name);
+ if (!pathHasValue(childPath, child)) {
+ throw new Error("");
+ }
+ recursiveScanChild(childPath, bindings, scopeTypes);
+ });
+ }
+ }
- } else if (namedTypes.Function.check(node)) {
- path.get("params").each(function(paramPath) {
- addPattern(paramPath, bindings);
- });
+ function pathHasValue(path, value) {
+ if (path.value === value) {
+ return true;
+ }
- recursiveScanChild(path.get("body"), bindings, scopeTypes);
-
- } else if (namedTypes.TypeAlias && namedTypes.TypeAlias.check(node)) {
- addTypePattern(path.get("id"), scopeTypes);
-
- } else if (namedTypes.VariableDeclarator.check(node)) {
- addPattern(path.get("id"), bindings);
- recursiveScanChild(path.get("init"), bindings, scopeTypes);
-
- } else if (node.type === "ImportSpecifier" ||
- node.type === "ImportNamespaceSpecifier" ||
- node.type === "ImportDefaultSpecifier") {
- addPattern(
- // Esprima used to use the .name field to refer to the local
- // binding identifier for ImportSpecifier nodes, but .id for
- // ImportNamespaceSpecifier and ImportDefaultSpecifier nodes.
- // ESTree/Acorn/ESpree use .local for all three node types.
- path.get(node.local ? "local" :
- node.name ? "name" : "id"),
- bindings
- );
+ // Empty arrays are probably produced by defaults.emptyArray, in which
+ // case is makes sense to regard them as equivalent, if not ===.
+ if (Array.isArray(path.value) &&
+ path.value.length === 0 &&
+ Array.isArray(value) &&
+ value.length === 0) {
+ return true;
+ }
- } else if (Node.check(node) && !Expression.check(node)) {
- types.eachField(node, function(name, child) {
- var childPath = path.get(name);
- if (childPath.value !== child) {
- throw new Error("");
- }
- recursiveScanChild(childPath, bindings, scopeTypes);
- });
+ return false;
}
-}
-function recursiveScanChild(path, bindings, scopeTypes) {
- var node = path.value;
+ function recursiveScanChild(path, bindings, scopeTypes) {
+ var node = path.value;
- if (!node || Expression.check(node)) {
- // Ignore falsy values and Expressions.
+ if (!node || Expression.check(node)) {
+ // Ignore falsy values and Expressions.
- } else if (namedTypes.FunctionDeclaration.check(node)) {
- addPattern(path.get("id"), bindings);
+ } else if (namedTypes.FunctionDeclaration.check(node)) {
+ addPattern(path.get("id"), bindings);
- } else if (namedTypes.ClassDeclaration &&
- namedTypes.ClassDeclaration.check(node)) {
- addPattern(path.get("id"), bindings);
+ } else if (namedTypes.ClassDeclaration &&
+ namedTypes.ClassDeclaration.check(node)) {
+ addPattern(path.get("id"), bindings);
- } else if (ScopeType.check(node)) {
- if (namedTypes.CatchClause.check(node)) {
- var catchParamName = node.param.name;
- var hadBinding = hasOwn.call(bindings, catchParamName);
-
- // Any declarations that occur inside the catch body that do
- // not have the same name as the catch parameter should count
- // as bindings in the outer scope.
- recursiveScanScope(path.get("body"), bindings, scopeTypes);
-
- // If a new binding matching the catch parameter name was
- // created while scanning the catch body, ignore it because it
- // actually refers to the catch parameter and not the outer
- // scope that we're currently scanning.
- if (!hadBinding) {
- delete bindings[catchParamName];
- }
- }
+ } else if (ScopeType.check(node)) {
+ if (namedTypes.CatchClause.check(node)) {
+ var catchParamName = node.param.name;
+ var hadBinding = hasOwn.call(bindings, catchParamName);
- } else {
- recursiveScanScope(path, bindings, scopeTypes);
- }
-}
+ // Any declarations that occur inside the catch body that do
+ // not have the same name as the catch parameter should count
+ // as bindings in the outer scope.
+ recursiveScanScope(path.get("body"), bindings, scopeTypes);
-function addPattern(patternPath, bindings) {
- var pattern = patternPath.value;
- namedTypes.Pattern.assert(pattern);
+ // If a new binding matching the catch parameter name was
+ // created while scanning the catch body, ignore it because it
+ // actually refers to the catch parameter and not the outer
+ // scope that we're currently scanning.
+ if (!hadBinding) {
+ delete bindings[catchParamName];
+ }
+ }
- if (namedTypes.Identifier.check(pattern)) {
- if (hasOwn.call(bindings, pattern.name)) {
- bindings[pattern.name].push(patternPath);
} else {
- bindings[pattern.name] = [patternPath];
+ recursiveScanScope(path, bindings, scopeTypes);
}
+ }
- } else if (namedTypes.ObjectPattern &&
- namedTypes.ObjectPattern.check(pattern)) {
- patternPath.get('properties').each(function(propertyPath) {
- var property = propertyPath.value;
- if (namedTypes.Pattern.check(property)) {
- addPattern(propertyPath, bindings);
- } else if (namedTypes.Property.check(property)) {
- addPattern(propertyPath.get('value'), bindings);
- } else if (namedTypes.SpreadProperty &&
- namedTypes.SpreadProperty.check(property)) {
- addPattern(propertyPath.get('argument'), bindings);
- }
- });
+ function addPattern(patternPath, bindings) {
+ var pattern = patternPath.value;
+ namedTypes.Pattern.assert(pattern);
- } else if (namedTypes.ArrayPattern &&
- namedTypes.ArrayPattern.check(pattern)) {
- patternPath.get('elements').each(function(elementPath) {
- var element = elementPath.value;
- if (namedTypes.Pattern.check(element)) {
- addPattern(elementPath, bindings);
- } else if (namedTypes.SpreadElement &&
- namedTypes.SpreadElement.check(element)) {
- addPattern(elementPath.get("argument"), bindings);
+ if (namedTypes.Identifier.check(pattern)) {
+ if (hasOwn.call(bindings, pattern.name)) {
+ bindings[pattern.name].push(patternPath);
+ } else {
+ bindings[pattern.name] = [patternPath];
}
- });
-
- } else if (namedTypes.PropertyPattern &&
- namedTypes.PropertyPattern.check(pattern)) {
- addPattern(patternPath.get('pattern'), bindings);
- } else if ((namedTypes.SpreadElementPattern &&
- namedTypes.SpreadElementPattern.check(pattern)) ||
- (namedTypes.SpreadPropertyPattern &&
- namedTypes.SpreadPropertyPattern.check(pattern))) {
- addPattern(patternPath.get('argument'), bindings);
+ } else if (namedTypes.ObjectPattern &&
+ namedTypes.ObjectPattern.check(pattern)) {
+ patternPath.get('properties').each(function(propertyPath) {
+ var property = propertyPath.value;
+ if (namedTypes.Pattern.check(property)) {
+ addPattern(propertyPath, bindings);
+ } else if (namedTypes.Property.check(property)) {
+ addPattern(propertyPath.get('value'), bindings);
+ } else if (namedTypes.SpreadProperty &&
+ namedTypes.SpreadProperty.check(property)) {
+ addPattern(propertyPath.get('argument'), bindings);
+ }
+ });
+
+ } else if (namedTypes.ArrayPattern &&
+ namedTypes.ArrayPattern.check(pattern)) {
+ patternPath.get('elements').each(function(elementPath) {
+ var element = elementPath.value;
+ if (namedTypes.Pattern.check(element)) {
+ addPattern(elementPath, bindings);
+ } else if (namedTypes.SpreadElement &&
+ namedTypes.SpreadElement.check(element)) {
+ addPattern(elementPath.get("argument"), bindings);
+ }
+ });
+
+ } else if (namedTypes.PropertyPattern &&
+ namedTypes.PropertyPattern.check(pattern)) {
+ addPattern(patternPath.get('pattern'), bindings);
+
+ } else if ((namedTypes.SpreadElementPattern &&
+ namedTypes.SpreadElementPattern.check(pattern)) ||
+ (namedTypes.SpreadPropertyPattern &&
+ namedTypes.SpreadPropertyPattern.check(pattern))) {
+ addPattern(patternPath.get('argument'), bindings);
+ }
}
-}
-function addTypePattern(patternPath, types) {
- var pattern = patternPath.value;
- namedTypes.Pattern.assert(pattern);
+ function addTypePattern(patternPath, types) {
+ var pattern = patternPath.value;
+ namedTypes.Pattern.assert(pattern);
- if (namedTypes.Identifier.check(pattern)) {
- if (hasOwn.call(types, pattern.name)) {
- types[pattern.name].push(patternPath);
- } else {
- types[pattern.name] = [patternPath];
- }
+ if (namedTypes.Identifier.check(pattern)) {
+ if (hasOwn.call(types, pattern.name)) {
+ types[pattern.name].push(patternPath);
+ } else {
+ types[pattern.name] = [patternPath];
+ }
+ }
}
-}
-
-Sp.lookup = function(name) {
- for (var scope = this; scope; scope = scope.parent)
- if (scope.declares(name))
- break;
- return scope;
-};
-
-Sp.lookupType = function(name) {
- for (var scope = this; scope; scope = scope.parent)
- if (scope.declaresType(name))
- break;
- return scope;
-};
-Sp.getGlobalScope = function() {
- var scope = this;
- while (!scope.isGlobal)
- scope = scope.parent;
- return scope;
+ Sp.lookup = function(name) {
+ for (var scope = this; scope; scope = scope.parent)
+ if (scope.declares(name))
+ break;
+ return scope;
+ };
+
+ Sp.lookupType = function(name) {
+ for (var scope = this; scope; scope = scope.parent)
+ if (scope.declaresType(name))
+ break;
+ return scope;
+ };
+
+ Sp.getGlobalScope = function() {
+ var scope = this;
+ while (!scope.isGlobal)
+ scope = scope.parent;
+ return scope;
+ };
+
+ return Scope;
};
-
-module.exports = Scope;
diff --git a/lib/shared.js b/lib/shared.js
index 3e84086..a2df7a9 100644
--- a/lib/shared.js
+++ b/lib/shared.js
@@ -1,41 +1,46 @@
-var types = require("../lib/types");
-var Type = types.Type;
-var builtin = types.builtInTypes;
-var isNumber = builtin.number;
+module.exports = function (fork) {
+ var exports = {};
+ var types = fork.use(require("../lib/types"));
+ var Type = types.Type;
+ var builtin = types.builtInTypes;
+ var isNumber = builtin.number;
-// An example of constructing a new type with arbitrary constraints from
-// an existing type.
-exports.geq = function(than) {
- return new Type(function(value) {
- return isNumber.check(value) && value >= than;
- }, isNumber + " >= " + than);
-};
+ // An example of constructing a new type with arbitrary constraints from
+ // an existing type.
+ exports.geq = function (than) {
+ return new Type(function (value) {
+ return isNumber.check(value) && value >= than;
+ }, isNumber + " >= " + than);
+ };
-// Default value-returning functions that may optionally be passed as a
-// third argument to Def.prototype.field.
-exports.defaults = {
- // Functions were used because (among other reasons) that's the most
- // elegant way to allow for the emptyArray one always to give a new
- // array instance.
- "null": function() { return null },
- "emptyArray": function() { return [] },
- "false": function() { return false },
- "true": function() { return true },
- "undefined": function() {}
-};
+ // Default value-returning functions that may optionally be passed as a
+ // third argument to Def.prototype.field.
+ exports.defaults = {
+ // Functions were used because (among other reasons) that's the most
+ // elegant way to allow for the emptyArray one always to give a new
+ // array instance.
+ "null": function () { return null },
+ "emptyArray": function () { return [] },
+ "false": function () { return false },
+ "true": function () { return true },
+ "undefined": function () {}
+ };
-var naiveIsPrimitive = Type.or(
- builtin.string,
- builtin.number,
- builtin.boolean,
- builtin.null,
- builtin.undefined
-);
+ var naiveIsPrimitive = Type.or(
+ builtin.string,
+ builtin.number,
+ builtin.boolean,
+ builtin.null,
+ builtin.undefined
+ );
-exports.isPrimitive = new Type(function(value) {
- if (value === null)
- return true;
- var type = typeof value;
- return !(type === "object" ||
- type === "function");
-}, naiveIsPrimitive.toString());
+ exports.isPrimitive = new Type(function (value) {
+ if (value === null)
+ return true;
+ var type = typeof value;
+ return !(type === "object" ||
+ type === "function");
+ }, naiveIsPrimitive.toString());
+
+ return exports;
+};
\ No newline at end of file
diff --git a/lib/types.js b/lib/types.js
index b4d4aee..927cba4 100644
--- a/lib/types.js
+++ b/lib/types.js
@@ -8,821 +8,828 @@ var funObjStr = objToStr.call(function(){});
var strObjStr = objToStr.call("");
var hasOwn = Op.hasOwnProperty;
-// A type is an object with a .check method that takes a value and returns
-// true or false according to whether the value matches the type.
+module.exports = function () {
-function Type(check, name) {
- var self = this;
- if (!(self instanceof Type)) {
- throw new Error("Type constructor cannot be invoked without 'new'");
- }
+ var exports = {};
- // Unfortunately we can't elegantly reuse isFunction and isString,
- // here, because this code is executed while defining those types.
- if (objToStr.call(check) !== funObjStr) {
- throw new Error(check + " is not a function");
- }
+ // A type is an object with a .check method that takes a value and returns
+ // true or false according to whether the value matches the type.
+
+ function Type(check, name) {
+ var self = this;
+ if (!(self instanceof Type)) {
+ throw new Error("Type constructor cannot be invoked without 'new'");
+ }
+
+ // Unfortunately we can't elegantly reuse isFunction and isString,
+ // here, because this code is executed while defining those types.
+ if (objToStr.call(check) !== funObjStr) {
+ throw new Error(check + " is not a function");
+ }
- // The `name` parameter can be either a function or a string.
- var nameObjStr = objToStr.call(name);
- if (!(nameObjStr === funObjStr ||
+ // The `name` parameter can be either a function or a string.
+ var nameObjStr = objToStr.call(name);
+ if (!(nameObjStr === funObjStr ||
nameObjStr === strObjStr)) {
- throw new Error(name + " is neither a function nor a string");
- }
+ throw new Error(name + " is neither a function nor a string");
+ }
- Object.defineProperties(self, {
- name: { value: name },
- check: {
- value: function(value, deep) {
- var result = check.call(self, value, deep);
- if (!result && deep && objToStr.call(deep) === funObjStr)
- deep(self, value);
- return result;
+ Object.defineProperties(self, {
+ name: {value: name},
+ check: {
+ value: function (value, deep) {
+ var result = check.call(self, value, deep);
+ if (!result && deep && objToStr.call(deep) === funObjStr)
+ deep(self, value);
+ return result;
+ }
}
- }
- });
-}
+ });
+ }
-var Tp = Type.prototype;
+ var Tp = Type.prototype;
-// Throughout this file we use Object.defineProperty to prevent
-// redefinition of exported properties.
-exports.Type = Type;
+ // Throughout this file we use Object.defineProperty to prevent
+ // redefinition of exported properties.
+ exports.Type = Type;
-// Like .check, except that failure triggers an AssertionError.
-Tp.assert = function(value, deep) {
- if (!this.check(value, deep)) {
- var str = shallowStringify(value);
- throw new Error(str + " does not match type " + this);
- }
- return true;
-};
+ // Like .check, except that failure triggers an AssertionError.
+ Tp.assert = function (value, deep) {
+ if (!this.check(value, deep)) {
+ var str = shallowStringify(value);
+ throw new Error(str + " does not match type " + this);
+ }
+ return true;
+ };
-function shallowStringify(value) {
- if (isObject.check(value))
- return "{" + Object.keys(value).map(function(key) {
- return key + ": " + value[key];
- }).join(", ") + "}";
+ function shallowStringify(value) {
+ if (isObject.check(value))
+ return "{" + Object.keys(value).map(function (key) {
+ return key + ": " + value[key];
+ }).join(", ") + "}";
- if (isArray.check(value))
- return "[" + value.map(shallowStringify).join(", ") + "]";
+ if (isArray.check(value))
+ return "[" + value.map(shallowStringify).join(", ") + "]";
- return JSON.stringify(value);
-}
+ return JSON.stringify(value);
+ }
-Tp.toString = function() {
- var name = this.name;
+ Tp.toString = function () {
+ var name = this.name;
- if (isString.check(name))
- return name;
+ if (isString.check(name))
+ return name;
- if (isFunction.check(name))
- return name.call(this) + "";
+ if (isFunction.check(name))
+ return name.call(this) + "";
- return name + " type";
-};
+ return name + " type";
+ };
-var builtInCtorFns = [];
-var builtInCtorTypes = [];
-var builtInTypes = {};
-exports.builtInTypes = builtInTypes;
+ var builtInCtorFns = [];
+ var builtInCtorTypes = [];
+ var builtInTypes = {};
+ exports.builtInTypes = builtInTypes;
-function defBuiltInType(example, name) {
- var objStr = objToStr.call(example);
+ function defBuiltInType(example, name) {
+ var objStr = objToStr.call(example);
- var type = new Type(function(value) {
- return objToStr.call(value) === objStr;
- }, name);
+ var type = new Type(function (value) {
+ return objToStr.call(value) === objStr;
+ }, name);
- builtInTypes[name] = type;
+ builtInTypes[name] = type;
- if (example && typeof example.constructor === "function") {
- builtInCtorFns.push(example.constructor);
- builtInCtorTypes.push(type);
+ if (example && typeof example.constructor === "function") {
+ builtInCtorFns.push(example.constructor);
+ builtInCtorTypes.push(type);
+ }
+
+ return type;
}
- return type;
-}
-
-// These types check the underlying [[Class]] attribute of the given
-// value, rather than using the problematic typeof operator. Note however
-// that no subtyping is considered; so, for instance, isObject.check
-// returns false for [], /./, new Date, and null.
-var isString = defBuiltInType("truthy", "string");
-var isFunction = defBuiltInType(function(){}, "function");
-var isArray = defBuiltInType([], "array");
-var isObject = defBuiltInType({}, "object");
-var isRegExp = defBuiltInType(/./, "RegExp");
-var isDate = defBuiltInType(new Date, "Date");
-var isNumber = defBuiltInType(3, "number");
-var isBoolean = defBuiltInType(true, "boolean");
-var isNull = defBuiltInType(null, "null");
-var isUndefined = defBuiltInType(void 0, "undefined");
-
-// There are a number of idiomatic ways of expressing types, so this
-// function serves to coerce them all to actual Type objects. Note that
-// providing the name argument is not necessary in most cases.
-function toType(from, name) {
- // The toType function should of course be idempotent.
- if (from instanceof Type)
- return from;
-
- // The Def type is used as a helper for constructing compound
- // interface types for AST nodes.
- if (from instanceof Def)
- return from.type;
-
- // Support [ElemType] syntax.
- if (isArray.check(from))
- return Type.fromArray(from);
-
- // Support { someField: FieldType, ... } syntax.
- if (isObject.check(from))
- return Type.fromObject(from);
-
- if (isFunction.check(from)) {
- var bicfIndex = builtInCtorFns.indexOf(from);
- if (bicfIndex >= 0) {
- return builtInCtorTypes[bicfIndex];
+ // These types check the underlying [[Class]] attribute of the given
+ // value, rather than using the problematic typeof operator. Note however
+ // that no subtyping is considered; so, for instance, isObject.check
+ // returns false for [], /./, new Date, and null.
+ var isString = defBuiltInType("truthy", "string");
+ var isFunction = defBuiltInType(function () {}, "function");
+ var isArray = defBuiltInType([], "array");
+ var isObject = defBuiltInType({}, "object");
+ var isRegExp = defBuiltInType(/./, "RegExp");
+ var isDate = defBuiltInType(new Date, "Date");
+ var isNumber = defBuiltInType(3, "number");
+ var isBoolean = defBuiltInType(true, "boolean");
+ var isNull = defBuiltInType(null, "null");
+ var isUndefined = defBuiltInType(void 0, "undefined");
+
+ // There are a number of idiomatic ways of expressing types, so this
+ // function serves to coerce them all to actual Type objects. Note that
+ // providing the name argument is not necessary in most cases.
+ function toType(from, name) {
+ // The toType function should of course be idempotent.
+ if (from instanceof Type)
+ return from;
+
+ // The Def type is used as a helper for constructing compound
+ // interface types for AST nodes.
+ if (from instanceof Def)
+ return from.type;
+
+ // Support [ElemType] syntax.
+ if (isArray.check(from))
+ return Type.fromArray(from);
+
+ // Support { someField: FieldType, ... } syntax.
+ if (isObject.check(from))
+ return Type.fromObject(from);
+
+ if (isFunction.check(from)) {
+ var bicfIndex = builtInCtorFns.indexOf(from);
+ if (bicfIndex >= 0) {
+ return builtInCtorTypes[bicfIndex];
+ }
+
+ // If isFunction.check(from), and from is not a built-in
+ // constructor, assume from is a binary predicate function we can
+ // use to define the type.
+ return new Type(from, name);
}
- // If isFunction.check(from), and from is not a built-in
- // constructor, assume from is a binary predicate function we can
- // use to define the type.
- return new Type(from, name);
+ // As a last resort, toType returns a type that matches any value that
+ // is === from. This is primarily useful for literal values like
+ // toType(null), but it has the additional advantage of allowing
+ // toType to be a total function.
+ return new Type(function (value) {
+ return value === from;
+ }, isUndefined.check(name) ? function () {
+ return from + "";
+ } : name);
}
- // As a last resort, toType returns a type that matches any value that
- // is === from. This is primarily useful for literal values like
- // toType(null), but it has the additional advantage of allowing
- // toType to be a total function.
- return new Type(function(value) {
- return value === from;
- }, isUndefined.check(name) ? function() {
- return from + "";
- } : name);
-}
-
-// Returns a type that matches the given value iff any of type1, type2,
-// etc. match the value.
-Type.or = function(/* type1, type2, ... */) {
- var types = [];
- var len = arguments.length;
- for (var i = 0; i < len; ++i)
- types.push(toType(arguments[i]));
-
- return new Type(function(value, deep) {
+ // Returns a type that matches the given value iff any of type1, type2,
+ // etc. match the value.
+ Type.or = function (/* type1, type2, ... */) {
+ var types = [];
+ var len = arguments.length;
for (var i = 0; i < len; ++i)
- if (types[i].check(value, deep))
- return true;
- return false;
- }, function() {
- return types.join(" | ");
- });
-};
+ types.push(toType(arguments[i]));
+
+ return new Type(function (value, deep) {
+ for (var i = 0; i < len; ++i)
+ if (types[i].check(value, deep))
+ return true;
+ return false;
+ }, function () {
+ return types.join(" | ");
+ });
+ };
-Type.fromArray = function(arr) {
- if (!isArray.check(arr)) {
- throw new Error("");
- }
- if (arr.length !== 1) {
- throw new Error("only one element type is permitted for typed arrays");
- }
- return toType(arr[0]).arrayOf();
-};
+ Type.fromArray = function (arr) {
+ if (!isArray.check(arr)) {
+ throw new Error("");
+ }
+ if (arr.length !== 1) {
+ throw new Error("only one element type is permitted for typed arrays");
+ }
+ return toType(arr[0]).arrayOf();
+ };
-Tp.arrayOf = function() {
- var elemType = this;
- return new Type(function(value, deep) {
- return isArray.check(value) && value.every(function(elem) {
- return elemType.check(elem, deep);
+ Tp.arrayOf = function () {
+ var elemType = this;
+ return new Type(function (value, deep) {
+ return isArray.check(value) && value.every(function (elem) {
+ return elemType.check(elem, deep);
+ });
+ }, function () {
+ return "[" + elemType + "]";
});
- }, function() {
- return "[" + elemType + "]";
- });
-};
+ };
-Type.fromObject = function(obj) {
- var fields = Object.keys(obj).map(function(name) {
- return new Field(name, obj[name]);
- });
+ Type.fromObject = function (obj) {
+ var fields = Object.keys(obj).map(function (name) {
+ return new Field(name, obj[name]);
+ });
- return new Type(function(value, deep) {
- return isObject.check(value) && fields.every(function(field) {
- return field.type.check(value[field.name], deep);
+ return new Type(function (value, deep) {
+ return isObject.check(value) && fields.every(function (field) {
+ return field.type.check(value[field.name], deep);
+ });
+ }, function () {
+ return "{ " + fields.join(", ") + " }";
});
- }, function() {
- return "{ " + fields.join(", ") + " }";
- });
-};
+ };
-function Field(name, type, defaultFn, hidden) {
- var self = this;
+ function Field(name, type, defaultFn, hidden) {
+ var self = this;
- if (!(self instanceof Field)) {
- throw new Error("Field constructor cannot be invoked without 'new'");
- }
- isString.assert(name);
+ if (!(self instanceof Field)) {
+ throw new Error("Field constructor cannot be invoked without 'new'");
+ }
+ isString.assert(name);
- type = toType(type);
+ type = toType(type);
- var properties = {
- name: { value: name },
- type: { value: type },
- hidden: { value: !!hidden }
- };
+ var properties = {
+ name: {value: name},
+ type: {value: type},
+ hidden: {value: !!hidden}
+ };
+
+ if (isFunction.check(defaultFn)) {
+ properties.defaultFn = {value: defaultFn};
+ }
- if (isFunction.check(defaultFn)) {
- properties.defaultFn = { value: defaultFn };
+ Object.defineProperties(self, properties);
}
- Object.defineProperties(self, properties);
-}
+ var Fp = Field.prototype;
-var Fp = Field.prototype;
+ Fp.toString = function () {
+ return JSON.stringify(this.name) + ": " + this.type;
+ };
-Fp.toString = function() {
- return JSON.stringify(this.name) + ": " + this.type;
-};
+ Fp.getValue = function (obj) {
+ var value = obj[this.name];
-Fp.getValue = function(obj) {
- var value = obj[this.name];
+ if (!isUndefined.check(value))
+ return value;
- if (!isUndefined.check(value))
- return value;
+ if (this.defaultFn)
+ value = this.defaultFn.call(obj);
- if (this.defaultFn)
- value = this.defaultFn.call(obj);
+ return value;
+ };
- return value;
-};
+ // Define a type whose name is registered in a namespace (the defCache) so
+ // that future definitions will return the same type given the same name.
+ // In particular, this system allows for circular and forward definitions.
+ // The Def object d returned from Type.def may be used to configure the
+ // type d.type by calling methods such as d.bases, d.build, and d.field.
+ Type.def = function (typeName) {
+ isString.assert(typeName);
+ return hasOwn.call(defCache, typeName)
+ ? defCache[typeName]
+ : defCache[typeName] = new Def(typeName);
+ };
-// Define a type whose name is registered in a namespace (the defCache) so
-// that future definitions will return the same type given the same name.
-// In particular, this system allows for circular and forward definitions.
-// The Def object d returned from Type.def may be used to configure the
-// type d.type by calling methods such as d.bases, d.build, and d.field.
-Type.def = function(typeName) {
- isString.assert(typeName);
- return hasOwn.call(defCache, typeName)
- ? defCache[typeName]
- : defCache[typeName] = new Def(typeName);
-};
+ // In order to return the same Def instance every time Type.def is called
+ // with a particular name, those instances need to be stored in a cache.
+ var defCache = Object.create(null);
-// In order to return the same Def instance every time Type.def is called
-// with a particular name, those instances need to be stored in a cache.
-var defCache = Object.create(null);
+ function Def(typeName) {
+ var self = this;
+ if (!(self instanceof Def)) {
+ throw new Error("Def constructor cannot be invoked without 'new'");
+ }
-function Def(typeName) {
- var self = this;
- if (!(self instanceof Def)) {
- throw new Error("Def constructor cannot be invoked without 'new'");
+ Object.defineProperties(self, {
+ typeName: {value: typeName},
+ baseNames: {value: []},
+ ownFields: {value: Object.create(null)},
+
+ // These two are populated during finalization.
+ allSupertypes: {value: Object.create(null)}, // Includes own typeName.
+ supertypeList: {value: []}, // Linear inheritance hierarchy.
+ allFields: {value: Object.create(null)}, // Includes inherited fields.
+ fieldNames: {value: []}, // Non-hidden keys of allFields.
+
+ type: {
+ value: new Type(function (value, deep) {
+ return self.check(value, deep);
+ }, typeName)
+ }
+ });
}
- Object.defineProperties(self, {
- typeName: { value: typeName },
- baseNames: { value: [] },
- ownFields: { value: Object.create(null) },
-
- // These two are populated during finalization.
- allSupertypes: { value: Object.create(null) }, // Includes own typeName.
- supertypeList: { value: [] }, // Linear inheritance hierarchy.
- allFields: { value: Object.create(null) }, // Includes inherited fields.
- fieldNames: { value: [] }, // Non-hidden keys of allFields.
-
- type: {
- value: new Type(function(value, deep) {
- return self.check(value, deep);
- }, typeName)
- }
- });
-}
-
-Def.fromValue = function(value) {
- if (value && typeof value === "object") {
- var type = value.type;
- if (typeof type === "string" &&
- hasOwn.call(defCache, type)) {
- var d = defCache[type];
- if (d.finalized) {
- return d;
+ Def.fromValue = function (value) {
+ if (value && typeof value === "object") {
+ var type = value.type;
+ if (typeof type === "string" &&
+ hasOwn.call(defCache, type)) {
+ var d = defCache[type];
+ if (d.finalized) {
+ return d;
+ }
}
}
- }
- return null;
-};
+ return null;
+ };
-var Dp = Def.prototype;
+ var Dp = Def.prototype;
-Dp.isSupertypeOf = function(that) {
- if (that instanceof Def) {
- if (this.finalized !== true ||
- that.finalized !== true) {
- throw new Error("");
+ Dp.isSupertypeOf = function (that) {
+ if (that instanceof Def) {
+ if (this.finalized !== true ||
+ that.finalized !== true) {
+ throw new Error("");
+ }
+ return hasOwn.call(that.allSupertypes, this.typeName);
+ } else {
+ throw new Error(that + " is not a Def");
}
- return hasOwn.call(that.allSupertypes, this.typeName);
- } else {
- throw new Error(that + " is not a Def");
- }
-};
-
-// Note that the list returned by this function is a copy of the internal
-// supertypeList, *without* the typeName itself as the first element.
-exports.getSupertypeNames = function(typeName) {
- if (!hasOwn.call(defCache, typeName)) {
- throw new Error("");
- }
- var d = defCache[typeName];
- if (d.finalized !== true) {
- throw new Error("");
- }
- return d.supertypeList.slice(1);
-};
-
-// Returns an object mapping from every known type in the defCache to the
-// most specific supertype whose name is an own property of the candidates
-// object.
-exports.computeSupertypeLookupTable = function(candidates) {
- var table = {};
- var typeNames = Object.keys(defCache);
- var typeNameCount = typeNames.length;
+ };
- for (var i = 0; i < typeNameCount; ++i) {
- var typeName = typeNames[i];
+ // Note that the list returned by this function is a copy of the internal
+ // supertypeList, *without* the typeName itself as the first element.
+ exports.getSupertypeNames = function (typeName) {
+ if (!hasOwn.call(defCache, typeName)) {
+ throw new Error("");
+ }
var d = defCache[typeName];
if (d.finalized !== true) {
- throw new Error("" + typeName);
+ throw new Error("");
}
- for (var j = 0; j < d.supertypeList.length; ++j) {
- var superTypeName = d.supertypeList[j];
- if (hasOwn.call(candidates, superTypeName)) {
- table[typeName] = superTypeName;
- break;
+ return d.supertypeList.slice(1);
+ };
+
+ // Returns an object mapping from every known type in the defCache to the
+ // most specific supertype whose name is an own property of the candidates
+ // object.
+ exports.computeSupertypeLookupTable = function (candidates) {
+ var table = {};
+ var typeNames = Object.keys(defCache);
+ var typeNameCount = typeNames.length;
+
+ for (var i = 0; i < typeNameCount; ++i) {
+ var typeName = typeNames[i];
+ var d = defCache[typeName];
+ if (d.finalized !== true) {
+ throw new Error("" + typeName);
+ }
+ for (var j = 0; j < d.supertypeList.length; ++j) {
+ var superTypeName = d.supertypeList[j];
+ if (hasOwn.call(candidates, superTypeName)) {
+ table[typeName] = superTypeName;
+ break;
+ }
}
}
- }
-
- return table;
-};
-Dp.checkAllFields = function(value, deep) {
- var allFields = this.allFields;
- if (this.finalized !== true) {
- throw new Error("" + this.typeName);
- }
+ return table;
+ };
- function checkFieldByName(name) {
- var field = allFields[name];
- var type = field.type;
- var child = field.getValue(value);
- return type.check(child, deep);
- }
+ Dp.checkAllFields = function (value, deep) {
+ var allFields = this.allFields;
+ if (this.finalized !== true) {
+ throw new Error("" + this.typeName);
+ }
- return isObject.check(value)
- && Object.keys(allFields).every(checkFieldByName);
-};
+ function checkFieldByName(name) {
+ var field = allFields[name];
+ var type = field.type;
+ var child = field.getValue(value);
+ return type.check(child, deep);
+ }
-Dp.check = function(value, deep) {
- if (this.finalized !== true) {
- throw new Error(
- "prematurely checking unfinalized type " + this.typeName
- );
- }
+ return isObject.check(value)
+ && Object.keys(allFields).every(checkFieldByName);
+ };
- // A Def type can only match an object value.
- if (!isObject.check(value))
- return false;
-
- var vDef = Def.fromValue(value);
- if (!vDef) {
- // If we couldn't infer the Def associated with the given value,
- // and we expected it to be a SourceLocation or a Position, it was
- // probably just missing a "type" field (because Esprima does not
- // assign a type property to such nodes). Be optimistic and let
- // this.checkAllFields make the final decision.
- if (this.typeName === "SourceLocation" ||
- this.typeName === "Position") {
- return this.checkAllFields(value, deep);
+ Dp.check = function (value, deep) {
+ if (this.finalized !== true) {
+ throw new Error(
+ "prematurely checking unfinalized type " + this.typeName
+ );
}
- // Calling this.checkAllFields for any other type of node is both
- // bad for performance and way too forgiving.
- return false;
- }
+ // A Def type can only match an object value.
+ if (!isObject.check(value))
+ return false;
+
+ var vDef = Def.fromValue(value);
+ if (!vDef) {
+ // If we couldn't infer the Def associated with the given value,
+ // and we expected it to be a SourceLocation or a Position, it was
+ // probably just missing a "type" field (because Esprima does not
+ // assign a type property to such nodes). Be optimistic and let
+ // this.checkAllFields make the final decision.
+ if (this.typeName === "SourceLocation" ||
+ this.typeName === "Position") {
+ return this.checkAllFields(value, deep);
+ }
- // If checking deeply and vDef === this, then we only need to call
- // checkAllFields once. Calling checkAllFields is too strict when deep
- // is false, because then we only care about this.isSupertypeOf(vDef).
- if (deep && vDef === this)
- return this.checkAllFields(value, deep);
-
- // In most cases we rely exclusively on isSupertypeOf to make O(1)
- // subtyping determinations. This suffices in most situations outside
- // of unit tests, since interface conformance is checked whenever new
- // instances are created using builder functions.
- if (!this.isSupertypeOf(vDef))
- return false;
-
- // The exception is when deep is true; then, we recursively check all
- // fields.
- if (!deep)
- return true;
+ // Calling this.checkAllFields for any other type of node is both
+ // bad for performance and way too forgiving.
+ return false;
+ }
- // Use the more specific Def (vDef) to perform the deep check, but
- // shallow-check fields defined by the less specific Def (this).
- return vDef.checkAllFields(value, deep)
- && this.checkAllFields(value, false);
-};
+ // If checking deeply and vDef === this, then we only need to call
+ // checkAllFields once. Calling checkAllFields is too strict when deep
+ // is false, because then we only care about this.isSupertypeOf(vDef).
+ if (deep && vDef === this)
+ return this.checkAllFields(value, deep);
+
+ // In most cases we rely exclusively on isSupertypeOf to make O(1)
+ // subtyping determinations. This suffices in most situations outside
+ // of unit tests, since interface conformance is checked whenever new
+ // instances are created using builder functions.
+ if (!this.isSupertypeOf(vDef))
+ return false;
+
+ // The exception is when deep is true; then, we recursively check all
+ // fields.
+ if (!deep)
+ return true;
+
+ // Use the more specific Def (vDef) to perform the deep check, but
+ // shallow-check fields defined by the less specific Def (this).
+ return vDef.checkAllFields(value, deep)
+ && this.checkAllFields(value, false);
+ };
-Dp.bases = function() {
- var args = slice.call(arguments);
- var bases = this.baseNames;
+ Dp.bases = function () {
+ var args = slice.call(arguments);
+ var bases = this.baseNames;
- if (this.finalized) {
- if (args.length !== bases.length) {
- throw new Error("");
- }
- for (var i = 0; i < args.length; i++) {
- if (args[i] !== bases[i]) {
+ if (this.finalized) {
+ if (args.length !== bases.length) {
throw new Error("");
}
+ for (var i = 0; i < args.length; i++) {
+ if (args[i] !== bases[i]) {
+ throw new Error("");
+ }
+ }
+ return this;
}
- return this;
- }
- args.forEach(function(baseName) {
- isString.assert(baseName);
+ args.forEach(function (baseName) {
+ isString.assert(baseName);
- // This indexOf lookup may be O(n), but the typical number of base
- // names is very small, and indexOf is a native Array method.
- if (bases.indexOf(baseName) < 0)
- bases.push(baseName);
- });
+ // This indexOf lookup may be O(n), but the typical number of base
+ // names is very small, and indexOf is a native Array method.
+ if (bases.indexOf(baseName) < 0)
+ bases.push(baseName);
+ });
- return this; // For chaining.
-};
+ return this; // For chaining.
+ };
-// False by default until .build(...) is called on an instance.
-Object.defineProperty(Dp, "buildable", { value: false });
+ // False by default until .build(...) is called on an instance.
+ Object.defineProperty(Dp, "buildable", {value: false});
-var builders = {};
-exports.builders = builders;
+ var builders = {};
+ exports.builders = builders;
-// This object is used as prototype for any node created by a builder.
-var nodePrototype = {};
+ // This object is used as prototype for any node created by a builder.
+ var nodePrototype = {};
-// Call this function to define a new method to be shared by all AST
-// nodes. The replaced method (if any) is returned for easy wrapping.
-exports.defineMethod = function(name, func) {
- var old = nodePrototype[name];
+ // Call this function to define a new method to be shared by all AST
+ // nodes. The replaced method (if any) is returned for easy wrapping.
+ exports.defineMethod = function (name, func) {
+ var old = nodePrototype[name];
- // Pass undefined as func to delete nodePrototype[name].
- if (isUndefined.check(func)) {
- delete nodePrototype[name];
+ // Pass undefined as func to delete nodePrototype[name].
+ if (isUndefined.check(func)) {
+ delete nodePrototype[name];
- } else {
- isFunction.assert(func);
+ } else {
+ isFunction.assert(func);
- Object.defineProperty(nodePrototype, name, {
- enumerable: true, // For discoverability.
- configurable: true, // For delete proto[name].
- value: func
- });
- }
+ Object.defineProperty(nodePrototype, name, {
+ enumerable: true, // For discoverability.
+ configurable: true, // For delete proto[name].
+ value: func
+ });
+ }
- return old;
-};
+ return old;
+ };
-var isArrayOfString = isString.arrayOf();
-
-// Calling the .build method of a Def simultaneously marks the type as
-// buildable (by defining builders[getBuilderName(typeName)]) and
-// specifies the order of arguments that should be passed to the builder
-// function to create an instance of the type.
-Dp.build = function(/* param1, param2, ... */) {
- var self = this;
-
- var newBuildParams = slice.call(arguments);
- isArrayOfString.assert(newBuildParams);
-
- // Calling Def.prototype.build multiple times has the effect of merely
- // redefining this property.
- Object.defineProperty(self, "buildParams", {
- value: newBuildParams,
- writable: false,
- enumerable: false,
- configurable: true
- });
-
- if (self.buildable) {
- // If this Def is already buildable, update self.buildParams and
- // continue using the old builder function.
- return self;
- }
+ var isArrayOfString = isString.arrayOf();
+
+ // Calling the .build method of a Def simultaneously marks the type as
+ // buildable (by defining builders[getBuilderName(typeName)]) and
+ // specifies the order of arguments that should be passed to the builder
+ // function to create an instance of the type.
+ Dp.build = function (/* param1, param2, ... */) {
+ var self = this;
+
+ var newBuildParams = slice.call(arguments);
+ isArrayOfString.assert(newBuildParams);
+
+ // Calling Def.prototype.build multiple times has the effect of merely
+ // redefining this property.
+ Object.defineProperty(self, "buildParams", {
+ value: newBuildParams,
+ writable: false,
+ enumerable: false,
+ configurable: true
+ });
- // Every buildable type will have its "type" field filled in
- // automatically. This includes types that are not subtypes of Node,
- // like SourceLocation, but that seems harmless (TODO?).
- self.field("type", String, function() { return self.typeName });
+ if (self.buildable) {
+ // If this Def is already buildable, update self.buildParams and
+ // continue using the old builder function.
+ return self;
+ }
- // Override Dp.buildable for this Def instance.
- Object.defineProperty(self, "buildable", { value: true });
+ // Every buildable type will have its "type" field filled in
+ // automatically. This includes types that are not subtypes of Node,
+ // like SourceLocation, but that seems harmless (TODO?).
+ self.field("type", String, function () { return self.typeName });
- Object.defineProperty(builders, getBuilderName(self.typeName), {
- enumerable: true,
+ // Override Dp.buildable for this Def instance.
+ Object.defineProperty(self, "buildable", {value: true});
- value: function() {
- var args = arguments;
- var argc = args.length;
- var built = Object.create(nodePrototype);
+ Object.defineProperty(builders, getBuilderName(self.typeName), {
+ enumerable: true,
- if (!self.finalized) {
- throw new Error(
- "attempting to instantiate unfinalized type " +
- self.typeName
- );
- }
+ value: function () {
+ var args = arguments;
+ var argc = args.length;
+ var built = Object.create(nodePrototype);
- function add(param, i) {
- if (hasOwn.call(built, param))
- return;
+ if (!self.finalized) {
+ throw new Error(
+ "attempting to instantiate unfinalized type " +
+ self.typeName
+ );
+ }
- var all = self.allFields;
- if (!hasOwn.call(all, param)) {
- throw new Error("" + param);
+ function add(param, i) {
+ if (hasOwn.call(built, param))
+ return;
+
+ var all = self.allFields;
+ if (!hasOwn.call(all, param)) {
+ throw new Error("" + param);
+ }
+
+ var field = all[param];
+ var type = field.type;
+ var value;
+
+ if (isNumber.check(i) && i < argc) {
+ value = args[i];
+ } else if (field.defaultFn) {
+ // Expose the partially-built object to the default
+ // function as its `this` object.
+ value = field.defaultFn.call(built);
+ } else {
+ var message = "no value or default function given for field " +
+ JSON.stringify(param) + " of " + self.typeName + "(" +
+ self.buildParams.map(function (name) {
+ return all[name];
+ }).join(", ") + ")";
+ throw new Error(message);
+ }
+
+ if (!type.check(value)) {
+ throw new Error(
+ shallowStringify(value) +
+ " does not match field " + field +
+ " of type " + self.typeName
+ );
+ }
+
+ // TODO Could attach getters and setters here to enforce
+ // dynamic type safety.
+ built[param] = value;
}
- var field = all[param];
- var type = field.type;
- var value;
+ self.buildParams.forEach(function (param, i) {
+ add(param, i);
+ });
- if (isNumber.check(i) && i < argc) {
- value = args[i];
- } else if (field.defaultFn) {
- // Expose the partially-built object to the default
- // function as its `this` object.
- value = field.defaultFn.call(built);
- } else {
- var message = "no value or default function given for field " +
- JSON.stringify(param) + " of " + self.typeName + "(" +
- self.buildParams.map(function(name) {
- return all[name];
- }).join(", ") + ")";
- throw new Error(message);
- }
+ Object.keys(self.allFields).forEach(function (param) {
+ add(param); // Use the default value.
+ });
- if (!type.check(value)) {
- throw new Error(
- shallowStringify(value) +
- " does not match field " + field +
- " of type " + self.typeName
- );
+ // Make sure that the "type" field was filled automatically.
+ if (built.type !== self.typeName) {
+ throw new Error("");
}
- // TODO Could attach getters and setters here to enforce
- // dynamic type safety.
- built[param] = value;
+ return built;
}
+ });
- self.buildParams.forEach(function(param, i) {
- add(param, i);
- });
-
- Object.keys(self.allFields).forEach(function(param) {
- add(param); // Use the default value.
- });
+ return self; // For chaining.
+ };
- // Make sure that the "type" field was filled automatically.
- if (built.type !== self.typeName) {
- throw new Error("");
+ function getBuilderName(typeName) {
+ return typeName.replace(/^[A-Z]+/, function (upperCasePrefix) {
+ var len = upperCasePrefix.length;
+ switch (len) {
+ case 0: return "";
+ // If there's only one initial capital letter, just lower-case it.
+ case 1: return upperCasePrefix.toLowerCase();
+ default:
+ // If there's more than one initial capital letter, lower-case
+ // all but the last one, so that XMLDefaultDeclaration (for
+ // example) becomes xmlDefaultDeclaration.
+ return upperCasePrefix.slice(
+ 0, len - 1).toLowerCase() +
+ upperCasePrefix.charAt(len - 1);
}
+ });
+ }
+ exports.getBuilderName = getBuilderName;
- return built;
+ function getStatementBuilderName(typeName) {
+ typeName = getBuilderName(typeName);
+ return typeName.replace(/(Expression)?$/, "Statement");
+ }
+ exports.getStatementBuilderName = getStatementBuilderName;
+
+ // The reason fields are specified using .field(...) instead of an object
+ // literal syntax is somewhat subtle: the object literal syntax would
+ // support only one key and one value, but with .field(...) we can pass
+ // any number of arguments to specify the field.
+ Dp.field = function (name, type, defaultFn, hidden) {
+ if (this.finalized) {
+ console.error("Ignoring attempt to redefine field " +
+ JSON.stringify(name) + " of finalized type " +
+ JSON.stringify(this.typeName));
+ return this;
}
- });
+ this.ownFields[name] = new Field(name, type, defaultFn, hidden);
+ return this; // For chaining.
+ };
- return self; // For chaining.
-};
+ var namedTypes = {};
+ exports.namedTypes = namedTypes;
-function getBuilderName(typeName) {
- return typeName.replace(/^[A-Z]+/, function(upperCasePrefix) {
- var len = upperCasePrefix.length;
- switch (len) {
- case 0: return "";
- // If there's only one initial capital letter, just lower-case it.
- case 1: return upperCasePrefix.toLowerCase();
- default:
- // If there's more than one initial capital letter, lower-case
- // all but the last one, so that XMLDefaultDeclaration (for
- // example) becomes xmlDefaultDeclaration.
- return upperCasePrefix.slice(
- 0, len - 1).toLowerCase() +
- upperCasePrefix.charAt(len - 1);
+ // Like Object.keys, but aware of what fields each AST type should have.
+ function getFieldNames(object) {
+ var d = Def.fromValue(object);
+ if (d) {
+ return d.fieldNames.slice(0);
}
- });
-}
-exports.getBuilderName = getBuilderName;
-
-function getStatementBuilderName(typeName) {
- typeName = getBuilderName(typeName);
- return typeName.replace(/(Expression)?$/, "Statement");
-}
-exports.getStatementBuilderName = getStatementBuilderName;
-
-// The reason fields are specified using .field(...) instead of an object
-// literal syntax is somewhat subtle: the object literal syntax would
-// support only one key and one value, but with .field(...) we can pass
-// any number of arguments to specify the field.
-Dp.field = function(name, type, defaultFn, hidden) {
- if (this.finalized) {
- console.error("Ignoring attempt to redefine field " +
- JSON.stringify(name) + " of finalized type " +
- JSON.stringify(this.typeName));
- return this;
- }
- this.ownFields[name] = new Field(name, type, defaultFn, hidden);
- return this; // For chaining.
-};
-var namedTypes = {};
-exports.namedTypes = namedTypes;
+ if ("type" in object) {
+ throw new Error(
+ "did not recognize object of type " +
+ JSON.stringify(object.type)
+ );
+ }
-// Like Object.keys, but aware of what fields each AST type should have.
-function getFieldNames(object) {
- var d = Def.fromValue(object);
- if (d) {
- return d.fieldNames.slice(0);
+ return Object.keys(object);
}
+ exports.getFieldNames = getFieldNames;
+
+ // Get the value of an object property, taking object.type and default
+ // functions into account.
+ function getFieldValue(object, fieldName) {
+ var d = Def.fromValue(object);
+ if (d) {
+ var field = d.allFields[fieldName];
+ if (field) {
+ return field.getValue(object);
+ }
+ }
- if ("type" in object) {
- throw new Error(
- "did not recognize object of type " +
- JSON.stringify(object.type)
- );
+ return object[fieldName];
}
+ exports.getFieldValue = getFieldValue;
+
+ // Iterate over all defined fields of an object, including those missing
+ // or undefined, passing each field name and effective value (as returned
+ // by getFieldValue) to the callback. If the object has no corresponding
+ // Def, the callback will never be called.
+ exports.eachField = function (object, callback, context) {
+ getFieldNames(object).forEach(function (name) {
+ callback.call(this, name, getFieldValue(object, name));
+ }, context);
+ };
- return Object.keys(object);
-}
-exports.getFieldNames = getFieldNames;
-
-// Get the value of an object property, taking object.type and default
-// functions into account.
-function getFieldValue(object, fieldName) {
- var d = Def.fromValue(object);
- if (d) {
- var field = d.allFields[fieldName];
- if (field) {
- return field.getValue(object);
- }
- }
+ // Similar to eachField, except that iteration stops as soon as the
+ // callback returns a truthy value. Like Array.prototype.some, the final
+ // result is either true or false to indicates whether the callback
+ // returned true for any element or not.
+ exports.someField = function (object, callback, context) {
+ return getFieldNames(object).some(function (name) {
+ return callback.call(this, name, getFieldValue(object, name));
+ }, context);
+ };
- return object[fieldName];
-}
-exports.getFieldValue = getFieldValue;
-
-// Iterate over all defined fields of an object, including those missing
-// or undefined, passing each field name and effective value (as returned
-// by getFieldValue) to the callback. If the object has no corresponding
-// Def, the callback will never be called.
-exports.eachField = function(object, callback, context) {
- getFieldNames(object).forEach(function(name) {
- callback.call(this, name, getFieldValue(object, name));
- }, context);
-};
+ // This property will be overridden as true by individual Def instances
+ // when they are finalized.
+ Object.defineProperty(Dp, "finalized", {value: false});
+
+ Dp.finalize = function () {
+ var self = this;
+
+ // It's not an error to finalize a type more than once, but only the
+ // first call to .finalize does anything.
+ if (!self.finalized) {
+ var allFields = self.allFields;
+ var allSupertypes = self.allSupertypes;
+
+ self.baseNames.forEach(function (name) {
+ var def = defCache[name];
+ if (def instanceof Def) {
+ def.finalize();
+ extend(allFields, def.allFields);
+ extend(allSupertypes, def.allSupertypes);
+ } else {
+ var message = "unknown supertype name " +
+ JSON.stringify(name) +
+ " for subtype " +
+ JSON.stringify(self.typeName);
+ throw new Error(message);
+ }
+ });
-// Similar to eachField, except that iteration stops as soon as the
-// callback returns a truthy value. Like Array.prototype.some, the final
-// result is either true or false to indicates whether the callback
-// returned true for any element or not.
-exports.someField = function(object, callback, context) {
- return getFieldNames(object).some(function(name) {
- return callback.call(this, name, getFieldValue(object, name));
- }, context);
-};
+ // TODO Warn if fields are overridden with incompatible types.
+ extend(allFields, self.ownFields);
+ allSupertypes[self.typeName] = self;
-// This property will be overridden as true by individual Def instances
-// when they are finalized.
-Object.defineProperty(Dp, "finalized", { value: false });
-
-Dp.finalize = function() {
- var self = this;
-
- // It's not an error to finalize a type more than once, but only the
- // first call to .finalize does anything.
- if (!self.finalized) {
- var allFields = self.allFields;
- var allSupertypes = self.allSupertypes;
-
- self.baseNames.forEach(function(name) {
- var def = defCache[name];
- if (def instanceof Def) {
- def.finalize();
- extend(allFields, def.allFields);
- extend(allSupertypes, def.allSupertypes);
- } else {
- var message = "unknown supertype name " +
- JSON.stringify(name) +
- " for subtype " +
- JSON.stringify(self.typeName);
- throw new Error(message);
+ self.fieldNames.length = 0;
+ for (var fieldName in allFields) {
+ if (hasOwn.call(allFields, fieldName) &&
+ !allFields[fieldName].hidden) {
+ self.fieldNames.push(fieldName);
+ }
}
- });
- // TODO Warn if fields are overridden with incompatible types.
- extend(allFields, self.ownFields);
- allSupertypes[self.typeName] = self;
+ // Types are exported only once they have been finalized.
+ Object.defineProperty(namedTypes, self.typeName, {
+ enumerable: true,
+ value: self.type
+ });
- self.fieldNames.length = 0;
- for (var fieldName in allFields) {
- if (hasOwn.call(allFields, fieldName) &&
- !allFields[fieldName].hidden) {
- self.fieldNames.push(fieldName);
+ Object.defineProperty(self, "finalized", {value: true});
+
+ // A linearization of the inheritance hierarchy.
+ populateSupertypeList(self.typeName, self.supertypeList);
+
+ if (self.buildable && self.supertypeList.lastIndexOf("Expression") >= 0) {
+ wrapExpressionBuilderWithStatement(self.typeName);
}
}
+ };
- // Types are exported only once they have been finalized.
- Object.defineProperty(namedTypes, self.typeName, {
- enumerable: true,
- value: self.type
- });
-
- Object.defineProperty(self, "finalized", { value: true });
+ // Adds an additional builder for Expression subtypes
+ // that wraps the built Expression in an ExpressionStatements.
+ function wrapExpressionBuilderWithStatement(typeName) {
+ var wrapperName = getStatementBuilderName(typeName);
- // A linearization of the inheritance hierarchy.
- populateSupertypeList(self.typeName, self.supertypeList);
+ // skip if the builder already exists
+ if (builders[wrapperName]) return;
- if (self.buildable && self.supertypeList.lastIndexOf("Expression") >= 0) {
- wrapExpressionBuilderWithStatement(self.typeName);
- }
- }
-};
+ // the builder function to wrap with builders.ExpressionStatement
+ var wrapped = builders[getBuilderName(typeName)];
-// Adds an additional builder for Expression subtypes
-// that wraps the built Expression in an ExpressionStatements.
-function wrapExpressionBuilderWithStatement(typeName) {
- var wrapperName = getStatementBuilderName(typeName);
+ // skip if there is nothing to wrap
+ if (!wrapped) return;
- // skip if the builder already exists
- if (builders[wrapperName]) return;
+ builders[wrapperName] = function () {
+ return builders.expressionStatement(wrapped.apply(builders, arguments));
+ };
+ }
- // the builder function to wrap with builders.ExpressionStatement
- var wrapped = builders[getBuilderName(typeName)];
+ function populateSupertypeList(typeName, list) {
+ list.length = 0;
+ list.push(typeName);
- // skip if there is nothing to wrap
- if (!wrapped) return;
+ var lastSeen = Object.create(null);
- builders[wrapperName] = function() {
- return builders.expressionStatement(wrapped.apply(builders, arguments));
- };
-}
+ for (var pos = 0; pos < list.length; ++pos) {
+ typeName = list[pos];
+ var d = defCache[typeName];
+ if (d.finalized !== true) {
+ throw new Error("");
+ }
-function populateSupertypeList(typeName, list) {
- list.length = 0;
- list.push(typeName);
+ // If we saw typeName earlier in the breadth-first traversal,
+ // delete the last-seen occurrence.
+ if (hasOwn.call(lastSeen, typeName)) {
+ delete list[lastSeen[typeName]];
+ }
- var lastSeen = Object.create(null);
+ // Record the new index of the last-seen occurrence of typeName.
+ lastSeen[typeName] = pos;
- for (var pos = 0; pos < list.length; ++pos) {
- typeName = list[pos];
- var d = defCache[typeName];
- if (d.finalized !== true) {
- throw new Error("");
+ // Enqueue the base names of this type.
+ list.push.apply(list, d.baseNames);
}
- // If we saw typeName earlier in the breadth-first traversal,
- // delete the last-seen occurrence.
- if (hasOwn.call(lastSeen, typeName)) {
- delete list[lastSeen[typeName]];
+ // Compaction loop to remove array holes.
+ for (var to = 0, from = to, len = list.length; from < len; ++from) {
+ if (hasOwn.call(list, from)) {
+ list[to++] = list[from];
+ }
}
- // Record the new index of the last-seen occurrence of typeName.
- lastSeen[typeName] = pos;
-
- // Enqueue the base names of this type.
- list.push.apply(list, d.baseNames);
- }
-
- // Compaction loop to remove array holes.
- for (var to = 0, from = to, len = list.length; from < len; ++from) {
- if (hasOwn.call(list, from)) {
- list[to++] = list[from];
- }
+ list.length = to;
}
- list.length = to;
-}
+ function extend(into, from) {
+ Object.keys(from).forEach(function (name) {
+ into[name] = from[name];
+ });
-function extend(into, from) {
- Object.keys(from).forEach(function(name) {
- into[name] = from[name];
- });
+ return into;
+ };
- return into;
-};
+ exports.finalize = function () {
+ Object.keys(defCache).forEach(function (name) {
+ defCache[name].finalize();
+ });
+ };
-exports.finalize = function() {
- Object.keys(defCache).forEach(function(name) {
- defCache[name].finalize();
- });
+ return exports;
};
diff --git a/main.js b/main.js
index 69f2493..571a15c 100644
--- a/main.js
+++ b/main.js
@@ -1,34 +1,16 @@
-var types = require("./lib/types");
+module.exports = require('./fork')([
+ // This core module of AST types captures ES5 as it is parsed today by
+ // git://github.com/ariya/esprima.git#master.
+ require("./def/core"),
-// This core module of AST types captures ES5 as it is parsed today by
-// git://github.com/ariya/esprima.git#master.
-require("./def/core");
-
-// Feel free to add to or remove from this list of extension modules to
-// configure the precise type hierarchy that you need.
-require("./def/es6");
-require("./def/es7");
-require("./def/mozilla");
-require("./def/e4x");
-require("./def/jsx");
-require("./def/flow");
-require("./def/esprima");
-require("./def/babel");
-
-types.finalize();
-
-exports.Type = types.Type;
-exports.builtInTypes = types.builtInTypes;
-exports.namedTypes = types.namedTypes;
-exports.builders = types.builders;
-exports.defineMethod = types.defineMethod;
-exports.getFieldNames = types.getFieldNames;
-exports.getFieldValue = types.getFieldValue;
-exports.eachField = types.eachField;
-exports.someField = types.someField;
-exports.getSupertypeNames = types.getSupertypeNames;
-exports.astNodesAreEquivalent = require("./lib/equiv");
-exports.finalize = types.finalize;
-exports.NodePath = require("./lib/node-path");
-exports.PathVisitor = require("./lib/path-visitor");
-exports.visit = exports.PathVisitor.visit;
+ // Feel free to add to or remove from this list of extension modules to
+ // configure the precise type hierarchy that you need.
+ require("./def/es6"),
+ require("./def/es7"),
+ require("./def/mozilla"),
+ require("./def/e4x"),
+ require("./def/jsx"),
+ require("./def/flow"),
+ require("./def/esprima"),
+ require("./def/babel")
+]);
\ No newline at end of file
diff --git a/package.json b/package.json
index e12bfcb..d1600ef 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"transformation",
"syntax"
],
- "version": "0.8.16",
+ "version": "0.9.0",
"homepage": "http://github.com/benjamn/ast-types",
"repository": {
"type": "git",
@@ -34,7 +34,7 @@
"babel-core": "^5.6.15",
"esprima": "~1.2.2",
"esprima-fb": "~14001.1.0-dev-harmony-fb",
- "mocha": "~2.2.5"
+ "mocha": "~2.5.3"
},
"engines": {
"node": ">= 0.8"
diff --git a/test/run.js b/test/run.js
index a2702ed..8590758 100644
--- a/test/run.js
+++ b/test/run.js
@@ -5,13 +5,13 @@ var b = types.builders;
var path = require("path");
var fs = require("fs");
var parse = require("esprima").parse;
-var Path = require("../lib/path");
-var NodePath = require("../lib/node-path");
-var PathVisitor = require("../lib/path-visitor");
-var builtin = types.builtInTypes
+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 = require("../lib/types");
+var rawTypes = types.use(require("../lib/types"));
var hasOwn = Object.prototype.hasOwnProperty;
@@ -64,7 +64,7 @@ describe("isSupertypeOf", function() {
describe("supertype lookup", function() {
it("should resolve the most precise supertypes", function() {
- var table = require("../lib/types").computeSupertypeLookupTable({
+ var table = types.use(require("../lib/types")).computeSupertypeLookupTable({
Function: true,
Declaration: true,
ArrowFunctionExpression: true,
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-ast-types.git
More information about the Pkg-javascript-commits
mailing list