[Pkg-javascript-commits] [node-recast] 01/05: Imported Upstream version 0.11.4
Julien Puydt
julien.puydt at laposte.net
Sun May 29 05:49:56 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-recast.
commit 293d25846103f32f7bece6f185b7d6ad245e04cc
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Sun May 29 07:43:01 2016 +0200
Imported Upstream version 0.11.4
---
.travis.yml | 4 +
README.md | 2 +-
lib/comments.js | 7 +-
lib/fast-path.js | 5 +
lib/options.js | 2 +-
lib/parser.js | 3 +
lib/printer.js | 335 +++++++++++++++++++++++++++-------------------------
lib/util.js | 115 ++++++++++++++----
package.json | 13 +-
test/babylon.js | 164 +++++++++++++++++++++++++
test/comments.js | 37 ++++++
test/es6tests.js | 6 +-
test/jsx.js | 89 +++++++-------
test/parens.js | 7 +-
test/parser.js | 4 +-
test/printer.js | 56 +++++++--
test/type-syntax.js | 176 +++++++++++++--------------
17 files changed, 689 insertions(+), 336 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 695586b..10219ea 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,5 +7,9 @@ node_js:
- "0.10"
- "0.8"
+matrix:
+ allow_failures:
+ - node_js: "0.8"
+
# Allow Travis tests to run in containers.
sudo: false
diff --git a/README.md b/README.md
index d4d7c19..7cb75c1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# recast, _v_. [![Build Status](https://travis-ci.org/benjamn/recast.png?branch=master)](https://travis-ci.org/benjamn/recast) [![Join the chat at https://gitter.im/benjamn/recast](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/benjamn/recast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# recast, _v_. [![Build Status](https://travis-ci.org/benjamn/recast.svg?branch=master)](https://travis-ci.org/benjamn/recast) [![Join the chat at https://gitter.im/benjamn/recast](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/benjamn/recast?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
1. to give (a metal object) a different form by melting it down and reshaping it.
1. to form, fashion, or arrange again.
diff --git a/lib/comments.js b/lib/comments.js
index 4247b6a..7a32b56 100644
--- a/lib/comments.js
+++ b/lib/comments.js
@@ -216,7 +216,7 @@ function breakTies(tiesToBreak, lines) {
(comment = tiesToBreak[indexOfFirstLeadingComment]) &&
// If the comment is a //-style comment and indented more
// deeply than the node itself, reconsider it as trailing.
- comment.type === "Line" &&
+ (comment.type === "Line" || comment.type === "CommentLine") &&
comment.loc.start.column > fn.loc.start.column) {
++indexOfFirstLeadingComment;
}
@@ -337,10 +337,11 @@ exports.printComments = function(path, print) {
var leading = types.getFieldValue(comment, "leading");
var trailing = types.getFieldValue(comment, "trailing");
- if (leading || (trailing && comment.type !== "Block")) {
+ if (leading || (trailing && !(n.Statement.check(value) ||
+ comment.type === "Block" ||
+ comment.type === "CommentBlock"))) {
leadingParts.push(printLeadingComment(commentPath, print));
} else if (trailing) {
- assert.strictEqual(comment.type, "Block");
trailingParts.push(printTrailingComment(commentPath, print));
}
}, "comments");
diff --git a/lib/fast-path.js b/lib/fast-path.js
index 1d97ab1..4f6ab77 100644
--- a/lib/fast-path.js
+++ b/lib/fast-path.js
@@ -319,6 +319,11 @@ FPp.needsParens = function(assumeExpressionContext) {
}
case "ArrowFunctionExpression":
+ if(parent.type === 'CallExpression' &&
+ name === 'callee') {
+ return true;
+ };
+
return isBinary(parent);
case "ObjectExpression":
diff --git a/lib/options.js b/lib/options.js
index 29ccccb..10f4520 100644
--- a/lib/options.js
+++ b/lib/options.js
@@ -2,7 +2,7 @@ var defaults = {
// If you want to use a different branch of esprima, or any other
// module that supports a .parse function, pass that module object to
// recast.parse as options.parser (legacy synonym: options.esprima).
- parser: require("esprima-fb"),
+ parser: require("esprima"),
// Number of spaces the pretty-printer should use per tab for
// indentation. If you do not pass this option explicitly, it will be
diff --git a/lib/parser.js b/lib/parser.js
index de589bd..fa2fef9 100644
--- a/lib/parser.js
+++ b/lib/parser.js
@@ -70,6 +70,8 @@ exports.parse = function parse(source, options) {
start: lines.firstPos(),
end: lines.lastPos()
};
+ } else if (file.type === "File") {
+ program = file.program;
}
// Passing file.program here instead of just file means that initial
@@ -124,6 +126,7 @@ TCp.copy = function(node) {
// of the comment. This only really matters for multiline Block
// comments, but it doesn't hurt for Line comments.
if (node.type === "Block" || node.type === "Line" ||
+ node.type === "CommentBlock" || node.type === "CommentLine" ||
this.lines.isPrecededOnlyByWhitespace(loc.start)) {
newIndent = this.indent = loc.start.column;
}
diff --git a/lib/printer.js b/lib/printer.js
index 5adc810..e44ef0f 100644
--- a/lib/printer.js
+++ b/lib/printer.js
@@ -156,7 +156,53 @@ function maybeAddParens(path, lines) {
function genericPrint(path, options, printPath) {
assert.ok(path instanceof FastPath);
- return maybeAddParens(path, genericPrintNoParens(path, options, printPath));
+
+ var node = path.getValue();
+ var parts = [];
+ var needsParens = false;
+ var linesWithoutParens =
+ genericPrintNoParens(path, options, printPath);
+
+ if (! node || linesWithoutParens.isEmpty()) {
+ return linesWithoutParens;
+ }
+
+ if (node.decorators &&
+ node.decorators.length > 0 &&
+ // If the parent node is an export declaration, it will be
+ // responsible for printing node.decorators.
+ ! util.getParentExportDeclaration(path)) {
+
+ path.each(function(decoratorPath) {
+ parts.push(printPath(decoratorPath), "\n");
+ }, "decorators");
+
+ } else if (util.isExportDeclaration(node) &&
+ node.declaration &&
+ node.declaration.decorators) {
+ // Export declarations are responsible for printing any decorators
+ // that logically apply to node.declaration.
+ path.each(function(decoratorPath) {
+ parts.push(printPath(decoratorPath), "\n");
+ }, "declaration", "decorators");
+
+ } else {
+ // Nodes with decorators can't have parentheses, so we can avoid
+ // computing path.needsParens() except in this case.
+ needsParens = path.needsParens();
+ }
+
+ if (needsParens) {
+ parts.unshift("(");
+ }
+
+ parts.push(linesWithoutParens);
+
+ if (needsParens) {
+ parts.push(")");
+ }
+
+ return concat(parts);
}
function genericPrintNoParens(path, options, print) {
@@ -172,6 +218,8 @@ function genericPrintNoParens(path, options, print) {
namedTypes.Printable.assert(n);
+ var parts = [];
+
switch (n.type) {
case "File":
return path.call(print, "program");
@@ -208,7 +256,7 @@ function genericPrintNoParens(path, options, print) {
]);
case "MemberExpression":
- var parts = [path.call(print, "object")];
+ parts.push(path.call(print, "object"));
var property = path.call(print, "property");
if (n.computed) {
@@ -227,8 +275,6 @@ function genericPrintNoParens(path, options, print) {
]);
case "BindExpression":
- var parts = [];
-
if (n.object) {
parts.push(path.call(print, "object"));
}
@@ -255,8 +301,6 @@ function genericPrintNoParens(path, options, print) {
case "FunctionDeclaration":
case "FunctionExpression":
- var parts = [];
-
if (n.async)
parts.push("async ");
@@ -285,15 +329,14 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "ArrowFunctionExpression":
- var parts = [];
-
if (n.async)
parts.push("async ");
if (
n.params.length === 1 &&
!n.rest &&
- n.params[0].type === 'Identifier'
+ n.params[0].type === 'Identifier' &&
+ !n.params[0].typeAnnotation
) {
parts.push(path.call(print, "params", 0));
} else {
@@ -309,8 +352,6 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "MethodDefinition":
- var parts = [];
-
if (n.static) {
parts.push("static ");
}
@@ -320,7 +361,7 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "YieldExpression":
- var parts = ["yield"];
+ parts.push("yield");
if (n.delegate)
parts.push("*");
@@ -331,7 +372,7 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "AwaitExpression":
- var parts = ["await"];
+ parts.push("await");
if (n.all)
parts.push("*");
@@ -342,7 +383,7 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "ModuleDeclaration":
- var parts = ["module", path.call(print, "id")];
+ parts.push("module", path.call(print, "id"));
if (n.source) {
assert.ok(!n.body);
@@ -354,8 +395,6 @@ function genericPrintNoParens(path, options, print) {
return fromString(" ").join(parts);
case "ImportSpecifier":
- var parts = [];
-
if (n.imported) {
parts.push(path.call(print, "imported"));
if (n.local &&
@@ -372,8 +411,6 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "ExportSpecifier":
- var parts = [];
-
if (n.local) {
parts.push(path.call(print, "local"));
if (n.exported &&
@@ -393,7 +430,7 @@ function genericPrintNoParens(path, options, print) {
return fromString("*");
case "ImportNamespaceSpecifier":
- var parts = ["* as "];
+ parts.push("* as ");
if (n.local) {
parts.push(path.call(print, "local"));
} else if (n.id) {
@@ -408,82 +445,23 @@ function genericPrintNoParens(path, options, print) {
return path.call(print, "id");
case "ExportDeclaration":
- var parts = ["export"];
-
- if (n["default"]) {
- parts.push(" default");
-
- } else if (n.specifiers &&
- n.specifiers.length > 0) {
-
- if (n.specifiers.length === 1 &&
- n.specifiers[0].type === "ExportBatchSpecifier") {
- parts.push(" *");
- } else {
- parts.push(
- " { ",
- fromString(", ").join(path.map(print, "specifiers")),
- " }"
- );
- }
-
- if (n.source)
- parts.push(" from ", path.call(print, "source"));
-
- parts.push(";");
-
- return concat(parts);
- }
-
- if (n.declaration) {
- var decLines = path.call(print, "declaration");
- parts.push(" ", decLines);
- if (lastNonSpaceCharacter(decLines) !== ";") {
- parts.push(";");
- }
- }
-
- return concat(parts);
-
case "ExportDefaultDeclaration":
- return concat([
- "export default ",
- path.call(print, "declaration")
- ]);
-
case "ExportNamedDeclaration":
- var parts = ["export "];
-
- if (n.declaration) {
- parts.push(path.call(print, "declaration"));
- }
-
- if (n.specifiers &&
- n.specifiers.length > 0) {
- parts.push(
- n.declaration ? ", {" : "{",
- fromString(", ").join(path.map(print, "specifiers")),
- "}"
- );
- }
-
- if (n.source) {
- parts.push(" from ", path.call(print, "source"));
- }
-
- return concat(parts);
+ return printExportDeclaration(path, options, print);
case "ExportAllDeclaration":
- var parts = ["export *"];
+ parts.push("export *");
if (n.exported) {
parts.push(" as ", path.call(print, "exported"));
}
- return concat([
+ parts.push(
" from ",
path.call(print, "source")
- ]);
+ );
+
+ return concat(parts);
case "ExportNamespaceSpecifier":
return concat(["* as ", path.call(print, "exported")]);
@@ -492,7 +470,7 @@ function genericPrintNoParens(path, options, print) {
return path.call(print, "exported");
case "ImportDeclaration":
- var parts = ["import "];
+ parts.push("import ");
if (n.importKind && n.importKind !== "value") {
parts.push(n.importKind + " ");
@@ -552,15 +530,13 @@ function genericPrintNoParens(path, options, print) {
]);
case "ReturnStatement":
- var parts = ["return"];
+ parts.push("return");
if (n.argument) {
var argLines = path.call(print, "argument");
if (argLines.length > 1 &&
- (namedTypes.XJSElement &&
- namedTypes.XJSElement.check(n.argument) ||
- namedTypes.JSXElement &&
- namedTypes.JSXElement.check(n.argument))) {
+ namedTypes.JSXElement &&
+ namedTypes.JSXElement.check(n.argument)) {
parts.push(
" (\n",
argLines.indent(options.tabWidth),
@@ -601,7 +577,7 @@ function genericPrintNoParens(path, options, print) {
});
var oneLine = (isTypeAnnotation && len === 1) || len === 0;
- var parts = [oneLine ? "{" : "{\n"];
+ parts.push(oneLine ? "{" : "{\n");
var i = 0;
fields.forEach(function(field) {
@@ -650,14 +626,6 @@ function genericPrintNoParens(path, options, print) {
return printMethod(path, options, print);
}
- var parts = [];
-
- if (n.decorators) {
- path.each(function(decoratorPath) {
- parts.push(print(decoratorPath), "\n");
- }, "decorators");
- }
-
var key = path.call(print, "key");
if (n.computed) {
parts.push("[", key, "]");
@@ -682,7 +650,7 @@ function genericPrintNoParens(path, options, print) {
var printed = path.map(print, "elements");
var joined = fromString(", ").join(printed);
var oneLine = joined.getLineLength(1) <= options.wrapColumn;
- var parts = [oneLine ? "[" : "[\n"];
+ parts.push(oneLine ? "[" : "[\n");
path.each(function(elemPath) {
var i = elemPath.getName();
@@ -741,14 +709,17 @@ function genericPrintNoParens(path, options, print) {
return fromString(nodeStr(n.value, options), options);
case "UnaryExpression":
- var parts = [n.operator];
+ parts.push(n.operator);
if (/[a-z]$/.test(n.operator))
parts.push(" ");
parts.push(path.call(print, "argument"));
return concat(parts);
case "UpdateExpression":
- var parts = [path.call(print, "argument"), n.operator];
+ parts.push(
+ path.call(print, "argument"),
+ n.operator
+ );
if (n.prefix)
parts.reverse();
@@ -763,7 +734,7 @@ function genericPrintNoParens(path, options, print) {
]);
case "NewExpression":
- var parts = ["new ", path.call(print, "callee")];
+ parts.push("new ", path.call(print, "callee"));
var args = n.arguments;
if (args) {
parts.push(printArgumentsList(path, options, print));
@@ -772,7 +743,7 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "VariableDeclaration":
- var parts = [n.kind, " "];
+ parts.push(n.kind, " ");
var maxLen = 0;
var printed = path.map(function(childPath) {
var lines = print(childPath);
@@ -907,14 +878,14 @@ function genericPrintNoParens(path, options, print) {
]);
case "BreakStatement":
- var parts = ["break"];
+ parts.push("break");
if (n.label)
parts.push(" ", path.call(print, "label"));
parts.push(";");
return concat(parts);
case "ContinueStatement":
- var parts = ["continue"];
+ parts.push("continue");
if (n.label)
parts.push(" ", path.call(print, "label"));
parts.push(";");
@@ -928,10 +899,10 @@ function genericPrintNoParens(path, options, print) {
]);
case "TryStatement":
- var parts = [
+ parts.push(
"try ",
path.call(print, "block")
- ];
+ );
if (n.handler) {
parts.push(" ", path.call(print, "handler"));
@@ -948,7 +919,7 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
case "CatchClause":
- var parts = ["catch (", path.call(print, "param")];
+ parts.push("catch (", path.call(print, "param"));
if (n.guard)
// Note: esprima does not recognize conditional catch clauses.
@@ -973,8 +944,6 @@ function genericPrintNoParens(path, options, print) {
// Note: ignoring n.lexical because it has no printing consequences.
case "SwitchCase":
- var parts = [];
-
if (n.test)
parts.push("case ", path.call(print, "test"), ":");
else
@@ -993,40 +962,33 @@ function genericPrintNoParens(path, options, print) {
// JSX extensions below.
- case "XJSAttribute":
case "JSXAttribute":
- var parts = [path.call(print, "name")];
+ parts.push(path.call(print, "name"));
if (n.value)
parts.push("=", path.call(print, "value"));
return concat(parts);
- case "XJSIdentifier":
case "JSXIdentifier":
return fromString(n.name, options);
- case "XJSNamespacedName":
case "JSXNamespacedName":
return fromString(":").join([
path.call(print, "namespace"),
path.call(print, "name")
]);
- case "XJSMemberExpression":
case "JSXMemberExpression":
return fromString(".").join([
path.call(print, "object"),
path.call(print, "property")
]);
- case "XJSSpreadAttribute":
case "JSXSpreadAttribute":
return concat(["{...", path.call(print, "argument"), "}"]);
- case "XJSExpressionContainer":
case "JSXExpressionContainer":
return concat(["{", path.call(print, "expression"), "}"]);
- case "XJSElement":
case "JSXElement":
var openingLines = path.call(print, "openingElement");
@@ -1041,11 +1003,7 @@ function genericPrintNoParens(path, options, print) {
if (namedTypes.Literal.check(child) &&
typeof child.value === "string") {
- if (/\S/.test(child.value)) {
- return child.value.replace(/^\s+|\s+$/g, "");
- } else if (/\n/.test(child.value)) {
- return "\n";
- }
+ return child.value;
}
return print(childPath);
@@ -1060,9 +1018,8 @@ function genericPrintNoParens(path, options, print) {
closingLines
]);
- case "XJSOpeningElement":
case "JSXOpeningElement":
- var parts = ["<", path.call(print, "name")];
+ parts.push("<", path.call(print, "name"));
var attrParts = [];
path.each(function(attrPath) {
@@ -1091,15 +1048,12 @@ function genericPrintNoParens(path, options, print) {
return concat(parts);
- case "XJSClosingElement":
case "JSXClosingElement":
return concat(["</", path.call(print, "name"), ">"]);
- case "XJSText":
case "JSXText":
return fromString(n.value, options);
- case "XJSEmptyExpression":
case "JSXEmptyExpression":
return fromString("");
@@ -1124,13 +1078,12 @@ function genericPrintNoParens(path, options, print) {
]);
case "ClassPropertyDefinition":
- var parts = ["static ", path.call(print, "definition")];
+ parts.push("static ", path.call(print, "definition"));
if (!namedTypes.MethodDefinition.check(n.definition))
parts.push(";");
return concat(parts);
case "ClassProperty":
- var parts = [];
if (n.static)
parts.push("static ");
@@ -1146,14 +1099,6 @@ function genericPrintNoParens(path, options, print) {
case "ClassDeclaration":
case "ClassExpression":
- var parts = [];
-
- if (n.decorators) {
- path.each(function(decoratorPath) {
- parts.push(print(decoratorPath), "\n");
- }, "decorators");
- }
-
parts.push("class");
if (n.id) {
@@ -1172,7 +1117,7 @@ function genericPrintNoParens(path, options, print) {
);
}
- if (n["implements"]) {
+ if (n["implements"] && n['implements'].length > 0) {
parts.push(
" implements ",
fromString(", ").join(path.map(print, "implements"))
@@ -1188,7 +1133,7 @@ function genericPrintNoParens(path, options, print) {
case "TemplateLiteral":
var expressions = path.map(print, "expressions");
- var parts = ["`"];
+ parts.push("`");
path.each(function(childPath) {
var i = childPath.getName();
@@ -1238,8 +1183,6 @@ function genericPrintNoParens(path, options, print) {
// Type Annotations for Facebook Flow, typically stripped out or
// transformed away before printing.
case "TypeAnnotation":
- var parts = [];
-
if (n.typeAnnotation) {
if (n.typeAnnotation.type !== "FunctionTypeAnnotation") {
parts.push(": ");
@@ -1270,40 +1213,45 @@ function genericPrintNoParens(path, options, print) {
return fromString("" + n.value, options);
case "DeclareClass":
- return concat([
- fromString("declare class ", options),
+ return printFlowDeclaration(path, [
+ "class ",
path.call(print, "id"),
" ",
path.call(print, "body"),
]);
case "DeclareFunction":
- return concat([
- fromString("declare function ", options),
+ return printFlowDeclaration(path, [
+ "function ",
path.call(print, "id"),
";"
]);
case "DeclareModule":
- return concat([
- fromString("declare module ", options),
+ return printFlowDeclaration(path, [
+ "module ",
path.call(print, "id"),
" ",
path.call(print, "body"),
]);
case "DeclareVariable":
- return concat([
- fromString("declare var ", options),
+ return printFlowDeclaration(path, [
+ "var ",
path.call(print, "id"),
";"
]);
+ case "DeclareExportDeclaration":
+ return concat([
+ "declare ",
+ printExportDeclaration(path, options, print)
+ ]);
+
case "FunctionTypeAnnotation":
// FunctionTypeAnnotation is ambiguous:
// declare function(a: B): void; OR
// var A: (a: B) => void;
- var parts = [];
var parent = path.getParentNode(0);
var isArrowFunctionTypeAnnotation = !(
namedTypes.ObjectTypeCallProperty.check(parent) ||
@@ -1338,6 +1286,7 @@ function genericPrintNoParens(path, options, print) {
case "FunctionTypeParam":
return concat([
path.call(print, "name"),
+ n.optional ? '?' : '',
": ",
path.call(print, "typeAnnotation"),
]);
@@ -1348,13 +1297,16 @@ function genericPrintNoParens(path, options, print) {
path.call(print, "typeParameters")
]);
+ case "DeclareInterface":
+ parts.push("declare ");
+
case "InterfaceDeclaration":
- var parts = [
+ parts.push(
fromString("interface ", options),
path.call(print, "id"),
path.call(print, "typeParameters"),
" "
- ];
+ );
if (n["extends"]) {
parts.push(
@@ -1383,6 +1335,12 @@ function genericPrintNoParens(path, options, print) {
path.call(print, "typeAnnotation")
]);
+ case "NullLiteralTypeAnnotation":
+ return fromString("null", options);
+
+ case "ThisTypeAnnotation":
+ return fromString("this", options);
+
case "NumberTypeAnnotation":
return fromString("number", options);
@@ -1423,6 +1381,9 @@ function genericPrintNoParens(path, options, print) {
case "StringTypeAnnotation":
return fromString("string", options);
+ case "DeclareTypeAlias":
+ parts.push("declare ");
+
case "TypeAlias":
return concat([
"type ",
@@ -1645,12 +1606,6 @@ function printMethod(path, options, print) {
namedTypes.FunctionExpression.assert(node.value);
- if (node.decorators) {
- path.each(function(decoratorPath) {
- parts.push(print(decoratorPath), "\n");
- }, "decorators");
- }
-
if (node.value.async) {
parts.push("async ");
}
@@ -1734,6 +1689,66 @@ function printFunctionParams(path, options, print) {
return joined;
}
+function printExportDeclaration(path, options, print) {
+ var decl = path.getValue();
+ var parts = ["export "];
+
+ namedTypes.Declaration.assert(decl);
+
+ if (decl["default"] ||
+ decl.type === "ExportDefaultDeclaration") {
+ parts.push("default ");
+ }
+
+ if (decl.declaration) {
+ parts.push(path.call(print, "declaration"));
+
+ } else if (decl.specifiers &&
+ decl.specifiers.length > 0) {
+
+ if (decl.specifiers.length === 1 &&
+ decl.specifiers[0].type === "ExportBatchSpecifier") {
+ parts.push("*");
+ } else {
+ parts.push(
+ "{",
+ fromString(", ").join(path.map(print, "specifiers")),
+ "}"
+ );
+ }
+
+ if (decl.source) {
+ parts.push(" from ", path.call(print, "source"));
+ }
+ }
+
+ var lines = concat(parts);
+
+ if (lastNonSpaceCharacter(lines) !== ";") {
+ lines = concat([lines, ";"]);
+ }
+
+ return lines;
+}
+
+function printFlowDeclaration(path, parts) {
+ var parentExportDecl = util.getParentExportDeclaration(path);
+
+ if (parentExportDecl) {
+ assert.strictEqual(
+ parentExportDecl.type,
+ "DeclareExportDeclaration"
+ );
+ } else {
+ // If the parent node has type DeclareExportDeclaration, then it
+ // will be responsible for printing the "declare" token. Otherwise
+ // it needs to be printed with this non-exported declaration node.
+ parts.unshift("declare ");
+ }
+
+ return concat(parts);
+}
+
function adjustClause(clause, options) {
if (clause.length > 1)
return concat([" ", clause]);
diff --git a/lib/util.js b/lib/util.js
index 5497f86..f78cdaa 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -6,6 +6,7 @@ var sourceMap = require("source-map");
var SourceMapConsumer = sourceMap.SourceMapConsumer;
var SourceMapGenerator = sourceMap.SourceMapGenerator;
var hasOwn = Object.prototype.hasOwnProperty;
+var util = exports;
function getUnionOfKeys() {
var result = {};
@@ -19,12 +20,12 @@ function getUnionOfKeys() {
}
return result;
}
-exports.getUnionOfKeys = getUnionOfKeys;
+util.getUnionOfKeys = getUnionOfKeys;
function comparePos(pos1, pos2) {
return (pos1.line - pos2.line) || (pos1.column - pos2.column);
}
-exports.comparePos = comparePos;
+util.comparePos = comparePos;
function copyPos(pos) {
return {
@@ -32,9 +33,9 @@ function copyPos(pos) {
column: pos.column
};
}
-exports.copyPos = copyPos;
+util.copyPos = copyPos;
-exports.composeSourceMaps = function(formerMap, latterMap) {
+util.composeSourceMaps = function(formerMap, latterMap) {
if (formerMap) {
if (!latterMap) {
return formerMap;
@@ -83,7 +84,7 @@ exports.composeSourceMaps = function(formerMap, latterMap) {
return smg.toJSON();
};
-exports.getTrueLoc = function(node, lines) {
+util.getTrueLoc = function(node, lines) {
// It's possible that node is newly-created (not parsed by Esprima),
// in which case it probably won't have a .loc property (or an
// .original property for that matter). That's fine; we'll just
@@ -92,42 +93,58 @@ exports.getTrueLoc = function(node, lines) {
return null;
}
- var start = node.loc.start;
- var end = node.loc.end;
+ var result = {
+ start: node.loc.start,
+ end: node.loc.end
+ };
+
+ function include(node) {
+ expandLoc(result, node.loc);
+ }
// If the node has any comments, their locations might contribute to
// the true start/end positions of the node.
if (node.comments) {
- node.comments.forEach(function(comment) {
- if (comment.loc) {
- if (comparePos(comment.loc.start, start) < 0) {
- start = comment.loc.start;
- }
-
- if (comparePos(end, comment.loc.end) < 0) {
- end = comment.loc.end;
- }
- }
- });
+ node.comments.forEach(include);
+ }
+
+ // If the node is an export declaration and its .declaration has any
+ // decorators, their locations might contribute to the true start/end
+ // positions of the export declaration node.
+ if (util.isExportDeclaration(node) &&
+ node.declaration.decorators) {
+ node.declaration.decorators.forEach(include);
}
- if (comparePos(start, end) < 0) {
+ if (comparePos(result.start, result.end) < 0) {
// Trim leading whitespace.
- start = copyPos(start);
- lines.skipSpaces(start, false, true);
+ result.start = copyPos(result.start);
+ lines.skipSpaces(result.start, false, true);
- if (comparePos(start, end) < 0) {
+ if (comparePos(result.start, result.end) < 0) {
// Trim trailing whitespace, if the end location is not already the
// same as the start location.
- end = copyPos(end);
- lines.skipSpaces(end, true, true);
+ result.end = copyPos(result.end);
+ lines.skipSpaces(result.end, true, true);
}
}
- return { start: start, end: end };
+ return result;
};
-exports.fixFaultyLocations = function(node, lines) {
+function expandLoc(parentLoc, childLoc) {
+ if (parentLoc && childLoc) {
+ if (comparePos(childLoc.start, parentLoc.start) < 0) {
+ parentLoc.start = childLoc.start;
+ }
+
+ if (comparePos(parentLoc.end, childLoc.end) < 0) {
+ parentLoc.end = childLoc.end;
+ }
+ }
+}
+
+util.fixFaultyLocations = function(node, lines) {
var loc = node.loc;
if (loc) {
if (loc.start.line < 1) {
@@ -141,6 +158,28 @@ exports.fixFaultyLocations = function(node, lines) {
if (node.type === "TemplateLiteral") {
fixTemplateLiteral(node, lines);
+
+ } else if (loc && node.decorators) {
+ // Expand the .loc of the node responsible for printing the decorators
+ // (here, the decorated node) so that it includes node.decorators.
+ node.decorators.forEach(function (decorator) {
+ expandLoc(loc, decorator.loc);
+ });
+
+ } else if (node.declaration && util.isExportDeclaration(node)) {
+ // Nullify .loc information for the child declaration so that we never
+ // try to reprint it without also reprinting the export declaration.
+ node.declaration.loc = null;
+
+ // Expand the .loc of the node responsible for printing the decorators
+ // (here, the export declaration) so that it includes node.decorators.
+ var decorators = node.declaration.decorators;
+ if (decorators) {
+ decorators.forEach(function (decorator) {
+ expandLoc(loc, decorator.loc);
+ });
+ }
+
} else if ((n.MethodDefinition && n.MethodDefinition.check(node)) ||
(n.Property.check(node) && (node.method || node.shorthand))) {
// If the node is a MethodDefinition or a .method or .shorthand
@@ -218,3 +257,27 @@ function fixTemplateLiteral(node, lines) {
}
});
}
+
+util.isExportDeclaration = function (node) {
+ if (node) switch (node.type) {
+ case "ExportDeclaration":
+ case "ExportDefaultDeclaration":
+ case "ExportDefaultSpecifier":
+ case "DeclareExportDeclaration":
+ case "ExportNamedDeclaration":
+ case "ExportAllDeclaration":
+ return true;
+ }
+
+ return false;
+};
+
+util.getParentExportDeclaration = function (path) {
+ var parentNode = path.getParentNode();
+ if (path.getName() === "declaration" &&
+ util.isExportDeclaration(parentNode)) {
+ return parentNode;
+ }
+
+ return null;
+};
diff --git a/package.json b/package.json
index 15c07ba..b87bb3b 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"parsing",
"pretty-printing"
],
- "version": "0.10.39",
+ "version": "0.11.4",
"homepage": "http://github.com/benjamn/recast",
"repository": {
"type": "git",
@@ -24,13 +24,18 @@
"test": "node ./node_modules/mocha/bin/mocha --reporter spec --full-trace",
"debug": "node ./node_modules/mocha/bin/mocha --debug-brk --reporter spec"
},
+ "browser": {
+ "fs": false
+ },
"dependencies": {
- "esprima-fb": "~15001.1001.0-dev-harmony-fb",
- "source-map": "~0.5.0",
+ "ast-types": "0.8.16",
+ "esprima": "~2.7.1",
"private": "~0.1.5",
- "ast-types": "0.8.12"
+ "source-map": "~0.5.0"
},
"devDependencies": {
+ "babylon": "~6.4.2",
+ "esprima-fb": "^15001.1001.0-dev-harmony-fb",
"mocha": "~2.2.5"
},
"engines": {
diff --git a/test/babylon.js b/test/babylon.js
new file mode 100644
index 0000000..319474e
--- /dev/null
+++ b/test/babylon.js
@@ -0,0 +1,164 @@
+var assert = require("assert");
+var recast = require("../main.js");
+var n = recast.types.namedTypes;
+var b = recast.types.builders;
+var eol = require("os").EOL;
+
+describe("decorators", function () {
+ var babylon = require("babylon");
+ var babylonOptions = {
+ sourceType: 'module',
+ allowImportExportEverywhere: false,
+ allowReturnOutsideFunction: false,
+ plugins: [
+ 'asyncFunctions',
+ 'asyncGenerators',
+ 'classConstructorCall',
+ 'classProperties',
+ 'decorators',
+ 'doExpressions',
+ 'exponentiationOperator',
+ 'exportExtensions',
+ 'flow',
+ 'functionSent',
+ 'functionBind',
+ 'jsx',
+ 'objectRestSpread',
+ 'trailingFunctionCommas'
+ ]
+ };
+
+ var parseOptions = {
+ parser: {
+ parse: function (source) {
+ return babylon.parse(source, babylonOptions);
+ }
+ }
+ };
+
+ it("should not disappear when surrounding code changes", function () {
+ var code = [
+ 'import foo from "foo";',
+ 'import React from "react";',
+ '',
+ '@component',
+ '@callExpression({foo: "bar"})',
+ 'class DebugPanel extends React.Component {',
+ ' render() {',
+ ' return (',
+ ' <div> test </div>',
+ ' );',
+ ' }',
+ '}',
+ '',
+ 'export default DebugPanel;',
+ ].join(eol);
+
+ var ast = recast.parse(code, parseOptions);
+
+ assert.strictEqual(recast.print(ast).code, code);
+
+ var root = new recast.types.NodePath(ast);
+ var reactImportPath = root.get("program", "body", 1);
+ n.ImportDeclaration.assert(reactImportPath.value);
+
+ // Remove the second import statement.
+ reactImportPath.prune();
+
+ var reprinted = recast.print(ast).code;
+
+ assert.ok(reprinted.match(/@component/));
+ assert.ok(reprinted.match(/@callExpression/));
+
+ assert.strictEqual(
+ reprinted,
+ code.split(eol).filter(function (line) {
+ return ! line.match(/^import React from/);
+ }).join(eol)
+ );
+ });
+
+ it("should not disappear when an import is added and `export` is used inline", function () {
+ var code = [
+ 'import foo from "foo";',
+ 'import React from "react";',
+ '',
+ '@component',
+ '@callExpression({foo: "bar"})',
+ '@callExpressionMultiLine({',
+ ' foo: "bar",',
+ '})',
+ 'export class DebugPanel extends React.Component {',
+ ' render() {',
+ ' return (',
+ ' <div> test </div>',
+ ' );',
+ ' }',
+ '}',
+ ].join(eol);
+
+ var ast = recast.parse(code, parseOptions);
+
+ assert.strictEqual(recast.print(ast).code, code);
+
+ var root = new recast.types.NodePath(ast);
+ var body = root.get("program", "body");
+
+ // add a new import statement
+ body.unshift(b.importDeclaration([
+ b.importDefaultSpecifier(b.identifier('x')),
+ ], b.literal('x')));
+
+ var reprinted = recast.print(ast).code;
+
+ assert.ok(reprinted.match(/@component/));
+ assert.ok(reprinted.match(/@callExpression/));
+
+ assert.strictEqual(
+ reprinted,
+ ['import x from "x";'].concat(code.split(eol)).join(eol)
+ );
+ });
+
+ it("should not disappear when an import is added and `export default` is used inline", function () {
+ var code = [
+ 'import foo from "foo";',
+ 'import React from "react";',
+ '',
+ '@component',
+ '@callExpression({foo: "bar"})',
+ '@callExpressionMultiLine({',
+ ' foo: "bar",',
+ '})',
+ 'export default class DebugPanel extends React.Component {',
+ ' render() {',
+ ' return (',
+ ' <div> test </div>',
+ ' );',
+ ' }',
+ '}',
+ ].join(eol);
+
+ var ast = recast.parse(code, parseOptions);
+
+ assert.strictEqual(recast.print(ast).code, code);
+
+ var root = new recast.types.NodePath(ast);
+ var body = root.get("program", "body");
+
+ // add a new import statement
+ body.unshift(b.importDeclaration([
+ b.importDefaultSpecifier(b.identifier('x')),
+ ], b.literal('x')));
+
+ var reprinted = recast.print(ast).code;
+
+ assert.ok(reprinted.match(/@component/));
+ assert.ok(reprinted.match(/@callExpression/));
+
+ assert.strictEqual(
+ reprinted,
+ ['import x from "x";'].concat(code.split(eol)).join(eol)
+ );
+ });
+});
diff --git a/test/comments.js b/test/comments.js
index cd4051c..d7abfe3 100644
--- a/test/comments.js
+++ b/test/comments.js
@@ -220,6 +220,43 @@ describe("comments", function() {
assert.strictEqual(actual, expected);
});
+ var statementTrailing = [
+ "if (true) {",
+ " f();",
+ " // trailing 1",
+ " /* trailing 2 */",
+ " // trailing 3",
+ " /* trailing 4 */",
+ "}"
+ ];
+
+ var statementTrailingExpected = [
+ "if (true) {",
+ " e();",
+ " f();",
+ " // trailing 1",
+ " /* trailing 2 */",
+ " // trailing 3",
+ " /* trailing 4 */",
+ "}"
+ ];
+
+ it("StatementTrailingComments", function() {
+ var code = statementTrailing.join(eol);
+ var ast = recast.parse(code);
+
+ var block = ast.program.body[0].consequent;
+ n.BlockStatement.assert(block);
+
+ block.body.unshift(b.expressionStatement(
+ b.callExpression(b.identifier("e"), [])));
+
+ var actual = recast.print(ast, { tabWidth: 2 }).code;
+ var expected = statementTrailingExpected.join(eol);
+
+ assert.strictEqual(actual, expected);
+ });
+
var protoAssign = [
"A.prototype.foo = function() {",
" return this.bar();",
diff --git a/test/es6tests.js b/test/es6tests.js
index 4203154..87af3a2 100644
--- a/test/es6tests.js
+++ b/test/es6tests.js
@@ -152,7 +152,7 @@ describe("import/export syntax", function() {
// const variables must have an initializer
checkInvalid(
"export const bar;",
- "Const must be initialized"
+ "Unexpected token ;"
);
// Unexpected token identifier, invalid named export syntax
@@ -188,7 +188,7 @@ describe("import/export syntax", function() {
// Invalid module specifier
checkInvalid(
"import foo from bar;",
- "Invalid module specifier"
+ "Unexpected token"
);
// Unexpected token default
@@ -224,7 +224,7 @@ describe("import/export syntax", function() {
// Missing as after import *
checkInvalid(
"import * from 'foo';",
- "Missing as after import *"
+ "Unexpected token"
);
// Unexpected token =
diff --git a/test/jsx.js b/test/jsx.js
index 7205b9e..5569b48 100644
--- a/test/jsx.js
+++ b/test/jsx.js
@@ -3,45 +3,52 @@ var Printer = require("../lib/printer").Printer;
var types = require("../lib/types");
describe("JSX Compatability", function() {
- var printer = new Printer({ tabWidth: 2 });
-
- function check(source) {
- var ast1 = parse(source);
- var ast2 = parse(printer.printGenerically(ast1).code);
- types.astNodesAreEquivalent.assert(ast1, ast2);
- }
-
- it("should parse and print attribute comments", function() {
- check("<b /* comment */ />");
- check("<b /* multi\nline\ncomment */ />");
- });
-
- it("should parse and print child comments", function() {
- check("<b>{/* comment */}</b>");
- check("<b>{/* multi\nline\ncomment */}</b>");
- });
-
- it("should parse and print literal attributes", function() {
- check("<b className=\"hello\" />");
- });
-
- it("should parse and print expression attributes", function() {
- check("<b className={classes} />");
- });
-
- it("should parse and print chidren", function() {
- check("<label><input /></label>");
- });
-
- it("should parse and print literal chidren", function() {
- check("<b>hello world</b>");
- });
-
- it("should parse and print expression children", function() {
- check("<b>{this.props.user.name}</b>");
- });
-
- it("should parse and print namespaced elements", function() {
- check("<Foo.Bar />");
- });
+ var printer = new Printer({ tabWidth: 2 });
+ var parseOptions = {
+ parser: require("esprima-fb")
+ };
+
+ function check(source) {
+ var ast1 = parse(source, parseOptions);
+ var ast2 = parse(printer.printGenerically(ast1).code, parseOptions);
+ types.astNodesAreEquivalent.assert(ast1, ast2);
+ }
+
+ it("should parse and print attribute comments", function() {
+ check("<b /* comment */ />");
+ check("<b /* multi\nline\ncomment */ />");
+ });
+
+ it("should parse and print child comments", function() {
+ check("<b>{/* comment */}</b>");
+ check("<b>{/* multi\nline\ncomment */}</b>");
+ });
+
+ it("should parse and print literal attributes", function() {
+ check("<b className=\"hello\" />");
+ });
+
+ it("should parse and print expression attributes", function() {
+ check("<b className={classes} />");
+ });
+
+ it("should parse and print chidren", function() {
+ check("<label><input /></label>");
+ });
+
+ it("should parse and print literal chidren", function() {
+ check("<b>hello world</b>");
+ });
+
+ it("should parse and print expression children", function() {
+ check("<b>{this.props.user.name}</b>");
+ });
+
+ it("should parse and print namespaced elements", function() {
+ check("<Foo.Bar />");
+ });
+
+ it('should parse and print string literal children with leading and trailing whitespace', function () {
+ check("<div>Hello, {name} and {name2}.</div>");
+ });
});
diff --git a/test/parens.js b/test/parens.js
index d9764d3..5fd5211 100644
--- a/test/parens.js
+++ b/test/parens.js
@@ -1,5 +1,5 @@
var assert = require("assert");
-var esprima = require("esprima-fb");
+var esprima = require("esprima");
var parse = require("../lib/parser").parse;
var Printer = require("../lib/printer").Printer;
var NodePath = require("ast-types").NodePath;
@@ -271,4 +271,9 @@ describe("parens", function() {
code
);
});
+
+ it("should be added to callees that are function expressions", function() {
+ check("(()=>{})()");
+ check("(function(){})()");
+ });
});
diff --git a/test/parser.js b/test/parser.js
index d729bbf..5839460 100644
--- a/test/parser.js
+++ b/test/parser.js
@@ -27,8 +27,8 @@ describe("parser", function() {
check("/* block comment */");
check("// line comment");
check("\t\t\t");
- check("\n");
- check("\n\n");
+ check(eol);
+ check(eol + eol);
check(" ");
});
diff --git a/test/printer.js b/test/printer.js
index 01d0710..90528fc 100644
--- a/test/printer.js
+++ b/test/printer.js
@@ -807,7 +807,10 @@ describe("printer", function() {
"});"
].join(eol);
- var ast = parse(code);
+ var ast = parse(code, {
+ // Supports trailing commas whereas plain esprima does not.
+ parser: require("esprima-fb")
+ });
var printer = new Printer({
tabWidth: 2,
@@ -826,7 +829,10 @@ describe("printer", function() {
");"
].join(eol);
- var ast = parse(code);
+ var ast = parse(code, {
+ // Supports trailing commas whereas plain esprima does not.
+ parser: require("esprima-fb")
+ });
var printer = new Printer({
tabWidth: 2,
@@ -846,7 +852,10 @@ describe("printer", function() {
"];"
].join(eol);
- var ast = parse(code);
+ var ast = parse(code, {
+ // Supports trailing commas whereas plain esprima does not.
+ parser: require("esprima-fb")
+ });
var printer = new Printer({
tabWidth: 2,
@@ -866,7 +875,10 @@ describe("printer", function() {
") {}"
].join(eol);
- var ast = parse(code);
+ var ast = parse(code, {
+ // Supports trailing commas whereas plain esprima does not.
+ parser: require("esprima-fb")
+ });
var printer = new Printer({
tabWidth: 2,
@@ -885,7 +897,12 @@ describe("printer", function() {
"}"
].join(eol);
- var ast = parse(code);
+ var ast = parse(code, {
+ // Supports rest parameter destructuring whereas plain esprima
+ // does not.
+ parser: require("esprima-fb")
+ });
+
var printer = new Printer({
tabWidth: 2
});
@@ -975,6 +992,29 @@ describe("printer", function() {
assert.strictEqual(pretty, code);
});
+ it("adds parenthesis around arrow functions with single arg and a type", function() {
+ var code = "(a: b) => {};";
+
+ var arg = b.identifier('a');
+ arg.typeAnnotation = b.typeAnnotation(
+ b.genericTypeAnnotation(b.identifier('b'), null)
+ );
+
+ var fn = b.arrowFunctionExpression(
+ [arg],
+ b.blockStatement([]),
+ false
+ );
+
+ var ast = b.program([
+ b.expressionStatement(fn)
+ ]);
+
+ var printer = new Printer();
+ var pretty = printer.printGenerically(ast).code;
+ assert.strictEqual(pretty, code);
+ });
+
it("prints ClassProperty correctly", function() {
var code = [
"class A {",
@@ -1122,7 +1162,7 @@ describe("printer", function() {
var ast = parse(code, {
esprima: {
parse: function(source, options) {
- var program = require("esprima-fb").parse(source, options);
+ var program = require("esprima").parse(source, options);
n.Program.assert(program);
// Expand ast.program.loc to include any
// leading/trailing whitespace, to simulate the
@@ -1178,7 +1218,7 @@ describe("printer", function() {
" }",
" `",
"};",
- ].join("\n");
+ ].join(eol);
var ast = parse(code);
var pretty = printer.printGenerically(ast).code;
@@ -1204,7 +1244,7 @@ describe("printer", function() {
"<~ This line should not be indented.",
" `, // 2 extraneous spaces.",
"};"
- ].join("\n");
+ ].join(eol);
var ast = parse(code);
var printer = new Printer({
diff --git a/test/type-syntax.js b/test/type-syntax.js
index f84391a..87e9fdd 100644
--- a/test/type-syntax.js
+++ b/test/type-syntax.js
@@ -7,90 +7,94 @@ var b = types.builders;
var eol = require("os").EOL;
describe("type syntax", function() {
- var printer = new Printer({ tabWidth: 2, quote: 'single' });
-
- function check(source) {
- var ast1 = parse(source);
- var code = printer.printGenerically(ast1).code;
- var ast2 = parse(code);
- types.astNodesAreEquivalent.assert(ast1, ast2);
- assert.strictEqual(source, code);
- }
-
- it("should parse and print type annotations correctly", function() {
- // Import type annotations
- check("import type foo from 'foo';");
- check("import typeof foo from 'foo';");
-
- // Scalar type annotations
- check("var a: number;");
- check("var a: number = 5;");
-
- check("var a: any;");
- check("var a: boolean;");
- check("var a: string;");
- check("var a: 'foo';");
- check("var a: void;");
-
- // Nullable
- check("var a: ?number;");
-
- // Unions & Intersections
- check("var a: number | string | boolean = 26;");
- check("var a: number & string & boolean = 26;");
-
- // Types
- check("var a: A = 5;");
- // TODO!?
- check("var a: typeof A;");
-
- // Type aliases
- check("type A = B;");
- check("type A = B.C;");
-
- // Generic
- check("var a: Array<Foo>;");
- check("var a: number[];");
-
- // Return types
- check("function a(): number {}");
- check("var a: () => X = fn;");
-
- // Object
- check("var a: {" + eol + " b: number;" + eol + " x: {y: A};" + eol + "};");
- check("var b: {[key: string]: number};")
- check("var c: {(): number};")
- check("var d: {" + eol + " [key: string]: A;" + eol + " [key: number]: B;" + eol + " (): C;" + eol + " a: D;" + eol + "};")
-
- // Casts
- check("(1 + 1: number);");
-
- // Declare
- check("declare var A: string;");
-
- check("declare function foo(c: C): void;");
- check("declare function foo(c: C, b: B): void;");
- check("declare function foo(c: (e: Event) => void, b: B): void;");
- check("declare class C {x: string}");
- check("declare module M {" + eol + " declare function foo(c: C): void;" + eol + "}");
-
- // Classes
- check("class A {" + eol + " a: number;" + eol + "}");
- check("class A {" + eol + " foo(a: number): string {}" + eol + "}");
- check("class A {" + eol + " static foo(a: number): string {}" + eol + "}");
-
- // Type parameters
- check("class A<T> {}");
- check("class A<X, Y> {}");
- check("class A<X> extends B<Y> {}");
- check("function a<T>(y: Y<T>): T {}");
- check("class A {" + eol + " foo<T>(a: number): string {}" + eol + "}");
-
- // Interfaces
- check("interface A<X> extends B<A>, C {a: number}");
- check("class A extends B implements C<T>, Y {}");
-
- // Bounded polymorphism
- check("class A<T: number> {}");
- });
+ var printer = new Printer({ tabWidth: 2, quote: 'single' });
+ var parseOptions = {
+ parser: require("esprima-fb")
+ };
+
+ function check(source) {
+ var ast1 = parse(source, parseOptions);
+ var code = printer.printGenerically(ast1).code;
+ var ast2 = parse(code, parseOptions);
+ types.astNodesAreEquivalent.assert(ast1, ast2);
+ assert.strictEqual(source, code);
+ }
+
+ it("should parse and print type annotations correctly", function() {
+ // Import type annotations
+ check("import type foo from 'foo';");
+ check("import typeof foo from 'foo';");
+
+ // Scalar type annotations
+ check("var a: number;");
+ check("var a: number = 5;");
+
+ check("var a: any;");
+ check("var a: boolean;");
+ check("var a: string;");
+ check("var a: 'foo';");
+ check("var a: void;");
+
+ // Nullable
+ check("var a: ?number;");
+
+ // Unions & Intersections
+ check("var a: number | string | boolean = 26;");
+ check("var a: number & string & boolean = 26;");
+
+ // Types
+ check("var a: A = 5;");
+ // TODO!?
+ check("var a: typeof A;");
+
+ // Type aliases
+ check("type A = B;");
+ check("type A = B.C;");
+
+ // Generic
+ check("var a: Array<Foo>;");
+ check("var a: number[];");
+
+ // Return types
+ check("function a(): number {}");
+ check("var a: () => X = fn;");
+
+ // Object
+ check("var a: {" + eol + " b: number;" + eol + " x: {y: A};" + eol + "};");
+ check("var b: {[key: string]: number};")
+ check("var c: {(): number};")
+ check("var d: {" + eol + " [key: string]: A;" + eol + " [key: number]: B;" + eol + " (): C;" + eol + " a: D;" + eol + "};")
+
+ // Casts
+ check("(1 + 1: number);");
+
+ // Declare
+ check("declare var A: string;");
+
+ check("declare function foo(c: C): void;");
+ check("declare function foo(c: C, b: B): void;");
+ check("declare function foo(c: (e: Event) => void, b: B): void;");
+ check("declare function foo(c: C, d?: Array<D>): void;");
+ check("declare class C {x: string}");
+ check("declare module M {" + eol + " declare function foo(c: C): void;" + eol + "}");
+
+ // Classes
+ check("class A {" + eol + " a: number;" + eol + "}");
+ check("class A {" + eol + " foo(a: number): string {}" + eol + "}");
+ check("class A {" + eol + " static foo(a: number): string {}" + eol + "}");
+
+ // Type parameters
+ check("class A<T> {}");
+ check("class A<X, Y> {}");
+ check("class A<X> extends B<Y> {}");
+ check("function a<T>(y: Y<T>): T {}");
+ check("class A {" + eol + " foo<T>(a: number): string {}" + eol + "}");
+
+ // Interfaces
+ check("interface A<X> extends B<A>, C {a: number}");
+ check("class A extends B implements C<T>, Y {}");
+
+ // Bounded polymorphism
+ check("class A<T: number> {}");
+ });
});
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-recast.git
More information about the Pkg-javascript-commits
mailing list