summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js')
-rw-r--r--deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js1802
1 files changed, 1802 insertions, 0 deletions
diff --git a/deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js b/deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js
new file mode 100644
index 0000000000..2ed1e8579b
--- /dev/null
+++ b/deps/npm/node_modules/readable-stream/node_modules/unreachable-branch-transform/node_modules/recast/lib/printer.js
@@ -0,0 +1,1802 @@
+var assert = require("assert");
+var sourceMap = require("source-map");
+var printComments = require("./comments").printComments;
+var linesModule = require("./lines");
+var fromString = linesModule.fromString;
+var concat = linesModule.concat;
+var normalizeOptions = require("./options").normalize;
+var getReprinter = require("./patcher").getReprinter;
+var types = require("./types");
+var namedTypes = types.namedTypes;
+var isString = types.builtInTypes.string;
+var isObject = types.builtInTypes.object;
+var FastPath = require("./fast-path");
+var util = require("./util");
+
+function PrintResult(code, sourceMap) {
+ assert.ok(this instanceof PrintResult);
+
+ isString.assert(code);
+ this.code = code;
+
+ if (sourceMap) {
+ isObject.assert(sourceMap);
+ this.map = sourceMap;
+ }
+}
+
+var PRp = PrintResult.prototype;
+var warnedAboutToString = false;
+
+PRp.toString = function() {
+ if (!warnedAboutToString) {
+ console.warn(
+ "Deprecation warning: recast.print now returns an object with " +
+ "a .code property. You appear to be treating the object as a " +
+ "string, which might still work but is strongly discouraged."
+ );
+
+ warnedAboutToString = true;
+ }
+
+ return this.code;
+};
+
+var emptyPrintResult = new PrintResult("");
+
+function Printer(originalOptions) {
+ assert.ok(this instanceof Printer);
+
+ var explicitTabWidth = originalOptions && originalOptions.tabWidth;
+ var options = normalizeOptions(originalOptions);
+ assert.notStrictEqual(options, originalOptions);
+
+ // It's common for client code to pass the same options into both
+ // recast.parse and recast.print, but the Printer doesn't need (and
+ // can be confused by) options.sourceFileName, so we null it out.
+ options.sourceFileName = null;
+
+ function printWithComments(path) {
+ assert.ok(path instanceof FastPath);
+ return printComments(path, print);
+ }
+
+ function print(path, includeComments) {
+ if (includeComments)
+ return printWithComments(path);
+
+ assert.ok(path instanceof FastPath);
+
+ if (!explicitTabWidth) {
+ var oldTabWidth = options.tabWidth;
+ var loc = path.getNode().loc;
+ if (loc && loc.lines && loc.lines.guessTabWidth) {
+ options.tabWidth = loc.lines.guessTabWidth();
+ var lines = maybeReprint(path);
+ options.tabWidth = oldTabWidth;
+ return lines;
+ }
+ }
+
+ return maybeReprint(path);
+ }
+
+ function maybeReprint(path) {
+ var reprinter = getReprinter(path);
+ if (reprinter) {
+ // Since the print function that we pass to the reprinter will
+ // be used to print "new" nodes, it's tempting to think we
+ // should pass printRootGenerically instead of print, to avoid
+ // calling maybeReprint again, but that would be a mistake
+ // because the new nodes might not be entirely new, but merely
+ // moved from elsewhere in the AST. The print function is the
+ // right choice because it gives us the opportunity to reprint
+ // such nodes using their original source.
+ return maybeAddParens(path, reprinter(print));
+ }
+ return printRootGenerically(path);
+ }
+
+ // Print the root node generically, but then resume reprinting its
+ // children non-generically.
+ function printRootGenerically(path, includeComments) {
+ return includeComments
+ ? printComments(path, printRootGenerically)
+ : genericPrint(path, options, printWithComments);
+ }
+
+ // Print the entire AST generically.
+ function printGenerically(path) {
+ return genericPrint(path, options, printGenerically);
+ }
+
+ this.print = function(ast) {
+ if (!ast) {
+ return emptyPrintResult;
+ }
+
+ var lines = print(FastPath.from(ast), true);
+
+ return new PrintResult(
+ lines.toString(options),
+ util.composeSourceMaps(
+ options.inputSourceMap,
+ lines.getSourceMap(
+ options.sourceMapName,
+ options.sourceRoot
+ )
+ )
+ );
+ };
+
+ this.printGenerically = function(ast) {
+ if (!ast) {
+ return emptyPrintResult;
+ }
+
+ var path = FastPath.from(ast);
+ var oldReuseWhitespace = options.reuseWhitespace;
+
+ // Do not reuse whitespace (or anything else, for that matter)
+ // when printing generically.
+ options.reuseWhitespace = false;
+
+ // TODO Allow printing of comments?
+ var pr = new PrintResult(printGenerically(path).toString(options));
+ options.reuseWhitespace = oldReuseWhitespace;
+ return pr;
+ };
+}
+
+exports.Printer = Printer;
+
+function maybeAddParens(path, lines) {
+ return path.needsParens() ? concat(["(", lines, ")"]) : lines;
+}
+
+function genericPrint(path, options, printPath) {
+ assert.ok(path instanceof FastPath);
+
+ 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) {
+ var n = path.getValue();
+
+ if (!n) {
+ return fromString("");
+ }
+
+ if (typeof n === "string") {
+ return fromString(n, options);
+ }
+
+ namedTypes.Printable.assert(n);
+
+ var parts = [];
+
+ switch (n.type) {
+ case "File":
+ return path.call(print, "program");
+
+ case "Program":
+ return path.call(function(bodyPath) {
+ return printStatementSequence(bodyPath, options, print);
+ }, "body");
+
+ case "Noop": // Babel extension.
+ case "EmptyStatement":
+ return fromString("");
+
+ case "ExpressionStatement":
+ return concat([path.call(print, "expression"), ";"]);
+
+ case "ParenthesizedExpression": // Babel extension.
+ return concat(["(", path.call(print, "expression"), ")"]);
+
+ case "BinaryExpression":
+ case "LogicalExpression":
+ case "AssignmentExpression":
+ return fromString(" ").join([
+ path.call(print, "left"),
+ n.operator,
+ path.call(print, "right")
+ ]);
+
+ case "AssignmentPattern":
+ return concat([
+ path.call(print, "left"),
+ "=",
+ path.call(print, "right")
+ ]);
+
+ case "MemberExpression":
+ parts.push(path.call(print, "object"));
+
+ var property = path.call(print, "property");
+ if (n.computed) {
+ parts.push("[", property, "]");
+ } else {
+ parts.push(".", property);
+ }
+
+ return concat(parts);
+
+ case "MetaProperty":
+ return concat([
+ path.call(print, "meta"),
+ ".",
+ path.call(print, "property")
+ ]);
+
+ case "BindExpression":
+ if (n.object) {
+ parts.push(path.call(print, "object"));
+ }
+
+ parts.push("::", path.call(print, "callee"));
+
+ return concat(parts);
+
+ case "Path":
+ return fromString(".").join(n.body);
+
+ case "Identifier":
+ return concat([
+ fromString(n.name, options),
+ path.call(print, "typeAnnotation")
+ ]);
+
+ case "SpreadElement":
+ case "SpreadElementPattern":
+ case "SpreadProperty":
+ case "SpreadPropertyPattern":
+ case "RestElement":
+ return concat(["...", path.call(print, "argument")]);
+
+ case "FunctionDeclaration":
+ case "FunctionExpression":
+ if (n.async)
+ parts.push("async ");
+
+ parts.push("function");
+
+ if (n.generator)
+ parts.push("*");
+
+ if (n.id) {
+ parts.push(
+ " ",
+ path.call(print, "id"),
+ path.call(print, "typeParameters")
+ );
+ }
+
+ parts.push(
+ "(",
+ printFunctionParams(path, options, print),
+ ")",
+ path.call(print, "returnType"),
+ " ",
+ path.call(print, "body")
+ );
+
+ return concat(parts);
+
+ case "ArrowFunctionExpression":
+ if (n.async)
+ parts.push("async ");
+
+ if (
+ n.params.length === 1 &&
+ !n.rest &&
+ n.params[0].type === 'Identifier' &&
+ !n.params[0].typeAnnotation
+ ) {
+ parts.push(path.call(print, "params", 0));
+ } else {
+ parts.push(
+ "(",
+ printFunctionParams(path, options, print),
+ ")"
+ );
+ }
+
+ parts.push(" => ", path.call(print, "body"));
+
+ return concat(parts);
+
+ case "MethodDefinition":
+ if (n.static) {
+ parts.push("static ");
+ }
+
+ parts.push(printMethod(path, options, print));
+
+ return concat(parts);
+
+ case "YieldExpression":
+ parts.push("yield");
+
+ if (n.delegate)
+ parts.push("*");
+
+ if (n.argument)
+ parts.push(" ", path.call(print, "argument"));
+
+ return concat(parts);
+
+ case "AwaitExpression":
+ parts.push("await");
+
+ if (n.all)
+ parts.push("*");
+
+ if (n.argument)
+ parts.push(" ", path.call(print, "argument"));
+
+ return concat(parts);
+
+ case "ModuleDeclaration":
+ parts.push("module", path.call(print, "id"));
+
+ if (n.source) {
+ assert.ok(!n.body);
+ parts.push("from", path.call(print, "source"));
+ } else {
+ parts.push(path.call(print, "body"));
+ }
+
+ return fromString(" ").join(parts);
+
+ case "ImportSpecifier":
+ if (n.imported) {
+ parts.push(path.call(print, "imported"));
+ if (n.local &&
+ n.local.name !== n.imported.name) {
+ parts.push(" as ", path.call(print, "local"));
+ }
+ } else if (n.id) {
+ parts.push(path.call(print, "id"));
+ if (n.name) {
+ parts.push(" as ", path.call(print, "name"));
+ }
+ }
+
+ return concat(parts);
+
+ case "ExportSpecifier":
+ if (n.local) {
+ parts.push(path.call(print, "local"));
+ if (n.exported &&
+ n.exported.name !== n.local.name) {
+ parts.push(" as ", path.call(print, "exported"));
+ }
+ } else if (n.id) {
+ parts.push(path.call(print, "id"));
+ if (n.name) {
+ parts.push(" as ", path.call(print, "name"));
+ }
+ }
+
+ return concat(parts);
+
+ case "ExportBatchSpecifier":
+ return fromString("*");
+
+ case "ImportNamespaceSpecifier":
+ parts.push("* as ");
+ if (n.local) {
+ parts.push(path.call(print, "local"));
+ } else if (n.id) {
+ parts.push(path.call(print, "id"));
+ }
+ return concat(parts);
+
+ case "ImportDefaultSpecifier":
+ if (n.local) {
+ return path.call(print, "local");
+ }
+ return path.call(print, "id");
+
+ case "ExportDeclaration":
+ case "ExportDefaultDeclaration":
+ case "ExportNamedDeclaration":
+ return printExportDeclaration(path, options, print);
+
+ case "ExportAllDeclaration":
+ parts.push("export *");
+
+ if (n.exported) {
+ parts.push(" as ", path.call(print, "exported"));
+ }
+
+ parts.push(
+ " from ",
+ path.call(print, "source")
+ );
+
+ return concat(parts);
+
+ case "ExportNamespaceSpecifier":
+ return concat(["* as ", path.call(print, "exported")]);
+
+ case "ExportDefaultSpecifier":
+ return path.call(print, "exported");
+
+ case "ImportDeclaration":
+ parts.push("import ");
+
+ if (n.importKind && n.importKind !== "value") {
+ parts.push(n.importKind + " ");
+ }
+
+ if (n.specifiers &&
+ n.specifiers.length > 0) {
+
+ var foundImportSpecifier = false;
+
+ path.each(function(specifierPath) {
+ var i = specifierPath.getName();
+ if (i > 0) {
+ parts.push(", ");
+ }
+
+ var value = specifierPath.getValue();
+
+ if (namedTypes.ImportDefaultSpecifier.check(value) ||
+ namedTypes.ImportNamespaceSpecifier.check(value)) {
+ assert.strictEqual(foundImportSpecifier, false);
+ } else {
+ namedTypes.ImportSpecifier.assert(value);
+ if (!foundImportSpecifier) {
+ foundImportSpecifier = true;
+ parts.push("{");
+ }
+ }
+
+ parts.push(print(specifierPath));
+ }, "specifiers");
+
+ if (foundImportSpecifier) {
+ parts.push("}");
+ }
+
+ parts.push(" from ");
+ }
+
+ parts.push(path.call(print, "source"), ";");
+
+ return concat(parts);
+
+ case "BlockStatement":
+ var naked = path.call(function(bodyPath) {
+ return printStatementSequence(bodyPath, options, print);
+ }, "body");
+
+ if (naked.isEmpty()) {
+ return fromString("{}");
+ }
+
+ return concat([
+ "{\n",
+ naked.indent(options.tabWidth),
+ "\n}"
+ ]);
+
+ case "ReturnStatement":
+ parts.push("return");
+
+ if (n.argument) {
+ var argLines = path.call(print, "argument");
+ if (argLines.length > 1 &&
+ namedTypes.JSXElement &&
+ namedTypes.JSXElement.check(n.argument)) {
+ parts.push(
+ " (\n",
+ argLines.indent(options.tabWidth),
+ "\n)"
+ );
+ } else {
+ parts.push(" ", argLines);
+ }
+ }
+
+ parts.push(";");
+
+ return concat(parts);
+
+ case "CallExpression":
+ return concat([
+ path.call(print, "callee"),
+ printArgumentsList(path, options, print)
+ ]);
+
+ case "ObjectExpression":
+ case "ObjectPattern":
+ case "ObjectTypeAnnotation":
+ var allowBreak = false;
+ var isTypeAnnotation = n.type === "ObjectTypeAnnotation";
+ var separator = isTypeAnnotation ? ';' : ',';
+ var fields = [];
+
+ if (isTypeAnnotation) {
+ fields.push("indexers", "callProperties");
+ }
+
+ fields.push("properties");
+
+ var len = 0;
+ fields.forEach(function(field) {
+ len += n[field].length;
+ });
+
+ var oneLine = (isTypeAnnotation && len === 1) || len === 0;
+ parts.push(oneLine ? "{" : "{\n");
+
+ var i = 0;
+ fields.forEach(function(field) {
+ path.each(function(childPath) {
+ var lines = print(childPath);
+
+ if (!oneLine) {
+ lines = lines.indent(options.tabWidth);
+ }
+
+ var multiLine = !isTypeAnnotation && lines.length > 1;
+ if (multiLine && allowBreak) {
+ // Similar to the logic for BlockStatement.
+ parts.push("\n");
+ }
+
+ parts.push(lines);
+
+ if (i < len - 1) {
+ // Add an extra line break if the previous object property
+ // had a multi-line value.
+ parts.push(separator + (multiLine ? "\n\n" : "\n"));
+ allowBreak = !multiLine;
+ } else if (len !== 1 && isTypeAnnotation) {
+ parts.push(separator);
+ } else if (options.trailingComma) {
+ parts.push(separator);
+ }
+ i++;
+ }, field);
+ });
+
+ parts.push(oneLine ? "}" : "\n}");
+
+ return concat(parts);
+
+ case "PropertyPattern":
+ return concat([
+ path.call(print, "key"),
+ ": ",
+ path.call(print, "pattern")
+ ]);
+
+ case "Property": // Non-standard AST node type.
+ if (n.method || n.kind === "get" || n.kind === "set") {
+ return printMethod(path, options, print);
+ }
+
+ var key = path.call(print, "key");
+ if (n.computed) {
+ parts.push("[", key, "]");
+ } else {
+ parts.push(key);
+ }
+
+ if (! n.shorthand) {
+ parts.push(": ", path.call(print, "value"));
+ }
+
+ return concat(parts);
+
+ case "Decorator":
+ return concat(["@", path.call(print, "expression")]);
+
+ case "ArrayExpression":
+ case "ArrayPattern":
+ var elems = n.elements,
+ len = elems.length;
+
+ var printed = path.map(print, "elements");
+ var joined = fromString(", ").join(printed);
+ var oneLine = joined.getLineLength(1) <= options.wrapColumn;
+ parts.push(oneLine ? "[" : "[\n");
+
+ path.each(function(elemPath) {
+ var i = elemPath.getName();
+ var elem = elemPath.getValue();
+ if (!elem) {
+ // If the array expression ends with a hole, that hole
+ // will be ignored by the interpreter, but if it ends with
+ // two (or more) holes, we need to write out two (or more)
+ // commas so that the resulting code is interpreted with
+ // both (all) of the holes.
+ parts.push(",");
+ } else {
+ var lines = printed[i];
+ if (oneLine) {
+ if (i > 0)
+ parts.push(" ");
+ } else {
+ lines = lines.indent(options.tabWidth);
+ }
+ parts.push(lines);
+ if (i < len - 1 || (!oneLine && options.trailingComma))
+ parts.push(",");
+ if (!oneLine)
+ parts.push("\n");
+ }
+ }, "elements");
+
+ parts.push("]");
+
+ return concat(parts);
+
+ case "SequenceExpression":
+ return fromString(", ").join(path.map(print, "expressions"));
+
+ case "ThisExpression":
+ return fromString("this");
+
+ case "Super":
+ return fromString("super");
+
+ case "Literal":
+ if (typeof n.value !== "string")
+ return fromString(n.value, options);
+
+ return fromString(nodeStr(n.value, options), options);
+
+ case "ModuleSpecifier":
+ if (n.local) {
+ throw new Error(
+ "The ESTree ModuleSpecifier type should be abstract"
+ );
+ }
+
+ // The Esprima ModuleSpecifier type is just a string-valued
+ // Literal identifying the imported-from module.
+ return fromString(nodeStr(n.value, options), options);
+
+ case "UnaryExpression":
+ parts.push(n.operator);
+ if (/[a-z]$/.test(n.operator))
+ parts.push(" ");
+ parts.push(path.call(print, "argument"));
+ return concat(parts);
+
+ case "UpdateExpression":
+ parts.push(
+ path.call(print, "argument"),
+ n.operator
+ );
+
+ if (n.prefix)
+ parts.reverse();
+
+ return concat(parts);
+
+ case "ConditionalExpression":
+ return concat([
+ "(", path.call(print, "test"),
+ " ? ", path.call(print, "consequent"),
+ " : ", path.call(print, "alternate"), ")"
+ ]);
+
+ case "NewExpression":
+ parts.push("new ", path.call(print, "callee"));
+ var args = n.arguments;
+ if (args) {
+ parts.push(printArgumentsList(path, options, print));
+ }
+
+ return concat(parts);
+
+ case "VariableDeclaration":
+ parts.push(n.kind, " ");
+ var maxLen = 0;
+ var printed = path.map(function(childPath) {
+ var lines = print(childPath);
+ maxLen = Math.max(lines.length, maxLen);
+ return lines;
+ }, "declarations");
+
+ if (maxLen === 1) {
+ parts.push(fromString(", ").join(printed));
+ } else if (printed.length > 1 ) {
+ parts.push(
+ fromString(",\n").join(printed)
+ .indentTail(n.kind.length + 1)
+ );
+ } else {
+ parts.push(printed[0]);
+ }
+
+ // We generally want to terminate all variable declarations with a
+ // semicolon, except when they are children of for loops.
+ var parentNode = path.getParentNode();
+ if (!namedTypes.ForStatement.check(parentNode) &&
+ !namedTypes.ForInStatement.check(parentNode) &&
+ !(namedTypes.ForOfStatement &&
+ namedTypes.ForOfStatement.check(parentNode))) {
+ parts.push(";");
+ }
+
+ return concat(parts);
+
+ case "VariableDeclarator":
+ return n.init ? fromString(" = ").join([
+ path.call(print, "id"),
+ path.call(print, "init")
+ ]) : path.call(print, "id");
+
+ case "WithStatement":
+ return concat([
+ "with (",
+ path.call(print, "object"),
+ ") ",
+ path.call(print, "body")
+ ]);
+
+ case "IfStatement":
+ var con = adjustClause(path.call(print, "consequent"), options),
+ parts = ["if (", path.call(print, "test"), ")", con];
+
+ if (n.alternate)
+ parts.push(
+ endsWithBrace(con) ? " else" : "\nelse",
+ adjustClause(path.call(print, "alternate"), options));
+
+ return concat(parts);
+
+ case "ForStatement":
+ // TODO Get the for (;;) case right.
+ var init = path.call(print, "init"),
+ sep = init.length > 1 ? ";\n" : "; ",
+ forParen = "for (",
+ indented = fromString(sep).join([
+ init,
+ path.call(print, "test"),
+ path.call(print, "update")
+ ]).indentTail(forParen.length),
+ head = concat([forParen, indented, ")"]),
+ clause = adjustClause(path.call(print, "body"), options),
+ parts = [head];
+
+ if (head.length > 1) {
+ parts.push("\n");
+ clause = clause.trimLeft();
+ }
+
+ parts.push(clause);
+
+ return concat(parts);
+
+ case "WhileStatement":
+ return concat([
+ "while (",
+ path.call(print, "test"),
+ ")",
+ adjustClause(path.call(print, "body"), options)
+ ]);
+
+ case "ForInStatement":
+ // Note: esprima can't actually parse "for each (".
+ return concat([
+ n.each ? "for each (" : "for (",
+ path.call(print, "left"),
+ " in ",
+ path.call(print, "right"),
+ ")",
+ adjustClause(path.call(print, "body"), options)
+ ]);
+
+ case "ForOfStatement":
+ return concat([
+ "for (",
+ path.call(print, "left"),
+ " of ",
+ path.call(print, "right"),
+ ")",
+ adjustClause(path.call(print, "body"), options)
+ ]);
+
+ case "DoWhileStatement":
+ var doBody = concat([
+ "do",
+ adjustClause(path.call(print, "body"), options)
+ ]), parts = [doBody];
+
+ if (endsWithBrace(doBody))
+ parts.push(" while");
+ else
+ parts.push("\nwhile");
+
+ parts.push(" (", path.call(print, "test"), ");");
+
+ return concat(parts);
+
+ case "DoExpression":
+ var statements = path.call(function(bodyPath) {
+ return printStatementSequence(bodyPath, options, print);
+ }, "body");
+
+ return concat([
+ "do {\n",
+ statements.indent(options.tabWidth),
+ "\n}"
+ ]);
+
+ case "BreakStatement":
+ parts.push("break");
+ if (n.label)
+ parts.push(" ", path.call(print, "label"));
+ parts.push(";");
+ return concat(parts);
+
+ case "ContinueStatement":
+ parts.push("continue");
+ if (n.label)
+ parts.push(" ", path.call(print, "label"));
+ parts.push(";");
+ return concat(parts);
+
+ case "LabeledStatement":
+ return concat([
+ path.call(print, "label"),
+ ":\n",
+ path.call(print, "body")
+ ]);
+
+ case "TryStatement":
+ parts.push(
+ "try ",
+ path.call(print, "block")
+ );
+
+ if (n.handler) {
+ parts.push(" ", path.call(print, "handler"));
+ } else if (n.handlers) {
+ path.each(function(handlerPath) {
+ parts.push(" ", print(handlerPath));
+ }, "handlers");
+ }
+
+ if (n.finalizer) {
+ parts.push(" finally ", path.call(print, "finalizer"));
+ }
+
+ return concat(parts);
+
+ case "CatchClause":
+ parts.push("catch (", path.call(print, "param"));
+
+ if (n.guard)
+ // Note: esprima does not recognize conditional catch clauses.
+ parts.push(" if ", path.call(print, "guard"));
+
+ parts.push(") ", path.call(print, "body"));
+
+ return concat(parts);
+
+ case "ThrowStatement":
+ return concat(["throw ", path.call(print, "argument"), ";"]);
+
+ case "SwitchStatement":
+ return concat([
+ "switch (",
+ path.call(print, "discriminant"),
+ ") {\n",
+ fromString("\n").join(path.map(print, "cases")),
+ "\n}"
+ ]);
+
+ // Note: ignoring n.lexical because it has no printing consequences.
+
+ case "SwitchCase":
+ if (n.test)
+ parts.push("case ", path.call(print, "test"), ":");
+ else
+ parts.push("default:");
+
+ if (n.consequent.length > 0) {
+ parts.push("\n", path.call(function(consequentPath) {
+ return printStatementSequence(consequentPath, options, print);
+ }, "consequent").indent(options.tabWidth));
+ }
+
+ return concat(parts);
+
+ case "DebuggerStatement":
+ return fromString("debugger;");
+
+ // JSX extensions below.
+
+ case "JSXAttribute":
+ parts.push(path.call(print, "name"));
+ if (n.value)
+ parts.push("=", path.call(print, "value"));
+ return concat(parts);
+
+ case "JSXIdentifier":
+ return fromString(n.name, options);
+
+ case "JSXNamespacedName":
+ return fromString(":").join([
+ path.call(print, "namespace"),
+ path.call(print, "name")
+ ]);
+
+ case "JSXMemberExpression":
+ return fromString(".").join([
+ path.call(print, "object"),
+ path.call(print, "property")
+ ]);
+
+ case "JSXSpreadAttribute":
+ return concat(["{...", path.call(print, "argument"), "}"]);
+
+ case "JSXExpressionContainer":
+ return concat(["{", path.call(print, "expression"), "}"]);
+
+ case "JSXElement":
+ var openingLines = path.call(print, "openingElement");
+
+ if (n.openingElement.selfClosing) {
+ assert.ok(!n.closingElement);
+ return openingLines;
+ }
+
+ var childLines = concat(
+ path.map(function(childPath) {
+ var child = childPath.getValue();
+
+ if (namedTypes.Literal.check(child) &&
+ typeof child.value === "string") {
+ return child.value;
+ }
+
+ return print(childPath);
+ }, "children")
+ ).indentTail(options.tabWidth);
+
+ var closingLines = path.call(print, "closingElement");
+
+ return concat([
+ openingLines,
+ childLines,
+ closingLines
+ ]);
+
+ case "JSXOpeningElement":
+ parts.push("<", path.call(print, "name"));
+ var attrParts = [];
+
+ path.each(function(attrPath) {
+ attrParts.push(" ", print(attrPath));
+ }, "attributes");
+
+ var attrLines = concat(attrParts);
+
+ var needLineWrap = (
+ attrLines.length > 1 ||
+ attrLines.getLineLength(1) > options.wrapColumn
+ );
+
+ if (needLineWrap) {
+ attrParts.forEach(function(part, i) {
+ if (part === " ") {
+ assert.strictEqual(i % 2, 0);
+ attrParts[i] = "\n";
+ }
+ });
+
+ attrLines = concat(attrParts).indentTail(options.tabWidth);
+ }
+
+ parts.push(attrLines, n.selfClosing ? " />" : ">");
+
+ return concat(parts);
+
+ case "JSXClosingElement":
+ return concat(["</", path.call(print, "name"), ">"]);
+
+ case "JSXText":
+ return fromString(n.value, options);
+
+ case "JSXEmptyExpression":
+ return fromString("");
+
+ case "TypeAnnotatedIdentifier":
+ return concat([
+ path.call(print, "annotation"),
+ " ",
+ path.call(print, "identifier")
+ ]);
+
+ case "ClassBody":
+ if (n.body.length === 0) {
+ return fromString("{}");
+ }
+
+ return concat([
+ "{\n",
+ path.call(function(bodyPath) {
+ return printStatementSequence(bodyPath, options, print);
+ }, "body").indent(options.tabWidth),
+ "\n}"
+ ]);
+
+ case "ClassPropertyDefinition":
+ parts.push("static ", path.call(print, "definition"));
+ if (!namedTypes.MethodDefinition.check(n.definition))
+ parts.push(";");
+ return concat(parts);
+
+ case "ClassProperty":
+ if (n.static)
+ parts.push("static ");
+
+ parts.push(path.call(print, "key"));
+ if (n.typeAnnotation)
+ parts.push(path.call(print, "typeAnnotation"));
+
+ if (n.value)
+ parts.push(" = ", path.call(print, "value"));
+
+ parts.push(";");
+ return concat(parts);
+
+ case "ClassDeclaration":
+ case "ClassExpression":
+ parts.push("class");
+
+ if (n.id) {
+ parts.push(
+ " ",
+ path.call(print, "id"),
+ path.call(print, "typeParameters")
+ );
+ }
+
+ if (n.superClass) {
+ parts.push(
+ " extends ",
+ path.call(print, "superClass"),
+ path.call(print, "superTypeParameters")
+ );
+ }
+
+ if (n["implements"] && n['implements'].length > 0) {
+ parts.push(
+ " implements ",
+ fromString(", ").join(path.map(print, "implements"))
+ );
+ }
+
+ parts.push(" ", path.call(print, "body"));
+
+ return concat(parts);
+
+ case "TemplateElement":
+ return fromString(n.value.raw, options).lockIndentTail();
+
+ case "TemplateLiteral":
+ var expressions = path.map(print, "expressions");
+ parts.push("`");
+
+ path.each(function(childPath) {
+ var i = childPath.getName();
+ parts.push(print(childPath));
+ if (i < expressions.length) {
+ parts.push("${", expressions[i], "}");
+ }
+ }, "quasis");
+
+ parts.push("`");
+
+ return concat(parts).lockIndentTail();
+
+ case "TaggedTemplateExpression":
+ return concat([
+ path.call(print, "tag"),
+ path.call(print, "quasi")
+ ]);
+
+ // These types are unprintable because they serve as abstract
+ // supertypes for other (printable) types.
+ case "Node":
+ case "Printable":
+ case "SourceLocation":
+ case "Position":
+ case "Statement":
+ case "Function":
+ case "Pattern":
+ case "Expression":
+ case "Declaration":
+ case "Specifier":
+ case "NamedSpecifier":
+ case "Comment": // Supertype of Block and Line.
+ case "MemberTypeAnnotation": // Flow
+ case "TupleTypeAnnotation": // Flow
+ case "Type": // Flow
+ throw new Error("unprintable type: " + JSON.stringify(n.type));
+
+ case "CommentBlock": // Babel block comment.
+ case "Block": // Esprima block comment.
+ return concat(["/*", fromString(n.value, options), "*/"]);
+
+ case "CommentLine": // Babel line comment.
+ case "Line": // Esprima line comment.
+ return concat(["//", fromString(n.value, options)]);
+
+ // Type Annotations for Facebook Flow, typically stripped out or
+ // transformed away before printing.
+ case "TypeAnnotation":
+ if (n.typeAnnotation) {
+ if (n.typeAnnotation.type !== "FunctionTypeAnnotation") {
+ parts.push(": ");
+ }
+ parts.push(path.call(print, "typeAnnotation"));
+ return concat(parts);
+ }
+
+ return fromString("");
+
+ case "AnyTypeAnnotation":
+ return fromString("any", options);
+
+ case "MixedTypeAnnotation":
+ return fromString("mixed", options);
+
+ case "ArrayTypeAnnotation":
+ return concat([
+ path.call(print, "elementType"),
+ "[]"
+ ]);
+
+ case "BooleanTypeAnnotation":
+ return fromString("boolean", options);
+
+ case "BooleanLiteralTypeAnnotation":
+ assert.strictEqual(typeof n.value, "boolean");
+ return fromString("" + n.value, options);
+
+ case "DeclareClass":
+ return printFlowDeclaration(path, [
+ "class ",
+ path.call(print, "id"),
+ " ",
+ path.call(print, "body"),
+ ]);
+
+ case "DeclareFunction":
+ return printFlowDeclaration(path, [
+ "function ",
+ path.call(print, "id"),
+ ";"
+ ]);
+
+ case "DeclareModule":
+ return printFlowDeclaration(path, [
+ "module ",
+ path.call(print, "id"),
+ " ",
+ path.call(print, "body"),
+ ]);
+
+ case "DeclareVariable":
+ 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 parent = path.getParentNode(0);
+ var isArrowFunctionTypeAnnotation = !(
+ namedTypes.ObjectTypeCallProperty.check(parent) ||
+ namedTypes.DeclareFunction.check(path.getParentNode(2))
+ );
+
+ var needsColon =
+ isArrowFunctionTypeAnnotation &&
+ !namedTypes.FunctionTypeParam.check(parent);
+
+ if (needsColon) {
+ parts.push(": ");
+ }
+
+ parts.push(
+ "(",
+ fromString(", ").join(path.map(print, "params")),
+ ")"
+ );
+
+ // The returnType is not wrapped in a TypeAnnotation, so the colon
+ // needs to be added separately.
+ if (n.returnType) {
+ parts.push(
+ isArrowFunctionTypeAnnotation ? " => " : ": ",
+ path.call(print, "returnType")
+ );
+ }
+
+ return concat(parts);
+
+ case "FunctionTypeParam":
+ return concat([
+ path.call(print, "name"),
+ n.optional ? '?' : '',
+ ": ",
+ path.call(print, "typeAnnotation"),
+ ]);
+
+ case "GenericTypeAnnotation":
+ return concat([
+ path.call(print, "id"),
+ path.call(print, "typeParameters")
+ ]);
+
+ case "DeclareInterface":
+ parts.push("declare ");
+
+ case "InterfaceDeclaration":
+ parts.push(
+ fromString("interface ", options),
+ path.call(print, "id"),
+ path.call(print, "typeParameters"),
+ " "
+ );
+
+ if (n["extends"]) {
+ parts.push(
+ "extends ",
+ fromString(", ").join(path.map(print, "extends"))
+ );
+ }
+
+ parts.push(" ", path.call(print, "body"));
+
+ return concat(parts);
+
+ case "ClassImplements":
+ case "InterfaceExtends":
+ return concat([
+ path.call(print, "id"),
+ path.call(print, "typeParameters")
+ ]);
+
+ case "IntersectionTypeAnnotation":
+ return fromString(" & ").join(path.map(print, "types"));
+
+ case "NullableTypeAnnotation":
+ return concat([
+ "?",
+ path.call(print, "typeAnnotation")
+ ]);
+
+ case "NullLiteralTypeAnnotation":
+ return fromString("null", options);
+
+ case "ThisTypeAnnotation":
+ return fromString("this", options);
+
+ case "NumberTypeAnnotation":
+ return fromString("number", options);
+
+ case "ObjectTypeCallProperty":
+ return path.call(print, "value");
+
+ case "ObjectTypeIndexer":
+ return concat([
+ "[",
+ path.call(print, "id"),
+ ": ",
+ path.call(print, "key"),
+ "]: ",
+ path.call(print, "value")
+ ]);
+
+ case "ObjectTypeProperty":
+ return concat([
+ path.call(print, "key"),
+ n.optional ? "?" : "",
+ ": ",
+ path.call(print, "value")
+ ]);
+
+ case "QualifiedTypeIdentifier":
+ return concat([
+ path.call(print, "qualification"),
+ ".",
+ path.call(print, "id")
+ ]);
+
+ case "StringLiteralTypeAnnotation":
+ return fromString(nodeStr(n.value, options), options);
+
+ case "NumberLiteralTypeAnnotation":
+ assert.strictEqual(typeof n.value, "number");
+ return fromString("" + n.value, options);
+
+ case "StringTypeAnnotation":
+ return fromString("string", options);
+
+ case "DeclareTypeAlias":
+ parts.push("declare ");
+
+ case "TypeAlias":
+ return concat([
+ "type ",
+ path.call(print, "id"),
+ " = ",
+ path.call(print, "right"),
+ ";"
+ ]);
+
+ case "TypeCastExpression":
+ return concat([
+ "(",
+ path.call(print, "expression"),
+ path.call(print, "typeAnnotation"),
+ ")"
+ ]);
+
+ case "TypeParameterDeclaration":
+ case "TypeParameterInstantiation":
+ return concat([
+ "<",
+ fromString(", ").join(path.map(print, "params")),
+ ">"
+ ]);
+
+ case "TypeofTypeAnnotation":
+ return concat([
+ fromString("typeof ", options),
+ path.call(print, "argument")
+ ]);
+
+ case "UnionTypeAnnotation":
+ return fromString(" | ").join(path.map(print, "types"));
+
+ case "VoidTypeAnnotation":
+ return fromString("void", options);
+
+ // Unhandled types below. If encountered, nodes of these types should
+ // be either left alone or desugared into AST types that are fully
+ // supported by the pretty-printer.
+ case "ClassHeritage": // TODO
+ case "ComprehensionBlock": // TODO
+ case "ComprehensionExpression": // TODO
+ case "Glob": // TODO
+ case "GeneratorExpression": // TODO
+ case "LetStatement": // TODO
+ case "LetExpression": // TODO
+ case "GraphExpression": // TODO
+ case "GraphIndexExpression": // TODO
+
+ // XML types that nobody cares about or needs to print.
+ case "XMLDefaultDeclaration":
+ case "XMLAnyName":
+ case "XMLQualifiedIdentifier":
+ case "XMLFunctionQualifiedIdentifier":
+ case "XMLAttributeSelector":
+ case "XMLFilterExpression":
+ case "XML":
+ case "XMLElement":
+ case "XMLList":
+ case "XMLEscape":
+ case "XMLText":
+ case "XMLStartTag":
+ case "XMLEndTag":
+ case "XMLPointTag":
+ case "XMLName":
+ case "XMLAttribute":
+ case "XMLCdata":
+ case "XMLComment":
+ case "XMLProcessingInstruction":
+ default:
+ debugger;
+ throw new Error("unknown type: " + JSON.stringify(n.type));
+ }
+
+ return p;
+}
+
+function printStatementSequence(path, options, print) {
+ var inClassBody =
+ namedTypes.ClassBody &&
+ namedTypes.ClassBody.check(path.getParentNode());
+
+ var filtered = [];
+ var sawComment = false;
+ var sawStatement = false;
+
+ path.each(function(stmtPath) {
+ var i = stmtPath.getName();
+ var stmt = stmtPath.getValue();
+
+ // Just in case the AST has been modified to contain falsy
+ // "statements," it's safer simply to skip them.
+ if (!stmt) {
+ return;
+ }
+
+ // Skip printing EmptyStatement nodes to avoid leaving stray
+ // semicolons lying around.
+ if (stmt.type === "EmptyStatement") {
+ return;
+ }
+
+ if (namedTypes.Comment.check(stmt)) {
+ // The pretty printer allows a dangling Comment node to act as
+ // a Statement when the Comment can't be attached to any other
+ // non-Comment node in the tree.
+ sawComment = true;
+ } else if (namedTypes.Statement.check(stmt)) {
+ sawStatement = true;
+ } else {
+ // When the pretty printer encounters a string instead of an
+ // AST node, it just prints the string. This behavior can be
+ // useful for fine-grained formatting decisions like inserting
+ // blank lines.
+ isString.assert(stmt);
+ }
+
+ // We can't hang onto stmtPath outside of this function, because
+ // it's just a reference to a mutable FastPath object, so we have
+ // to go ahead and print it here.
+ filtered.push({
+ node: stmt,
+ printed: print(stmtPath)
+ });
+ });
+
+ if (sawComment) {
+ assert.strictEqual(
+ sawStatement, false,
+ "Comments may appear as statements in otherwise empty statement " +
+ "lists, but may not coexist with non-Comment nodes."
+ );
+ }
+
+ var prevTrailingSpace = null;
+ var len = filtered.length;
+ var parts = [];
+
+ filtered.forEach(function(info, i) {
+ var printed = info.printed;
+ var stmt = info.node;
+ var multiLine = printed.length > 1;
+ var notFirst = i > 0;
+ var notLast = i < len - 1;
+ var leadingSpace;
+ var trailingSpace;
+ var lines = stmt && stmt.loc && stmt.loc.lines;
+ var trueLoc = lines && options.reuseWhitespace &&
+ util.getTrueLoc(stmt, lines);
+
+ if (notFirst) {
+ if (trueLoc) {
+ var beforeStart = lines.skipSpaces(trueLoc.start, true);
+ var beforeStartLine = beforeStart ? beforeStart.line : 1;
+ var leadingGap = trueLoc.start.line - beforeStartLine;
+ leadingSpace = Array(leadingGap + 1).join("\n");
+ } else {
+ leadingSpace = multiLine ? "\n\n" : "\n";
+ }
+ } else {
+ leadingSpace = "";
+ }
+
+ if (notLast) {
+ if (trueLoc) {
+ var afterEnd = lines.skipSpaces(trueLoc.end);
+ var afterEndLine = afterEnd ? afterEnd.line : lines.length;
+ var trailingGap = afterEndLine - trueLoc.end.line;
+ trailingSpace = Array(trailingGap + 1).join("\n");
+ } else {
+ trailingSpace = multiLine ? "\n\n" : "\n";
+ }
+ } else {
+ trailingSpace = "";
+ }
+
+ parts.push(
+ maxSpace(prevTrailingSpace, leadingSpace),
+ printed
+ );
+
+ if (notLast) {
+ prevTrailingSpace = trailingSpace;
+ } else if (trailingSpace) {
+ parts.push(trailingSpace);
+ }
+ });
+
+ return concat(parts);
+}
+
+function maxSpace(s1, s2) {
+ if (!s1 && !s2) {
+ return fromString("");
+ }
+
+ if (!s1) {
+ return fromString(s2);
+ }
+
+ if (!s2) {
+ return fromString(s1);
+ }
+
+ var spaceLines1 = fromString(s1);
+ var spaceLines2 = fromString(s2);
+
+ if (spaceLines2.length > spaceLines1.length) {
+ return spaceLines2;
+ }
+
+ return spaceLines1;
+}
+
+function printMethod(path, options, print) {
+ var node = path.getNode();
+ var kind = node.kind;
+ var parts = [];
+
+ namedTypes.FunctionExpression.assert(node.value);
+
+ if (node.value.async) {
+ parts.push("async ");
+ }
+
+ if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
+ if (node.value.generator) {
+ parts.push("*");
+ }
+ } else {
+ assert.ok(kind === "get" || kind === "set");
+ parts.push(kind, " ");
+ }
+
+ var key = path.call(print, "key");
+ if (node.computed) {
+ key = concat(["[", key, "]"]);
+ }
+
+ parts.push(
+ key,
+ path.call(print, "value", "typeParameters"),
+ "(",
+ path.call(function(valuePath) {
+ return printFunctionParams(valuePath, options, print);
+ }, "value"),
+ ")",
+ path.call(print, "value", "returnType"),
+ " ",
+ path.call(print, "value", "body")
+ );
+
+ return concat(parts);
+}
+
+function printArgumentsList(path, options, print) {
+ var printed = path.map(print, "arguments");
+
+ var joined = fromString(", ").join(printed);
+ if (joined.getLineLength(1) > options.wrapColumn) {
+ joined = fromString(",\n").join(printed);
+ return concat([
+ "(\n",
+ joined.indent(options.tabWidth),
+ options.trailingComma ? ",\n)" : "\n)"
+ ]);
+ }
+
+ return concat(["(", joined, ")"]);
+}
+
+function printFunctionParams(path, options, print) {
+ var fun = path.getValue();
+ namedTypes.Function.assert(fun);
+
+ var printed = path.map(print, "params");
+
+ if (fun.defaults) {
+ path.each(function(defExprPath) {
+ var i = defExprPath.getName();
+ var p = printed[i];
+ if (p && defExprPath.getValue()) {
+ printed[i] = concat([p, "=", print(defExprPath)]);
+ }
+ }, "defaults");
+ }
+
+ if (fun.rest) {
+ printed.push(concat(["...", path.call(print, "rest")]));
+ }
+
+ var joined = fromString(", ").join(printed);
+ if (joined.length > 1 ||
+ joined.getLineLength(1) > options.wrapColumn) {
+ joined = fromString(",\n").join(printed);
+ if (options.trailingComma && !fun.rest) {
+ joined = concat([joined, ",\n"]);
+ }
+ return concat(["\n", joined.indent(options.tabWidth)]);
+ }
+
+ 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]);
+
+ return concat([
+ "\n",
+ maybeAddSemicolon(clause).indent(options.tabWidth)
+ ]);
+}
+
+function lastNonSpaceCharacter(lines) {
+ var pos = lines.lastPos();
+ do {
+ var ch = lines.charAt(pos);
+ if (/\S/.test(ch))
+ return ch;
+ } while (lines.prevPos(pos));
+}
+
+function endsWithBrace(lines) {
+ return lastNonSpaceCharacter(lines) === "}";
+}
+
+function swapQuotes(str) {
+ return str.replace(/['"]/g, function(m) {
+ return m === '"' ? '\'' : '"';
+ });
+}
+
+function nodeStr(str, options) {
+ isString.assert(str);
+ switch (options.quote) {
+ case "auto":
+ var double = JSON.stringify(str);
+ var single = swapQuotes(JSON.stringify(swapQuotes(str)));
+ return double.length > single.length ? single : double;
+ case "single":
+ return swapQuotes(JSON.stringify(swapQuotes(str)));
+ case "double":
+ default:
+ return JSON.stringify(str);
+ }
+}
+
+function maybeAddSemicolon(lines) {
+ var eoc = lastNonSpaceCharacter(lines);
+ if (!eoc || "\n};".indexOf(eoc) < 0)
+ return concat([lines, ";"]);
+ return lines;
+}