2017-01-10 20:18:22 +03:00
|
|
|
"use strict";
|
2017-01-28 18:50:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
var assert = require("assert");
|
2017-01-19 22:46:37 +03:00
|
|
|
var comments = require("./comments");
|
2016-12-23 21:38:10 +03:00
|
|
|
var FastPath = require("./fast-path");
|
|
|
|
var util = require("./util");
|
2017-01-11 08:48:49 +03:00
|
|
|
var isIdentifierName = require("esutils").keyword.isIdentifierNameES6;
|
2016-12-23 21:38:10 +03:00
|
|
|
|
2017-01-19 23:46:57 +03:00
|
|
|
var docBuilders = require("./doc-builders");
|
|
|
|
var concat = docBuilders.concat;
|
|
|
|
var join = docBuilders.join;
|
|
|
|
var line = docBuilders.line;
|
|
|
|
var hardline = docBuilders.hardline;
|
|
|
|
var softline = docBuilders.softline;
|
|
|
|
var literalline = docBuilders.literalline;
|
|
|
|
var group = docBuilders.group;
|
|
|
|
var indent = docBuilders.indent;
|
2017-04-07 05:49:37 +03:00
|
|
|
var align = docBuilders.align;
|
2017-01-19 23:46:57 +03:00
|
|
|
var conditionalGroup = docBuilders.conditionalGroup;
|
|
|
|
var ifBreak = docBuilders.ifBreak;
|
2017-02-04 00:15:21 +03:00
|
|
|
var breakParent = docBuilders.breakParent;
|
2017-02-23 20:26:26 +03:00
|
|
|
var lineSuffixBoundary = docBuilders.lineSuffixBoundary;
|
2017-01-19 23:46:57 +03:00
|
|
|
|
|
|
|
var docUtils = require("./doc-utils");
|
2017-01-24 02:47:11 +03:00
|
|
|
var willBreak = docUtils.willBreak;
|
|
|
|
var isLineNext = docUtils.isLineNext;
|
2017-01-19 23:46:57 +03:00
|
|
|
var isEmpty = docUtils.isEmpty;
|
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
var types = require("./ast-types");
|
2017-01-19 23:46:57 +03:00
|
|
|
var namedTypes = types.namedTypes;
|
|
|
|
var isString = types.builtInTypes.string;
|
|
|
|
|
2017-02-18 06:44:55 +03:00
|
|
|
function shouldPrintComma(options, level) {
|
|
|
|
level = level || "es5";
|
|
|
|
|
2017-02-23 20:57:51 +03:00
|
|
|
switch (options.trailingComma) {
|
2017-02-18 06:44:55 +03:00
|
|
|
case "all":
|
2017-02-23 20:57:51 +03:00
|
|
|
if (level === "all") {
|
2017-02-18 06:44:55 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case "es5":
|
2017-02-23 20:57:51 +03:00
|
|
|
if (level === "es5") {
|
2017-02-18 06:44:55 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case "none":
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-11 18:50:49 +03:00
|
|
|
function genericPrint(path, options, printPath, args) {
|
2016-12-23 21:38:10 +03:00
|
|
|
assert.ok(path instanceof FastPath);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
var node = path.getValue();
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-14 05:58:50 +03:00
|
|
|
// Escape hatch
|
2017-02-16 06:56:11 +03:00
|
|
|
if (
|
2017-04-18 17:51:50 +03:00
|
|
|
node &&
|
2017-02-16 06:56:11 +03:00
|
|
|
node.comments &&
|
|
|
|
node.comments.length > 0 &&
|
2017-04-05 20:51:20 +03:00
|
|
|
node.comments.some(comment => comment.value.trim() === "prettier-ignore")
|
2017-02-16 06:56:11 +03:00
|
|
|
) {
|
|
|
|
return options.originalText.slice(util.locStart(node), util.locEnd(node));
|
2017-02-14 05:58:50 +03:00
|
|
|
}
|
|
|
|
|
2017-04-18 17:51:50 +03:00
|
|
|
var parts = [];
|
|
|
|
var needsParens = false;
|
|
|
|
var linesWithoutParens = genericPrintNoParens(path, options, printPath, args);
|
|
|
|
|
|
|
|
if (!node || isEmpty(linesWithoutParens)) {
|
|
|
|
return linesWithoutParens;
|
|
|
|
}
|
|
|
|
|
2016-12-31 07:03:22 +03:00
|
|
|
if (
|
2017-01-19 02:31:46 +03:00
|
|
|
node.decorators &&
|
2017-02-16 06:56:11 +03:00
|
|
|
node.decorators.length > 0 &&
|
|
|
|
// If the parent node is an export declaration, it will be
|
|
|
|
// responsible for printing node.decorators.
|
|
|
|
!util.getParentExportDeclaration(path)
|
2016-12-31 07:03:22 +03:00
|
|
|
) {
|
2017-01-26 00:30:09 +03:00
|
|
|
const separator = node.decorators.length === 1 &&
|
2017-03-16 23:27:20 +03:00
|
|
|
(node.decorators[0].expression.type === "Identifier" ||
|
2017-04-12 20:16:11 +03:00
|
|
|
node.decorators[0].expression.type === "MemberExpression")
|
2017-01-28 18:50:22 +03:00
|
|
|
? " "
|
|
|
|
: hardline;
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(decoratorPath) {
|
|
|
|
parts.push(printPath(decoratorPath), separator);
|
|
|
|
}, "decorators");
|
2017-01-09 20:09:04 +03:00
|
|
|
} else if (
|
2017-01-19 02:31:46 +03:00
|
|
|
util.isExportDeclaration(node) &&
|
2017-02-16 06:56:11 +03:00
|
|
|
node.declaration &&
|
|
|
|
node.declaration.decorators
|
2017-01-09 20:09:04 +03:00
|
|
|
) {
|
|
|
|
// Export declarations are responsible for printing any decorators
|
|
|
|
// that logically apply to node.declaration.
|
|
|
|
path.each(
|
|
|
|
function(decoratorPath) {
|
|
|
|
parts.push(printPath(decoratorPath), line);
|
|
|
|
},
|
|
|
|
"declaration",
|
|
|
|
"decorators"
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Nodes with decorators can't have parentheses, so we can avoid
|
|
|
|
// computing path.needsParens() except in this case.
|
|
|
|
needsParens = path.needsParens();
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
if (node.type) {
|
|
|
|
// HACK: ASI prevention in no-semi mode relies on knowledge of whether
|
|
|
|
// or not a paren has been inserted (see `exprNeedsASIProtection()`).
|
|
|
|
// For now, we're just passing that information by mutating the AST here,
|
|
|
|
// but it would be nice to find a cleaner way to do this.
|
|
|
|
node.needsParens = needsParens;
|
|
|
|
}
|
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (needsParens) {
|
|
|
|
parts.unshift("(");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
parts.push(linesWithoutParens);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (needsParens) {
|
|
|
|
parts.push(")");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
2017-04-11 18:50:49 +03:00
|
|
|
function genericPrintNoParens(path, options, print, args) {
|
2016-12-23 21:38:10 +03:00
|
|
|
var n = path.getValue();
|
2017-04-12 20:16:11 +03:00
|
|
|
const semi = options.semi ? ";" : "";
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (!n) {
|
2017-01-20 00:20:03 +03:00
|
|
|
return "";
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (typeof n === "string") {
|
2017-01-20 00:20:03 +03:00
|
|
|
return n;
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-22 19:51:36 +03:00
|
|
|
// TODO: Investigate types that return not printable.
|
2016-12-27 21:28:04 +03:00
|
|
|
// This assert isn't very useful though.
|
|
|
|
// namedTypes.Printable.assert(n);
|
2017-03-22 19:51:36 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
var parts = [];
|
|
|
|
switch (n.type) {
|
2017-01-13 23:03:53 +03:00
|
|
|
case "File":
|
|
|
|
return path.call(print, "program");
|
|
|
|
case "Program":
|
|
|
|
// Babel 6
|
|
|
|
if (n.directives) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(childPath) {
|
|
|
|
parts.push(print(childPath), semi, hardline);
|
|
|
|
if (
|
|
|
|
util.isNextLineEmpty(options.originalText, childPath.getValue())
|
|
|
|
) {
|
|
|
|
parts.push(hardline);
|
|
|
|
}
|
|
|
|
}, "directives");
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(
|
2017-04-12 20:16:11 +03:00
|
|
|
path.call(function(bodyPath) {
|
|
|
|
return printStatementSequence(bodyPath, options, print);
|
|
|
|
}, "body")
|
2017-01-13 23:03:53 +03:00
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-28 00:09:15 +03:00
|
|
|
parts.push(
|
2017-02-14 04:08:58 +03:00
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true)
|
2017-01-28 00:09:15 +03:00
|
|
|
);
|
2017-02-07 18:39:04 +03:00
|
|
|
|
|
|
|
// Only force a trailing newline if there were any contents.
|
|
|
|
if (n.body.length || n.comments) {
|
|
|
|
parts.push(hardline);
|
|
|
|
}
|
2017-01-11 17:39:32 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
// Babel extension.
|
|
|
|
case "Noop":
|
|
|
|
case "EmptyStatement":
|
2017-01-20 00:20:03 +03:00
|
|
|
return "";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ExpressionStatement":
|
2017-04-11 23:50:47 +03:00
|
|
|
return concat([path.call(print, "expression"), semi]); // Babel extension.
|
2017-01-28 18:50:22 +03:00
|
|
|
case "ParenthesizedExpression":
|
|
|
|
return concat(["(", path.call(print, "expression"), ")"]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "AssignmentExpression":
|
2017-03-15 19:45:40 +03:00
|
|
|
return printAssignment(
|
2017-04-14 03:09:00 +03:00
|
|
|
n.left,
|
2017-03-15 19:45:40 +03:00
|
|
|
path.call(print, "left"),
|
|
|
|
n.operator,
|
|
|
|
n.right,
|
|
|
|
path.call(print, "right"),
|
|
|
|
options
|
2017-01-13 23:03:53 +03:00
|
|
|
);
|
|
|
|
case "BinaryExpression":
|
2017-01-19 01:01:17 +03:00
|
|
|
case "LogicalExpression": {
|
2017-02-09 18:36:05 +03:00
|
|
|
const parent = path.getParentNode();
|
2017-05-06 07:44:50 +03:00
|
|
|
const parentParent = path.getParentNode(1);
|
2017-04-19 20:43:48 +03:00
|
|
|
const isInsideParenthesis =
|
|
|
|
n !== parent.body &&
|
|
|
|
(parent.type === "IfStatement" ||
|
|
|
|
parent.type === "WhileStatement" ||
|
|
|
|
parent.type === "DoStatement");
|
2017-02-09 18:36:05 +03:00
|
|
|
|
2017-04-19 20:43:48 +03:00
|
|
|
const parts = printBinaryishExpressions(
|
|
|
|
path,
|
|
|
|
print,
|
|
|
|
options,
|
|
|
|
/* isNested */ false,
|
|
|
|
isInsideParenthesis
|
|
|
|
);
|
|
|
|
|
|
|
|
// if (
|
|
|
|
// this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft
|
|
|
|
// ) {
|
|
|
|
//
|
|
|
|
// looks super weird, we want to break the children if the parent breaks
|
|
|
|
//
|
|
|
|
// if (
|
|
|
|
// this.hasPlugin("dynamicImports") &&
|
|
|
|
// this.lookahead().type === tt.parenLeft
|
|
|
|
// ) {
|
|
|
|
if (isInsideParenthesis) {
|
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Avoid indenting sub-expressions in assignment/return/etc statements.
|
2017-02-15 17:41:06 +03:00
|
|
|
if (
|
2017-03-15 19:45:40 +03:00
|
|
|
parent.type === "AssignmentExpression" ||
|
|
|
|
parent.type === "VariableDeclarator" ||
|
2017-02-15 17:41:06 +03:00
|
|
|
shouldInlineLogicalExpression(n) ||
|
2017-03-19 05:35:09 +03:00
|
|
|
parent.type === "ReturnStatement" ||
|
2017-05-06 07:44:50 +03:00
|
|
|
(parent.type === "JSXExpressionContainer" &&
|
|
|
|
parentParent.type === "JSXAttribute") ||
|
2017-04-19 20:43:48 +03:00
|
|
|
(n === parent.body && parent.type === "ArrowFunctionExpression") ||
|
|
|
|
(n !== parent.body && parent.type === "ForStatement")
|
2017-02-09 18:36:05 +03:00
|
|
|
) {
|
|
|
|
return group(concat(parts));
|
|
|
|
}
|
|
|
|
|
|
|
|
const rest = concat(parts.slice(1));
|
2017-01-19 01:01:17 +03:00
|
|
|
|
2017-02-03 19:50:51 +03:00
|
|
|
return group(
|
|
|
|
concat([
|
2017-01-19 02:31:46 +03:00
|
|
|
// Don't include the initial expression in the indentation
|
|
|
|
// level. The first item is guaranteed to be the first
|
|
|
|
// left-most expression.
|
|
|
|
parts.length > 0 ? parts[0] : "",
|
2017-04-07 05:49:37 +03:00
|
|
|
indent(rest)
|
2017-02-03 19:50:51 +03:00
|
|
|
])
|
|
|
|
);
|
2017-01-19 01:01:17 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "AssignmentPattern":
|
|
|
|
return concat([
|
2017-01-09 20:09:04 +03:00
|
|
|
path.call(print, "left"),
|
2017-01-13 23:03:53 +03:00
|
|
|
" = ",
|
2017-01-09 20:09:04 +03:00
|
|
|
path.call(print, "right")
|
2017-01-13 23:03:53 +03:00
|
|
|
]);
|
|
|
|
case "MemberExpression": {
|
2017-04-11 21:37:35 +03:00
|
|
|
const parent = path.getParentNode();
|
2017-04-14 03:09:00 +03:00
|
|
|
let firstNonMemberParent;
|
|
|
|
let i = 0;
|
|
|
|
do {
|
|
|
|
firstNonMemberParent = path.getParentNode(i);
|
|
|
|
i++;
|
|
|
|
} while (
|
|
|
|
firstNonMemberParent &&
|
|
|
|
firstNonMemberParent.type === "MemberExpression"
|
|
|
|
);
|
|
|
|
|
2017-04-11 21:37:35 +03:00
|
|
|
const shouldInline =
|
2017-04-14 03:09:00 +03:00
|
|
|
firstNonMemberParent && (
|
|
|
|
(firstNonMemberParent.type === "VariableDeclarator" &&
|
2017-04-14 04:31:21 +03:00
|
|
|
firstNonMemberParent.id.type !== "Identifier") ||
|
2017-04-14 03:09:00 +03:00
|
|
|
(firstNonMemberParent.type === "AssignmentExpression" &&
|
2017-04-14 04:31:21 +03:00
|
|
|
firstNonMemberParent.left.type !== "Identifier")) ||
|
2017-04-11 21:37:35 +03:00
|
|
|
n.computed ||
|
|
|
|
(n.object.type === "Identifier" &&
|
|
|
|
n.property.type === "Identifier" &&
|
|
|
|
parent.type !== "MemberExpression");
|
|
|
|
|
2017-01-09 20:09:04 +03:00
|
|
|
return concat([
|
|
|
|
path.call(print, "object"),
|
2017-04-11 21:37:35 +03:00
|
|
|
shouldInline
|
|
|
|
? printMemberLookup(path, options, print)
|
|
|
|
: group(
|
|
|
|
indent(
|
|
|
|
concat([softline, printMemberLookup(path, options, print)])
|
|
|
|
)
|
|
|
|
)
|
2017-01-09 20:09:04 +03:00
|
|
|
]);
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "MetaProperty":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "meta"),
|
|
|
|
".",
|
|
|
|
path.call(print, "property")
|
|
|
|
]);
|
|
|
|
case "BindExpression":
|
|
|
|
if (n.object) {
|
|
|
|
parts.push(path.call(print, "object"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push("::", path.call(print, "callee"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "Path":
|
|
|
|
return join(".", n.body);
|
|
|
|
case "Identifier":
|
2017-04-23 04:09:53 +03:00
|
|
|
var parentNode = path.getParentNode()
|
2017-04-25 19:48:56 +03:00
|
|
|
var isFunctionDeclarationIdentifier =
|
2017-04-23 04:09:53 +03:00
|
|
|
parentNode.type === 'DeclareFunction' &&
|
|
|
|
parentNode.id === n
|
2017-04-25 19:48:56 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
|
|
|
n.name,
|
|
|
|
n.optional ? "?" : "",
|
2017-04-23 04:09:53 +03:00
|
|
|
(n.typeAnnotation && !isFunctionDeclarationIdentifier) ? ": " : "",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
]);
|
|
|
|
case "SpreadElement":
|
|
|
|
case "SpreadElementPattern":
|
|
|
|
// Babel 6 for ObjectPattern
|
|
|
|
case "RestProperty":
|
|
|
|
case "SpreadProperty":
|
|
|
|
case "SpreadPropertyPattern":
|
|
|
|
case "RestElement":
|
2017-04-05 00:52:16 +03:00
|
|
|
case "ObjectTypeSpreadProperty":
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
|
|
|
"...",
|
|
|
|
path.call(print, "argument"),
|
2017-04-23 04:09:53 +03:00
|
|
|
n.typeAnnotation ? ": " : "",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
]);
|
|
|
|
case "FunctionDeclaration":
|
|
|
|
case "FunctionExpression":
|
2017-05-03 03:06:25 +03:00
|
|
|
case "TSNamespaceFunctionDeclaration":
|
2017-04-27 19:37:42 +03:00
|
|
|
if (isNodeStartingWithDeclare(n, options)) {
|
|
|
|
parts.push("declare ");
|
|
|
|
}
|
|
|
|
parts.push(printFunctionDeclaration(path, print, options));
|
|
|
|
return concat(parts);
|
2017-04-11 18:50:49 +03:00
|
|
|
case "ArrowFunctionExpression": {
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.async) {
|
|
|
|
parts.push("async ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-06 05:44:26 +03:00
|
|
|
parts.push(printFunctionTypeParameters(path, options, print));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
if (canPrintParamsWithoutParens(n)) {
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(path.call(print, "params", 0));
|
|
|
|
} else {
|
|
|
|
parts.push(
|
2017-01-24 02:47:11 +03:00
|
|
|
group(
|
2017-01-13 23:03:53 +03:00
|
|
|
concat([
|
2017-04-13 06:24:50 +03:00
|
|
|
printFunctionParams(
|
|
|
|
path,
|
|
|
|
print,
|
|
|
|
options,
|
|
|
|
args && (args.expandLastArg || args.expandFirstArg)
|
|
|
|
),
|
2017-01-13 23:03:53 +03:00
|
|
|
printReturnType(path, print)
|
|
|
|
])
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(" =>");
|
2017-01-11 00:46:33 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
const body = path.call(print, "body");
|
2017-01-28 18:50:22 +03:00
|
|
|
const collapsed = concat([concat(parts), " ", body]);
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-01-24 21:54:01 +03:00
|
|
|
// We want to always keep these types of nodes on the same line
|
|
|
|
// as the arrow.
|
2017-01-15 08:04:50 +03:00
|
|
|
if (
|
2017-01-19 02:31:46 +03:00
|
|
|
n.body.type === "ArrayExpression" ||
|
2017-02-16 06:56:11 +03:00
|
|
|
n.body.type === "ObjectExpression" ||
|
|
|
|
n.body.type === "JSXElement" ||
|
2017-03-09 20:08:12 +03:00
|
|
|
n.body.type === "BlockStatement" ||
|
2017-05-04 00:35:58 +03:00
|
|
|
isTemplateOnItsOwnLine(n.body, options.originalText) ||
|
2017-03-22 23:33:28 +03:00
|
|
|
n.body.type === "ArrowFunctionExpression"
|
2017-01-15 08:04:50 +03:00
|
|
|
) {
|
2017-01-13 23:03:53 +03:00
|
|
|
return group(collapsed);
|
|
|
|
}
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-04-11 18:50:49 +03:00
|
|
|
// if the arrow function is expanded as last argument, we are adding a
|
|
|
|
// level of indentation and need to add a softline to align the closing )
|
|
|
|
// with the opening (.
|
|
|
|
const shouldAddSoftLine = args && args.expandLastArg;
|
|
|
|
|
2017-05-02 00:32:52 +03:00
|
|
|
// In order to avoid confusion between
|
|
|
|
// a => a ? a : a
|
|
|
|
// a <= a ? a : a
|
|
|
|
const shouldAddParens =
|
|
|
|
n.body.type === "ConditionalExpression" &&
|
|
|
|
!util.startsWithNoLookaheadToken(
|
|
|
|
n.body,
|
|
|
|
/* forbidFunctionAndClass */ false
|
|
|
|
);
|
|
|
|
|
2017-01-24 21:54:01 +03:00
|
|
|
return group(
|
2017-03-09 20:08:12 +03:00
|
|
|
concat([
|
|
|
|
concat(parts),
|
2017-04-11 18:50:49 +03:00
|
|
|
group(
|
|
|
|
concat([
|
2017-05-02 00:32:52 +03:00
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
line,
|
|
|
|
shouldAddParens ? ifBreak("", "(") : "",
|
|
|
|
body,
|
|
|
|
shouldAddParens ? ifBreak("", ")") : ""
|
|
|
|
])
|
|
|
|
),
|
2017-04-11 18:50:49 +03:00
|
|
|
shouldAddSoftLine
|
|
|
|
? concat([
|
|
|
|
ifBreak(shouldPrintComma(options, "all") ? "," : ""),
|
|
|
|
softline
|
|
|
|
])
|
2017-04-12 20:16:11 +03:00
|
|
|
: ""
|
2017-04-11 18:50:49 +03:00
|
|
|
])
|
2017-04-12 20:16:11 +03:00
|
|
|
)
|
2017-03-09 20:08:12 +03:00
|
|
|
])
|
2017-01-24 21:54:01 +03:00
|
|
|
);
|
2017-04-11 18:50:49 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "MethodDefinition":
|
2017-04-26 19:25:58 +03:00
|
|
|
case "TSAbstractMethodDefinition":
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.static) {
|
|
|
|
parts.push("static ");
|
|
|
|
}
|
2017-04-26 19:25:58 +03:00
|
|
|
if (n.accessibility) {
|
|
|
|
parts.push(n.accessibility + " ");
|
|
|
|
}
|
|
|
|
if (n.type === "TSAbstractMethodDefinition") {
|
|
|
|
parts.push("abstract ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(printMethod(path, options, print));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "YieldExpression":
|
|
|
|
parts.push("yield");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.delegate) {
|
|
|
|
parts.push("*");
|
|
|
|
}
|
|
|
|
if (n.argument) {
|
|
|
|
parts.push(" ", path.call(print, "argument"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "AwaitExpression":
|
|
|
|
parts.push("await");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.all) {
|
|
|
|
parts.push("*");
|
|
|
|
}
|
|
|
|
if (n.argument) {
|
|
|
|
parts.push(" ", path.call(print, "argument"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ModuleDeclaration":
|
|
|
|
parts.push("module", path.call(print, "id"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.source) {
|
|
|
|
assert.ok(!n.body);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push("from", path.call(print, "source"));
|
|
|
|
} else {
|
|
|
|
parts.push(path.call(print, "body"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return join(" ", parts);
|
|
|
|
case "ImportSpecifier":
|
|
|
|
if (n.imported) {
|
2017-02-15 23:56:34 +03:00
|
|
|
if (n.importKind) {
|
|
|
|
parts.push(path.call(print, "importKind"), " ");
|
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(path.call(print, "imported"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
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"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.name) {
|
|
|
|
parts.push(" as ", path.call(print, "name"));
|
|
|
|
}
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ExportSpecifier":
|
|
|
|
if (n.local) {
|
|
|
|
parts.push(path.call(print, "local"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
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"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.name) {
|
|
|
|
parts.push(" as ", path.call(print, "name"));
|
|
|
|
}
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ExportBatchSpecifier":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "*";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ImportNamespaceSpecifier":
|
|
|
|
parts.push("* as ");
|
|
|
|
|
|
|
|
if (n.local) {
|
|
|
|
parts.push(path.call(print, "local"));
|
|
|
|
} else if (n.id) {
|
|
|
|
parts.push(path.call(print, "id"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ImportDefaultSpecifier":
|
|
|
|
if (n.local) {
|
|
|
|
return path.call(print, "local");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return path.call(print, "id");
|
|
|
|
case "ExportDeclaration":
|
|
|
|
case "ExportDefaultDeclaration":
|
|
|
|
case "ExportNamedDeclaration":
|
|
|
|
return printExportDeclaration(path, options, print);
|
|
|
|
case "ExportAllDeclaration":
|
|
|
|
parts.push("export *");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.exported) {
|
|
|
|
parts.push(" as ", path.call(print, "exported"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(" from ", path.call(print, "source"), semi);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ExportNamespaceSpecifier":
|
|
|
|
case "ExportDefaultSpecifier":
|
|
|
|
return path.call(print, "exported");
|
|
|
|
case "ImportDeclaration":
|
|
|
|
parts.push("import ");
|
|
|
|
|
2017-02-04 00:19:14 +03:00
|
|
|
const fromParts = [];
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.importKind && n.importKind !== "value") {
|
|
|
|
parts.push(n.importKind + " ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-04 00:19:14 +03:00
|
|
|
var standalones = [];
|
|
|
|
var grouped = [];
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.specifiers && n.specifiers.length > 0) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(specifierPath) {
|
|
|
|
var value = specifierPath.getValue();
|
|
|
|
if (
|
|
|
|
namedTypes.ImportDefaultSpecifier.check(value) ||
|
|
|
|
namedTypes.ImportNamespaceSpecifier.check(value)
|
|
|
|
) {
|
|
|
|
standalones.push(print(specifierPath));
|
|
|
|
} else {
|
|
|
|
grouped.push(print(specifierPath));
|
|
|
|
}
|
|
|
|
}, "specifiers");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (standalones.length > 0) {
|
2017-01-22 23:34:00 +03:00
|
|
|
parts.push(join(", ", standalones));
|
Break multiline imports (#167)
Follows the same pattern as https://github.com/jlongster/prettier/pull/156/files
```js
echo "import { aaaaaaaa, bbbbbb, cccccc, dddddddd, eeeeeee, fffffffff, ggggggggg } from 'vjeux';" | ./bin/prettier.js --stdin
import {
aaaaaaaa,
bbbbbb,
cccccc,
dddddddd,
eeeeeee,
fffffffff,
ggggggggg
} from "vjeux";
```
2017-01-13 20:59:33 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (standalones.length > 0 && grouped.length > 0) {
|
|
|
|
parts.push(", ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (grouped.length > 0) {
|
|
|
|
parts.push(
|
2017-01-24 21:54:01 +03:00
|
|
|
group(
|
Break multiline imports (#167)
Follows the same pattern as https://github.com/jlongster/prettier/pull/156/files
```js
echo "import { aaaaaaaa, bbbbbb, cccccc, dddddddd, eeeeeee, fffffffff, ggggggggg } from 'vjeux';" | ./bin/prettier.js --stdin
import {
aaaaaaaa,
bbbbbb,
cccccc,
dddddddd,
eeeeeee,
fffffffff,
ggggggggg
} from "vjeux";
```
2017-01-13 20:59:33 +03:00
|
|
|
concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
"{",
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
options.bracketSpacing ? line : softline,
|
2017-01-28 18:50:22 +03:00
|
|
|
join(concat([",", line]), grouped)
|
2017-01-13 23:03:53 +03:00
|
|
|
])
|
|
|
|
),
|
2017-02-18 06:44:55 +03:00
|
|
|
ifBreak(shouldPrintComma(options) ? "," : ""),
|
Break multiline imports (#167)
Follows the same pattern as https://github.com/jlongster/prettier/pull/156/files
```js
echo "import { aaaaaaaa, bbbbbb, cccccc, dddddddd, eeeeeee, fffffffff, ggggggggg } from 'vjeux';" | ./bin/prettier.js --stdin
import {
aaaaaaaa,
bbbbbb,
cccccc,
dddddddd,
eeeeeee,
fffffffff,
ggggggggg
} from "vjeux";
```
2017-01-13 20:59:33 +03:00
|
|
|
options.bracketSpacing ? line : softline,
|
2017-01-13 23:03:53 +03:00
|
|
|
"}"
|
Break multiline imports (#167)
Follows the same pattern as https://github.com/jlongster/prettier/pull/156/files
```js
echo "import { aaaaaaaa, bbbbbb, cccccc, dddddddd, eeeeeee, fffffffff, ggggggggg } from 'vjeux';" | ./bin/prettier.js --stdin
import {
aaaaaaaa,
bbbbbb,
cccccc,
dddddddd,
eeeeeee,
fffffffff,
ggggggggg
} from "vjeux";
```
2017-01-13 20:59:33 +03:00
|
|
|
])
|
2017-01-13 23:03:53 +03:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-02-04 00:19:14 +03:00
|
|
|
fromParts.push(grouped.length === 0 ? line : " ", "from ");
|
2017-03-06 06:08:42 +03:00
|
|
|
} else if (n.importKind && n.importKind === "type") {
|
|
|
|
parts.push("{} from ");
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
fromParts.push(path.call(print, "source"), semi);
|
2017-02-04 00:19:14 +03:00
|
|
|
|
|
|
|
// If there's a very long import, break the following way:
|
|
|
|
//
|
|
|
|
// import veryLong
|
|
|
|
// from 'verylong'
|
|
|
|
//
|
|
|
|
// In case there are grouped elements, they will already break the way
|
|
|
|
// we want and this break would take precedence instead.
|
|
|
|
if (grouped.length === 0) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return group(concat([concat(parts), indent(concat(fromParts))]));
|
2017-02-04 00:19:14 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-04 00:19:14 +03:00
|
|
|
return concat([concat(parts), concat(fromParts)]);
|
2017-01-25 18:33:48 +03:00
|
|
|
|
|
|
|
case "Import": {
|
|
|
|
return "import";
|
|
|
|
}
|
2017-01-24 20:37:01 +03:00
|
|
|
case "BlockStatement": {
|
2017-04-12 20:16:11 +03:00
|
|
|
var naked = path.call(function(bodyPath) {
|
|
|
|
return printStatementSequence(bodyPath, options, print);
|
|
|
|
}, "body");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-13 06:25:58 +03:00
|
|
|
const hasContent = n.body.find(node => node.type !== "EmptyStatement");
|
2017-01-15 07:39:41 +03:00
|
|
|
const hasDirectives = n.directives && n.directives.length > 0;
|
|
|
|
|
2017-01-24 20:37:01 +03:00
|
|
|
var parent = path.getParentNode();
|
2017-02-23 18:29:05 +03:00
|
|
|
const parentParent = path.getParentNode(1);
|
2017-01-28 18:50:22 +03:00
|
|
|
if (
|
|
|
|
!hasContent &&
|
2017-02-16 06:56:11 +03:00
|
|
|
!hasDirectives &&
|
|
|
|
!n.comments &&
|
|
|
|
(parent.type === "ArrowFunctionExpression" ||
|
|
|
|
parent.type === "FunctionExpression" ||
|
|
|
|
parent.type === "FunctionDeclaration" ||
|
|
|
|
parent.type === "ObjectMethod" ||
|
2017-02-23 18:29:05 +03:00
|
|
|
parent.type === "ClassMethod" ||
|
|
|
|
(parent.type === "CatchClause" && !parentParent.finalizer))
|
2017-01-28 18:50:22 +03:00
|
|
|
) {
|
2017-01-24 20:37:01 +03:00
|
|
|
return "{}";
|
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push("{");
|
|
|
|
|
|
|
|
// Babel 6
|
2017-01-15 07:39:41 +03:00
|
|
|
if (hasDirectives) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(childPath) {
|
|
|
|
parts.push(indent(concat([hardline, print(childPath), semi])));
|
|
|
|
}, "directives");
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-15 07:39:41 +03:00
|
|
|
if (hasContent) {
|
2017-04-07 05:49:37 +03:00
|
|
|
parts.push(indent(concat([hardline, naked])));
|
2017-01-19 22:46:37 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-28 00:09:15 +03:00
|
|
|
parts.push(comments.printDanglingComments(path, options));
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(hardline, "}");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
2017-01-24 20:37:01 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ReturnStatement":
|
|
|
|
parts.push("return");
|
|
|
|
|
2017-03-09 04:06:18 +03:00
|
|
|
if (n.argument) {
|
|
|
|
if (returnArgumentHasLeadingComment(options, n.argument)) {
|
|
|
|
parts.push(
|
|
|
|
concat([
|
|
|
|
" (",
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([softline, path.call(print, "argument")])),
|
2017-03-09 04:06:18 +03:00
|
|
|
line,
|
|
|
|
")"
|
|
|
|
])
|
|
|
|
);
|
2017-03-19 05:35:09 +03:00
|
|
|
} else if (
|
2017-04-12 20:16:11 +03:00
|
|
|
n.argument.type === "LogicalExpression" ||
|
|
|
|
n.argument.type === "BinaryExpression"
|
2017-03-19 05:35:09 +03:00
|
|
|
) {
|
|
|
|
parts.push(
|
2017-04-12 20:16:11 +03:00
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
ifBreak(" (", " "),
|
|
|
|
indent(concat([softline, path.call(print, "argument")])),
|
|
|
|
softline,
|
|
|
|
ifBreak(")")
|
|
|
|
])
|
|
|
|
)
|
2017-03-19 05:35:09 +03:00
|
|
|
);
|
2017-03-09 04:06:18 +03:00
|
|
|
} else {
|
|
|
|
parts.push(" ", path.call(print, "argument"));
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-02 00:41:18 +03:00
|
|
|
if (hasDanglingComments(n)) {
|
2017-04-10 20:46:25 +03:00
|
|
|
parts.push(
|
|
|
|
" ",
|
2017-04-12 20:16:11 +03:00
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true)
|
2017-04-10 20:46:25 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "CallExpression": {
|
2017-03-04 00:48:29 +03:00
|
|
|
if (
|
|
|
|
// We want to keep require calls as a unit
|
2017-03-04 02:39:37 +03:00
|
|
|
(n.callee.type === "Identifier" && n.callee.name === "require") ||
|
2017-05-02 00:27:00 +03:00
|
|
|
// Template literals as single arguments
|
2017-05-04 00:35:58 +03:00
|
|
|
(n.arguments.length === 1 &&
|
|
|
|
isTemplateOnItsOwnLine(n.arguments[0], options.originalText)) ||
|
2017-03-09 00:24:28 +03:00
|
|
|
// Keep test declarations on a single line
|
|
|
|
// e.g. `it('long name', () => {`
|
2017-03-04 02:39:37 +03:00
|
|
|
(n.callee.type === "Identifier" &&
|
2017-03-09 00:24:28 +03:00
|
|
|
(n.callee.name === "it" ||
|
|
|
|
n.callee.name === "test" ||
|
|
|
|
n.callee.name === "describe") &&
|
2017-03-04 00:48:29 +03:00
|
|
|
n.arguments.length === 2 &&
|
2017-03-04 02:39:37 +03:00
|
|
|
(n.arguments[0].type === "StringLiteral" ||
|
2017-03-07 19:36:03 +03:00
|
|
|
n.arguments[0].type === "TemplateLiteral" ||
|
2017-03-04 02:39:37 +03:00
|
|
|
(n.arguments[0].type === "Literal" &&
|
|
|
|
typeof n.arguments[0].value === "string")) &&
|
|
|
|
(n.arguments[1].type === "FunctionExpression" ||
|
|
|
|
n.arguments[1].type === "ArrowFunctionExpression") &&
|
2017-03-04 00:48:29 +03:00
|
|
|
n.arguments[1].params.length <= 1)
|
|
|
|
) {
|
2017-03-03 06:21:02 +03:00
|
|
|
return concat([
|
|
|
|
path.call(print, "callee"),
|
2017-03-19 18:06:52 +03:00
|
|
|
path.call(print, "typeParameters"),
|
2017-03-03 06:21:02 +03:00
|
|
|
concat(["(", join(", ", path.map(print, "arguments")), ")"])
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2017-03-04 00:48:29 +03:00
|
|
|
// We detect calls on member lookups and possibly print them in a
|
|
|
|
// special chain format. See `printMemberChain` for more info.
|
|
|
|
if (n.callee.type === "MemberExpression") {
|
|
|
|
return printMemberChain(path, options, print);
|
|
|
|
}
|
|
|
|
|
2017-01-09 20:09:04 +03:00
|
|
|
return concat([
|
|
|
|
path.call(print, "callee"),
|
2017-05-06 05:44:26 +03:00
|
|
|
printFunctionTypeParameters(path, options, print),
|
2017-01-09 20:09:04 +03:00
|
|
|
printArgumentsList(path, options, print)
|
|
|
|
]);
|
|
|
|
}
|
2017-01-05 23:26:45 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ObjectExpression":
|
|
|
|
case "ObjectPattern":
|
|
|
|
case "ObjectTypeAnnotation":
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSInterfaceDeclaration":
|
2017-05-02 05:12:53 +03:00
|
|
|
case "TSTypeLiteral": {
|
2017-01-13 23:03:53 +03:00
|
|
|
var isTypeAnnotation = n.type === "ObjectTypeAnnotation";
|
2017-05-05 05:06:30 +03:00
|
|
|
var isTypeScriptTypeAnnotation = n.type === "TSTypeLiteral";
|
2017-05-03 03:06:25 +03:00
|
|
|
var isTypeScriptInterfaceDeclaration = n.type === "TSInterfaceDeclaration";
|
2017-05-05 05:06:30 +03:00
|
|
|
var isTypeScriptType = isTypeScriptTypeAnnotation || isTypeScriptInterfaceDeclaration;
|
2017-01-13 23:03:53 +03:00
|
|
|
// Leave this here because we *might* want to make this
|
2017-04-05 23:28:02 +03:00
|
|
|
// configurable later -- flow accepts ";" for type separators,
|
2017-03-19 18:06:52 +03:00
|
|
|
// typescript accepts ";" and newlines
|
2017-01-13 23:03:53 +03:00
|
|
|
var separator = isTypeAnnotation ? "," : ",";
|
|
|
|
var fields = [];
|
2017-05-03 18:01:45 +03:00
|
|
|
var prefix = [];
|
2017-01-13 23:03:53 +03:00
|
|
|
var leftBrace = n.exact ? "{|" : "{";
|
|
|
|
var rightBrace = n.exact ? "|}" : "}";
|
2017-02-13 20:03:56 +03:00
|
|
|
var parent = path.getParentNode(0);
|
2017-02-16 06:56:11 +03:00
|
|
|
var parentIsUnionTypeAnnotation = parent.type === "UnionTypeAnnotation";
|
2017-05-02 00:42:52 +03:00
|
|
|
var propertiesField = isTypeScriptType
|
2017-04-12 20:16:11 +03:00
|
|
|
? "members"
|
|
|
|
: "properties";
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
if (isTypeAnnotation) {
|
|
|
|
fields.push("indexers", "callProperties");
|
|
|
|
}
|
2017-05-01 19:25:49 +03:00
|
|
|
if (isTypeScriptInterfaceDeclaration) {
|
2017-05-03 03:06:25 +03:00
|
|
|
prefix.push(
|
|
|
|
printTypeScriptModifiers(path, options, print),
|
2017-05-01 19:25:49 +03:00
|
|
|
"interface ",
|
|
|
|
path.call(print, "name"),
|
2017-05-03 18:01:45 +03:00
|
|
|
printTypeParameters(path, options, print, "typeParameters"),
|
|
|
|
" "
|
2017-05-04 21:20:52 +03:00
|
|
|
);
|
2017-05-03 18:01:45 +03:00
|
|
|
}
|
|
|
|
if (n.heritageClauses) {
|
|
|
|
prefix.push(
|
|
|
|
"extends ",
|
|
|
|
join(", ", path.map(print, "heritageClauses")),
|
2017-05-01 19:25:49 +03:00
|
|
|
" "
|
2017-05-03 03:06:25 +03:00
|
|
|
);
|
2017-05-01 19:25:49 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
fields.push(propertiesField);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-02 00:42:52 +03:00
|
|
|
// Unfortunately, things are grouped together in the ast can be
|
|
|
|
// interleaved in the source code. So we need to reorder them before
|
|
|
|
// printing them.
|
|
|
|
const propsAndLoc = [];
|
2017-01-13 23:03:53 +03:00
|
|
|
fields.forEach(function(field) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(childPath) {
|
2017-05-02 00:42:52 +03:00
|
|
|
const node = childPath.getValue();
|
|
|
|
propsAndLoc.push({
|
|
|
|
node: node,
|
|
|
|
printed: print(childPath),
|
|
|
|
loc: util.locStart(node)
|
|
|
|
});
|
|
|
|
}, field);
|
|
|
|
});
|
2017-04-12 20:16:11 +03:00
|
|
|
|
2017-05-02 00:42:52 +03:00
|
|
|
let separatorParts = [];
|
|
|
|
const props = propsAndLoc
|
|
|
|
.sort((a, b) => a.loc - b.loc)
|
|
|
|
.map(prop => {
|
|
|
|
const result = concat(separatorParts.concat(group(prop.printed)));
|
2017-04-12 20:16:11 +03:00
|
|
|
separatorParts = [separator, line];
|
|
|
|
if (
|
2017-05-02 00:42:52 +03:00
|
|
|
util.isNextLineEmpty(options.originalText, prop.node)
|
2017-04-12 20:16:11 +03:00
|
|
|
) {
|
|
|
|
separatorParts.push(hardline);
|
|
|
|
}
|
2017-05-02 00:42:52 +03:00
|
|
|
return result;
|
|
|
|
});
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
const lastElem = util.getLast(n[propertiesField]);
|
2017-04-13 17:10:08 +03:00
|
|
|
|
|
|
|
const canHaveTrailingComma = !(
|
|
|
|
lastElem &&
|
|
|
|
(lastElem.type === "RestProperty" || lastElem.type === "RestElement")
|
|
|
|
);
|
2017-01-30 18:07:03 +03:00
|
|
|
|
2017-05-02 00:49:03 +03:00
|
|
|
let content;
|
|
|
|
if (props.length === 0 && !n.typeAnnotation) {
|
2017-05-02 00:41:18 +03:00
|
|
|
if (!hasDanglingComments(n)) {
|
2017-05-03 03:06:25 +03:00
|
|
|
return concat([concat(prefix), leftBrace, rightBrace]);
|
2017-05-02 00:41:18 +03:00
|
|
|
}
|
|
|
|
|
2017-05-02 00:49:03 +03:00
|
|
|
content = group(
|
2017-01-31 17:52:05 +03:00
|
|
|
concat([
|
2017-05-03 03:06:25 +03:00
|
|
|
concat(prefix),
|
2017-04-03 20:24:36 +03:00
|
|
|
leftBrace,
|
2017-01-31 17:52:05 +03:00
|
|
|
comments.printDanglingComments(path, options),
|
|
|
|
softline,
|
2017-04-03 20:24:36 +03:00
|
|
|
rightBrace
|
2017-01-31 17:52:05 +03:00
|
|
|
])
|
|
|
|
);
|
2017-01-13 23:03:53 +03:00
|
|
|
} else {
|
2017-05-02 00:49:03 +03:00
|
|
|
content = concat([
|
2017-05-03 03:06:25 +03:00
|
|
|
concat(prefix),
|
2017-05-02 00:49:03 +03:00
|
|
|
leftBrace,
|
|
|
|
indent(
|
2017-04-07 05:49:37 +03:00
|
|
|
align(
|
2017-02-13 20:03:56 +03:00
|
|
|
parentIsUnionTypeAnnotation ? 2 : 0,
|
2017-05-02 00:49:03 +03:00
|
|
|
concat([
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
concat(props)
|
|
|
|
])
|
|
|
|
)
|
|
|
|
),
|
|
|
|
ifBreak(
|
|
|
|
canHaveTrailingComma && shouldPrintComma(options) ? "," : ""
|
|
|
|
),
|
|
|
|
align(
|
|
|
|
parentIsUnionTypeAnnotation ? 2 : 0,
|
|
|
|
concat([options.bracketSpacing ? line : softline, rightBrace])
|
|
|
|
),
|
|
|
|
n.typeAnnotation ? ": " : "",
|
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we inline the object as first argument of the parent, we don't want
|
|
|
|
// to create another group so that the object breaks before the return
|
|
|
|
// type
|
2017-05-02 05:12:53 +03:00
|
|
|
const parentParentParent = path.getParentNode(2);
|
2017-05-02 00:49:03 +03:00
|
|
|
if (
|
2017-05-02 05:12:53 +03:00
|
|
|
(n.type === "ObjectPattern" &&
|
|
|
|
parent &&
|
|
|
|
shouldHugArguments(parent) &&
|
|
|
|
parent.params[0] === n) ||
|
|
|
|
(n.type === "ObjectTypeAnnotation" &&
|
|
|
|
parentParentParent &&
|
|
|
|
shouldHugArguments(parentParentParent) &&
|
|
|
|
parentParentParent.params[0].typeAnnotation.typeAnnotation === n)
|
2017-05-02 00:49:03 +03:00
|
|
|
) {
|
|
|
|
return content;
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
|
|
|
|
2017-05-02 00:49:03 +03:00
|
|
|
const shouldBreak =
|
|
|
|
n.type !== "ObjectPattern" &&
|
|
|
|
util.hasNewlineInRange(
|
|
|
|
options.originalText,
|
|
|
|
util.locStart(n),
|
|
|
|
util.locEnd(n)
|
|
|
|
);
|
|
|
|
|
|
|
|
return group(content, { shouldBreak });
|
2017-05-02 05:12:53 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "PropertyPattern":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "key"),
|
|
|
|
": ",
|
|
|
|
path.call(print, "pattern")
|
|
|
|
]);
|
|
|
|
// Babel 6
|
2017-01-28 18:50:22 +03:00
|
|
|
case "ObjectProperty": // Non-standard AST node type.
|
|
|
|
case "Property":
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.method || n.kind === "get" || n.kind === "set") {
|
|
|
|
return printMethod(path, options, print);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n.shorthand) {
|
|
|
|
parts.push(path.call(print, "value"));
|
|
|
|
} else {
|
|
|
|
if (n.computed) {
|
|
|
|
parts.push("[", path.call(print, "key"), "]");
|
|
|
|
} else {
|
2017-01-19 20:37:24 +03:00
|
|
|
parts.push(printPropertyKey(path, options, print));
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2017-02-15 18:20:37 +03:00
|
|
|
parts.push(concat([": ", path.call(print, "value")]));
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
|
|
|
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(parts); // Babel 6
|
|
|
|
case "ClassMethod":
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.static) {
|
|
|
|
parts.push("static ");
|
|
|
|
}
|
|
|
|
|
|
|
|
parts = parts.concat(printObjectMethod(path, options, print));
|
|
|
|
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(parts); // Babel 6
|
|
|
|
case "ObjectMethod":
|
2017-01-13 23:03:53 +03:00
|
|
|
return printObjectMethod(path, options, print);
|
2017-05-03 02:03:23 +03:00
|
|
|
case "TSDecorator":
|
2017-01-13 23:03:53 +03:00
|
|
|
case "Decorator":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["@", path.call(print, "expression")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ArrayExpression":
|
2017-01-23 07:52:30 +03:00
|
|
|
case "ArrayPattern":
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.elements.length === 0) {
|
2017-05-02 00:41:18 +03:00
|
|
|
if (!hasDanglingComments(n)) {
|
|
|
|
parts.push("[]");
|
|
|
|
} else {
|
|
|
|
parts.push(
|
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
"[",
|
|
|
|
comments.printDanglingComments(path, options),
|
|
|
|
softline,
|
|
|
|
"]"
|
|
|
|
])
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
} else {
|
2017-01-23 02:20:47 +03:00
|
|
|
const lastElem = util.getLast(n.elements);
|
2017-01-23 20:49:46 +03:00
|
|
|
const canHaveTrailingComma = !(lastElem &&
|
|
|
|
lastElem.type === "RestElement");
|
2017-01-23 02:20:47 +03:00
|
|
|
|
2017-01-16 20:53:39 +03:00
|
|
|
// JavaScript allows you to have empty elements in an array which
|
|
|
|
// changes its length based on the number of commas. The algorithm
|
|
|
|
// is that if the last argument is null, we need to force insert
|
|
|
|
// a comma to ensure JavaScript recognizes it.
|
|
|
|
// [,].length === 1
|
|
|
|
// [1,].length === 1
|
|
|
|
// [1,,].length === 2
|
|
|
|
//
|
|
|
|
// Note that util.getLast returns null if the array is empty, but
|
|
|
|
// we already check for an empty array just above so we are safe
|
2017-04-12 20:16:11 +03:00
|
|
|
const needsForcedTrailingComma =
|
|
|
|
canHaveTrailingComma && lastElem === null;
|
2017-01-16 20:53:39 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(
|
2017-01-24 21:54:01 +03:00
|
|
|
group(
|
2017-01-13 23:03:53 +03:00
|
|
|
concat([
|
|
|
|
"[",
|
|
|
|
indent(
|
2017-03-15 19:35:22 +03:00
|
|
|
concat([
|
|
|
|
softline,
|
|
|
|
printArrayItems(path, options, "elements", print)
|
|
|
|
])
|
2017-01-13 23:03:53 +03:00
|
|
|
),
|
2017-01-16 20:53:39 +03:00
|
|
|
needsForcedTrailingComma ? "," : "",
|
2017-01-23 02:20:47 +03:00
|
|
|
ifBreak(
|
|
|
|
canHaveTrailingComma &&
|
2017-01-23 20:49:46 +03:00
|
|
|
!needsForcedTrailingComma &&
|
2017-02-18 06:44:55 +03:00
|
|
|
shouldPrintComma(options)
|
2017-01-23 20:49:46 +03:00
|
|
|
? ","
|
|
|
|
: ""
|
2017-01-23 02:20:47 +03:00
|
|
|
),
|
2017-02-23 20:57:51 +03:00
|
|
|
comments.printDanglingComments(
|
|
|
|
path,
|
|
|
|
options,
|
|
|
|
/* sameIndent */ true
|
|
|
|
),
|
2017-01-24 22:38:12 +03:00
|
|
|
softline,
|
2017-01-13 23:03:53 +03:00
|
|
|
"]"
|
|
|
|
])
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.typeAnnotation) {
|
|
|
|
parts.push(": ", path.call(print, "typeAnnotation"));
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "SequenceExpression":
|
|
|
|
return join(", ", path.map(print, "expressions"));
|
|
|
|
case "ThisExpression":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "this";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "Super":
|
2017-04-19 20:24:13 +03:00
|
|
|
return "super";
|
|
|
|
// Babel 6 Literal split
|
2017-01-28 18:50:22 +03:00
|
|
|
case "NullLiteral":
|
2017-04-19 20:24:13 +03:00
|
|
|
return "null";
|
|
|
|
// Babel 6 Literal split
|
2017-01-28 18:50:22 +03:00
|
|
|
case "RegExpLiteral":
|
2017-04-19 20:24:13 +03:00
|
|
|
return printRegex(n);
|
2017-01-13 23:03:53 +03:00
|
|
|
// Babel 6 Literal split
|
|
|
|
case "NumericLiteral":
|
2017-01-30 20:36:23 +03:00
|
|
|
return printNumber(n.extra.raw);
|
2017-01-17 07:01:51 +03:00
|
|
|
// Babel 6 Literal split
|
|
|
|
case "BooleanLiteral":
|
2017-01-13 23:03:53 +03:00
|
|
|
// Babel 6 Literal split
|
|
|
|
case "StringLiteral":
|
|
|
|
case "Literal":
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.regex) {
|
|
|
|
return printRegex(n.regex);
|
|
|
|
}
|
2017-05-06 07:39:11 +03:00
|
|
|
if (typeof n.value === "number") {
|
|
|
|
return printNumber(n.raw);
|
|
|
|
}
|
2017-05-03 03:06:25 +03:00
|
|
|
if (typeof n.value !== "string") {
|
|
|
|
return "" + n.value;
|
|
|
|
}
|
2017-01-28 18:50:22 +03:00
|
|
|
return nodeStr(n, options); // Babel 6
|
|
|
|
case "Directive":
|
|
|
|
return path.call(print, "value"); // Babel 6
|
|
|
|
case "DirectiveLiteral":
|
2017-01-20 00:20:03 +03:00
|
|
|
return nodeStr(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
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.
|
2017-01-20 00:20:03 +03:00
|
|
|
return nodeStr(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "UnaryExpression":
|
|
|
|
parts.push(n.operator);
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (/[a-z]$/.test(n.operator)) {
|
|
|
|
parts.push(" ");
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
parts.push(path.call(print, "argument"));
|
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "UpdateExpression":
|
|
|
|
parts.push(path.call(print, "argument"), n.operator);
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.prefix) {
|
|
|
|
parts.reverse();
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "ConditionalExpression":
|
|
|
|
return group(
|
2017-01-09 20:09:04 +03:00
|
|
|
concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "test"),
|
2017-01-09 20:09:04 +03:00
|
|
|
indent(
|
|
|
|
concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
line,
|
|
|
|
"? ",
|
2017-05-02 00:28:36 +03:00
|
|
|
n.consequent.type === "ConditionalExpression" ? ifBreak("", "(") : "",
|
2017-04-07 05:49:37 +03:00
|
|
|
align(2, path.call(print, "consequent")),
|
2017-05-02 00:28:36 +03:00
|
|
|
n.consequent.type === "ConditionalExpression" ? ifBreak("", ")") : "",
|
2017-01-13 23:03:53 +03:00
|
|
|
line,
|
|
|
|
": ",
|
2017-04-07 05:49:37 +03:00
|
|
|
align(2, path.call(print, "alternate"))
|
2017-01-09 20:09:04 +03:00
|
|
|
])
|
2017-01-13 23:03:53 +03:00
|
|
|
)
|
2017-01-09 20:09:04 +03:00
|
|
|
])
|
|
|
|
);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "NewExpression":
|
2017-05-06 05:44:26 +03:00
|
|
|
parts.push(
|
|
|
|
"new ",
|
|
|
|
path.call(print, "callee"),
|
|
|
|
printFunctionTypeParameters(path, options, print)
|
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-06 05:44:26 +03:00
|
|
|
if (n.arguments) {
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(printArgumentsList(path, options, print));
|
2017-01-11 08:48:49 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "VariableDeclaration":
|
2017-04-12 20:16:11 +03:00
|
|
|
var printed = path.map(function(childPath) {
|
|
|
|
return print(childPath);
|
|
|
|
}, "declarations");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts = [
|
2017-04-27 19:37:42 +03:00
|
|
|
isNodeStartingWithDeclare(n, options) ? "declare " : "",
|
2017-01-13 23:03:53 +03:00
|
|
|
n.kind,
|
|
|
|
" ",
|
2017-01-19 02:31:46 +03:00
|
|
|
printed[0],
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat(printed.slice(1).map(p => concat([",", line, p]))))
|
2017-01-13 23:03:53 +03:00
|
|
|
];
|
|
|
|
|
|
|
|
// We generally want to terminate all variable declarations with a
|
2017-01-22 23:34:14 +03:00
|
|
|
// semicolon, except when they in the () part of for loops.
|
2017-01-13 23:03:53 +03:00
|
|
|
var parentNode = path.getParentNode();
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
var isParentForLoop =
|
|
|
|
namedTypes.ForStatement.check(parentNode) ||
|
2017-01-23 20:49:46 +03:00
|
|
|
namedTypes.ForInStatement.check(parentNode) ||
|
2017-02-23 20:57:51 +03:00
|
|
|
(namedTypes.ForOfStatement &&
|
|
|
|
namedTypes.ForOfStatement.check(parentNode)) ||
|
|
|
|
(namedTypes.ForAwaitStatement &&
|
|
|
|
namedTypes.ForAwaitStatement.check(parentNode));
|
2017-01-22 23:34:14 +03:00
|
|
|
|
|
|
|
if (!(isParentForLoop && parentNode.body !== n)) {
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
|
|
|
|
2017-01-24 21:54:01 +03:00
|
|
|
return group(concat(parts));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "VariableDeclarator":
|
2017-03-15 19:45:40 +03:00
|
|
|
return printAssignment(
|
2017-04-14 03:09:00 +03:00
|
|
|
n.id,
|
2017-04-26 00:08:30 +03:00
|
|
|
concat([path.call(print, "id"), path.call(print, "typeParameters")]),
|
2017-03-15 19:45:40 +03:00
|
|
|
"=",
|
|
|
|
n.init,
|
|
|
|
n.init && path.call(print, "init"),
|
|
|
|
options
|
|
|
|
);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "WithStatement":
|
2017-05-04 01:50:48 +03:00
|
|
|
return group(concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
"with (",
|
|
|
|
path.call(print, "object"),
|
2017-01-16 20:54:39 +03:00
|
|
|
")",
|
2017-04-13 06:25:44 +03:00
|
|
|
adjustClause(n.body, path.call(print, "body"))
|
2017-05-04 01:50:48 +03:00
|
|
|
]));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "IfStatement":
|
2017-04-13 06:25:44 +03:00
|
|
|
const con = adjustClause(n.consequent, path.call(print, "consequent"));
|
2017-04-12 20:16:11 +03:00
|
|
|
const opening = group(
|
|
|
|
concat([
|
|
|
|
"if (",
|
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
indent(concat([softline, path.call(print, "test")])),
|
|
|
|
softline
|
|
|
|
])
|
2017-03-18 00:02:35 +03:00
|
|
|
),
|
2017-04-12 20:16:11 +03:00
|
|
|
")",
|
|
|
|
con
|
|
|
|
])
|
|
|
|
);
|
2017-03-18 00:02:35 +03:00
|
|
|
|
|
|
|
parts.push(opening);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.alternate) {
|
2017-04-13 06:25:44 +03:00
|
|
|
if (n.consequent.type === "BlockStatement") {
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(" else");
|
|
|
|
} else {
|
2017-03-18 00:02:35 +03:00
|
|
|
parts.push(hardline, "else");
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(
|
2017-04-12 20:16:11 +03:00
|
|
|
group(
|
|
|
|
adjustClause(
|
2017-04-13 06:25:44 +03:00
|
|
|
n.alternate,
|
2017-04-12 20:16:11 +03:00
|
|
|
path.call(print, "alternate"),
|
|
|
|
n.alternate.type === "IfStatement"
|
|
|
|
)
|
|
|
|
)
|
2017-01-13 23:03:53 +03:00
|
|
|
);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-18 00:02:35 +03:00
|
|
|
return concat(parts);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ForStatement": {
|
2017-04-13 06:25:44 +03:00
|
|
|
const body = adjustClause(n.body, path.call(print, "body"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-20 18:15:46 +03:00
|
|
|
// We want to keep dangling comments above the loop to stay consistent.
|
|
|
|
// Any comment positioned between the for statement and the parentheses
|
|
|
|
// is going to be printed before the statement.
|
2017-02-23 20:57:51 +03:00
|
|
|
const dangling = comments.printDanglingComments(
|
|
|
|
path,
|
|
|
|
options,
|
|
|
|
/* sameLine */ true
|
|
|
|
);
|
2017-02-20 17:17:10 +03:00
|
|
|
const printedComments = dangling ? concat([dangling, softline]) : "";
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (!n.init && !n.test && !n.update) {
|
2017-05-04 01:50:48 +03:00
|
|
|
return concat([printedComments, group(concat(["for (;;)", body]))]);
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
2017-02-20 17:17:10 +03:00
|
|
|
printedComments,
|
2017-05-04 01:50:48 +03:00
|
|
|
group(concat([
|
|
|
|
"for (",
|
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
softline,
|
|
|
|
path.call(print, "init"),
|
|
|
|
";",
|
|
|
|
line,
|
|
|
|
path.call(print, "test"),
|
|
|
|
";",
|
|
|
|
line,
|
|
|
|
path.call(print, "update")
|
|
|
|
])
|
|
|
|
),
|
|
|
|
softline
|
|
|
|
])
|
|
|
|
),
|
|
|
|
")",
|
|
|
|
body
|
|
|
|
]))
|
2017-01-13 23:03:53 +03:00
|
|
|
]);
|
2016-12-31 07:03:22 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "WhileStatement":
|
2017-05-04 01:50:48 +03:00
|
|
|
return group(concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
"while (",
|
2017-01-20 20:42:16 +03:00
|
|
|
group(
|
|
|
|
concat([
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([softline, path.call(print, "test")])),
|
2017-01-20 20:42:16 +03:00
|
|
|
softline
|
|
|
|
])
|
|
|
|
),
|
2017-01-13 23:03:53 +03:00
|
|
|
")",
|
2017-04-13 06:25:44 +03:00
|
|
|
adjustClause(n.body, path.call(print, "body"))
|
2017-05-04 01:50:48 +03:00
|
|
|
]));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ForInStatement":
|
|
|
|
// Note: esprima can't actually parse "for each (".
|
2017-05-04 01:50:48 +03:00
|
|
|
return group(concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
n.each ? "for each (" : "for (",
|
|
|
|
path.call(print, "left"),
|
|
|
|
" in ",
|
|
|
|
path.call(print, "right"),
|
|
|
|
")",
|
2017-04-13 06:25:44 +03:00
|
|
|
adjustClause(n.body, path.call(print, "body"))
|
2017-05-04 01:50:48 +03:00
|
|
|
]));
|
2017-03-22 19:23:57 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ForOfStatement":
|
|
|
|
case "ForAwaitStatement":
|
2017-04-05 23:28:02 +03:00
|
|
|
// Babylon 7 removed ForAwaitStatement in favor of ForOfStatement
|
2017-03-22 19:23:57 +03:00
|
|
|
// with `"await": true`:
|
|
|
|
// https://github.com/estree/estree/pull/138
|
2017-04-12 20:16:11 +03:00
|
|
|
const isAwait = n.type === "ForAwaitStatement" || n.await;
|
2017-03-22 19:23:57 +03:00
|
|
|
|
2017-05-04 01:50:48 +03:00
|
|
|
return group(concat([
|
2017-03-22 19:23:57 +03:00
|
|
|
"for",
|
|
|
|
isAwait ? " await" : "",
|
|
|
|
" (",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "left"),
|
|
|
|
" of ",
|
|
|
|
path.call(print, "right"),
|
|
|
|
")",
|
2017-04-13 06:25:44 +03:00
|
|
|
adjustClause(n.body, path.call(print, "body"))
|
2017-05-04 01:50:48 +03:00
|
|
|
]));
|
2017-03-22 19:23:57 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
case "DoWhileStatement":
|
2017-04-13 06:25:44 +03:00
|
|
|
var clause = adjustClause(n.body, path.call(print, "body"));
|
2017-05-04 01:50:48 +03:00
|
|
|
var doBody = group(concat(["do", clause]));
|
2017-01-28 18:50:22 +03:00
|
|
|
var parts = [doBody];
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-13 06:25:44 +03:00
|
|
|
if (n.body.type === "BlockStatement") {
|
|
|
|
parts.push(" ");
|
|
|
|
} else {
|
|
|
|
parts.push(hardline);
|
|
|
|
}
|
2017-04-21 18:03:53 +03:00
|
|
|
parts.push("while (");
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-21 18:03:53 +03:00
|
|
|
parts.push(group(
|
|
|
|
concat([
|
|
|
|
indent(softline), path.call(print, "test"),
|
|
|
|
softline
|
|
|
|
])
|
|
|
|
), ")", semi);
|
2017-01-13 23:03:53 +03:00
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "DoExpression":
|
2017-02-27 18:49:08 +03:00
|
|
|
return concat(["do ", path.call(print, "body")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "BreakStatement":
|
|
|
|
parts.push("break");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.label) {
|
|
|
|
parts.push(" ", path.call(print, "label"));
|
|
|
|
}
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ContinueStatement":
|
|
|
|
parts.push("continue");
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.label) {
|
|
|
|
parts.push(" ", path.call(print, "label"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "LabeledStatement":
|
2017-01-22 23:34:27 +03:00
|
|
|
if (n.body.type === "EmptyStatement") {
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat([path.call(print, "label"), ":;"]);
|
2017-01-22 23:34:27 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
|
|
|
path.call(print, "label"),
|
2017-03-04 00:46:40 +03:00
|
|
|
": ",
|
2017-01-13 23:03:53 +03:00
|
|
|
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) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(handlerPath) {
|
|
|
|
parts.push(" ", print(handlerPath));
|
|
|
|
}, "handlers");
|
2017-01-05 20:10:14 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
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"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(") ", path.call(print, "body"));
|
2017-01-13 21:00:32 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ThrowStatement":
|
2017-04-11 23:50:47 +03:00
|
|
|
return concat(["throw ", path.call(print, "argument"), semi]);
|
2017-01-13 23:03:53 +03:00
|
|
|
// Note: ignoring n.lexical because it has no printing consequences.
|
|
|
|
case "SwitchStatement":
|
2017-01-13 21:00:32 +03:00
|
|
|
return concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
"switch (",
|
|
|
|
path.call(print, "discriminant"),
|
|
|
|
") {",
|
2017-01-23 20:49:46 +03:00
|
|
|
n.cases.length > 0
|
2017-04-12 20:16:11 +03:00
|
|
|
? indent(concat([hardline, join(hardline, path.map(print, "cases"))]))
|
2017-01-23 20:49:46 +03:00
|
|
|
: "",
|
2017-01-13 23:03:53 +03:00
|
|
|
hardline,
|
|
|
|
"}"
|
2017-01-13 21:00:32 +03:00
|
|
|
]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "SwitchCase":
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.test) {
|
|
|
|
parts.push("case ", path.call(print, "test"), ":");
|
|
|
|
} else {
|
|
|
|
parts.push("default:");
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
|
2017-04-06 02:27:14 +03:00
|
|
|
const isFirstCase = path.getNode() === path.getParentNode().cases[0];
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
if (
|
|
|
|
!isFirstCase &&
|
|
|
|
util.isPreviousLineEmpty(options.originalText, path.getValue())
|
|
|
|
) {
|
2017-04-06 02:27:14 +03:00
|
|
|
parts.unshift(hardline);
|
|
|
|
}
|
|
|
|
|
2017-01-22 23:33:21 +03:00
|
|
|
if (n.consequent.find(node => node.type !== "EmptyStatement")) {
|
2017-03-17 18:08:36 +03:00
|
|
|
const cons = path.call(consequentPath => {
|
2017-04-12 20:16:11 +03:00
|
|
|
return join(
|
|
|
|
hardline,
|
2017-04-13 03:26:31 +03:00
|
|
|
consequentPath
|
|
|
|
.map((p, i) => {
|
|
|
|
if (n.consequent[i].type === "EmptyStatement") {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const shouldAddLine =
|
|
|
|
i !== n.consequent.length - 1 &&
|
|
|
|
util.isNextLineEmpty(options.originalText, p.getValue());
|
|
|
|
return concat([print(p), shouldAddLine ? hardline : ""]);
|
|
|
|
})
|
|
|
|
.filter(e => e !== null)
|
2017-04-12 20:16:11 +03:00
|
|
|
);
|
2017-03-17 18:08:36 +03:00
|
|
|
}, "consequent");
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(
|
2017-04-13 06:25:44 +03:00
|
|
|
n.consequent.length === 1 && n.consequent[0].type === "BlockStatement"
|
2017-01-28 18:50:22 +03:00
|
|
|
? concat([" ", cons])
|
2017-04-07 05:49:37 +03:00
|
|
|
: indent(concat([hardline, cons]))
|
2017-01-13 23:03:53 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
// JSX extensions below.
|
|
|
|
case "DebuggerStatement":
|
2017-04-11 23:50:47 +03:00
|
|
|
return concat(["debugger", semi]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "JSXAttribute":
|
|
|
|
parts.push(path.call(print, "name"));
|
|
|
|
|
|
|
|
if (n.value) {
|
|
|
|
let res;
|
|
|
|
if (
|
|
|
|
(n.value.type === "StringLiteral" || n.value.type === "Literal") &&
|
2017-02-16 06:56:11 +03:00
|
|
|
typeof n.value.value === "string"
|
2017-01-13 23:03:53 +03:00
|
|
|
) {
|
2017-04-08 17:55:50 +03:00
|
|
|
const value = n.value.extra ? n.value.extra.raw : n.value.raw;
|
2017-05-03 18:47:15 +03:00
|
|
|
res = '"' + value.slice(1, -1).replace(/"/g, """) + '"';
|
2017-01-13 23:03:53 +03:00
|
|
|
} else {
|
|
|
|
res = path.call(print, "value");
|
|
|
|
}
|
|
|
|
parts.push("=", res);
|
|
|
|
}
|
2017-01-13 21:00:32 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "JSXIdentifier":
|
2017-01-20 00:20:03 +03:00
|
|
|
return "" + n.name;
|
2017-01-13 23:03:53 +03:00
|
|
|
case "JSXNamespacedName":
|
|
|
|
return join(":", [
|
|
|
|
path.call(print, "namespace"),
|
|
|
|
path.call(print, "name")
|
|
|
|
]);
|
|
|
|
case "JSXMemberExpression":
|
|
|
|
return join(".", [
|
|
|
|
path.call(print, "object"),
|
|
|
|
path.call(print, "property")
|
|
|
|
]);
|
|
|
|
case "JSXSpreadAttribute":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["{...", path.call(print, "argument"), "}"]);
|
2017-01-26 22:51:08 +03:00
|
|
|
case "JSXExpressionContainer": {
|
|
|
|
const parent = path.getParentNode(0);
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const shouldInline =
|
|
|
|
n.expression.type === "ArrayExpression" ||
|
2017-01-26 22:51:08 +03:00
|
|
|
n.expression.type === "ObjectExpression" ||
|
|
|
|
n.expression.type === "ArrowFunctionExpression" ||
|
|
|
|
n.expression.type === "CallExpression" ||
|
|
|
|
n.expression.type === "FunctionExpression" ||
|
2017-02-05 05:37:18 +03:00
|
|
|
n.expression.type === "JSXEmptyExpression" ||
|
2017-04-11 19:33:02 +03:00
|
|
|
n.expression.type === "TemplateLiteral" ||
|
|
|
|
n.expression.type === "TaggedTemplateExpression" ||
|
2017-02-23 20:57:51 +03:00
|
|
|
(parent.type === "JSXElement" &&
|
2017-01-28 18:50:22 +03:00
|
|
|
(n.expression.type === "ConditionalExpression" ||
|
2017-03-09 18:59:53 +03:00
|
|
|
isBinaryish(n.expression)));
|
2017-01-26 22:51:08 +03:00
|
|
|
|
|
|
|
if (shouldInline) {
|
2017-02-23 20:57:51 +03:00
|
|
|
return group(
|
|
|
|
concat(["{", path.call(print, "expression"), lineSuffixBoundary, "}"])
|
|
|
|
);
|
2017-01-19 20:37:02 +03:00
|
|
|
}
|
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
return group(
|
2017-01-13 23:03:53 +03:00
|
|
|
concat([
|
|
|
|
"{",
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([softline, path.call(print, "expression")])),
|
2017-01-13 23:03:53 +03:00
|
|
|
softline,
|
2017-02-23 20:26:26 +03:00
|
|
|
lineSuffixBoundary,
|
2017-01-13 23:03:53 +03:00
|
|
|
"}"
|
|
|
|
])
|
|
|
|
);
|
2017-01-26 22:51:08 +03:00
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
case "JSXElement": {
|
|
|
|
const elem = printJSXElement(path, options, print);
|
|
|
|
return maybeWrapJSXElementInParens(path, elem, options);
|
|
|
|
}
|
2017-01-27 01:22:56 +03:00
|
|
|
case "JSXOpeningElement": {
|
|
|
|
const n = path.getValue();
|
|
|
|
|
|
|
|
// don't break up opening elements with a single long text attribute
|
2017-01-28 18:50:22 +03:00
|
|
|
if (
|
|
|
|
n.attributes.length === 1 &&
|
2017-02-16 06:56:11 +03:00
|
|
|
n.attributes[0].value &&
|
2017-04-13 17:09:40 +03:00
|
|
|
(n.attributes[0].value.type === "Literal" ||
|
|
|
|
n.attributes[0].value.type === "StringLiteral") &&
|
2017-02-16 06:56:11 +03:00
|
|
|
typeof n.attributes[0].value.value === "string"
|
2017-01-27 01:22:56 +03:00
|
|
|
) {
|
2017-01-28 18:50:22 +03:00
|
|
|
return group(
|
|
|
|
concat([
|
|
|
|
"<",
|
|
|
|
path.call(print, "name"),
|
|
|
|
" ",
|
|
|
|
concat(path.map(print, "attributes")),
|
|
|
|
n.selfClosing ? " />" : ">"
|
|
|
|
])
|
|
|
|
);
|
2017-01-27 01:22:56 +03:00
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return group(
|
2017-01-09 20:09:04 +03:00
|
|
|
concat([
|
2017-01-13 23:03:53 +03:00
|
|
|
"<",
|
|
|
|
path.call(print, "name"),
|
2017-01-24 21:54:01 +03:00
|
|
|
concat([
|
|
|
|
indent(
|
|
|
|
concat(
|
2017-01-28 18:50:22 +03:00
|
|
|
path.map(attr => concat([line, print(attr)]), "attributes")
|
2017-01-24 21:54:01 +03:00
|
|
|
)
|
|
|
|
),
|
2017-02-16 06:56:11 +03:00
|
|
|
n.selfClosing ? line : options.jsxBracketSameLine ? ">" : softline
|
2017-01-24 21:54:01 +03:00
|
|
|
]),
|
2017-02-16 06:56:11 +03:00
|
|
|
n.selfClosing ? "/>" : options.jsxBracketSameLine ? "" : ">"
|
2017-01-09 20:09:04 +03:00
|
|
|
])
|
|
|
|
);
|
2017-01-27 01:22:56 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "JSXClosingElement":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["</", path.call(print, "name"), ">"]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "JSXText":
|
|
|
|
throw new Error("JSXTest should be handled by JSXElement");
|
|
|
|
case "JSXEmptyExpression":
|
2017-04-14 04:32:13 +03:00
|
|
|
const requiresHardline = n.comments && n.comments.some(
|
2017-03-11 05:23:11 +03:00
|
|
|
comment => comment.type === "Line" || comment.type === "CommentLine"
|
2017-03-04 02:39:37 +03:00
|
|
|
);
|
2017-03-11 05:23:11 +03:00
|
|
|
|
|
|
|
return concat([
|
|
|
|
comments.printDanglingComments(
|
|
|
|
path,
|
|
|
|
options,
|
2017-03-16 23:26:44 +03:00
|
|
|
/* sameIndent */ !requiresHardline
|
2017-03-11 05:23:11 +03:00
|
|
|
),
|
|
|
|
requiresHardline ? hardline : ""
|
|
|
|
]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TypeAnnotatedIdentifier":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "annotation"),
|
|
|
|
" ",
|
|
|
|
path.call(print, "identifier")
|
|
|
|
]);
|
|
|
|
case "ClassBody":
|
2017-02-04 00:56:06 +03:00
|
|
|
if (!n.comments && n.body.length === 0) {
|
|
|
|
return "{}";
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-03 19:50:51 +03:00
|
|
|
return concat([
|
|
|
|
"{",
|
2017-02-09 18:44:56 +03:00
|
|
|
n.body.length > 0
|
|
|
|
? indent(
|
|
|
|
concat([
|
|
|
|
hardline,
|
2017-04-12 20:16:11 +03:00
|
|
|
path.call(function(bodyPath) {
|
|
|
|
return printStatementSequence(bodyPath, options, print);
|
|
|
|
}, "body")
|
2017-02-09 18:44:56 +03:00
|
|
|
])
|
2017-01-13 23:03:53 +03:00
|
|
|
)
|
2017-02-09 18:44:56 +03:00
|
|
|
: comments.printDanglingComments(path, options),
|
2017-02-03 19:50:51 +03:00
|
|
|
hardline,
|
|
|
|
"}"
|
|
|
|
]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ClassPropertyDefinition":
|
|
|
|
parts.push("static ", path.call(print, "definition"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (!namedTypes.MethodDefinition.check(n.definition)) {
|
|
|
|
parts.push(semi);
|
|
|
|
}
|
2017-01-09 20:07:39 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ClassProperty":
|
2017-05-01 03:41:19 +03:00
|
|
|
case "TSAbstractClassProperty":
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.static) {
|
|
|
|
parts.push("static ");
|
|
|
|
}
|
2017-05-01 03:41:19 +03:00
|
|
|
var variance = getFlowVariance(n, options);
|
2017-05-03 03:06:25 +03:00
|
|
|
if (variance) {
|
|
|
|
parts.push(variance);
|
|
|
|
}
|
|
|
|
if (n.accessibility) {
|
|
|
|
parts.push(n.accessibility + " ");
|
|
|
|
}
|
|
|
|
if (n.type === "TSAbstractClassProperty") {
|
|
|
|
parts.push("abstract ");
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.computed) {
|
2017-05-01 03:41:19 +03:00
|
|
|
parts.push("[", path.call(print, "key"), "]");
|
2017-01-11 22:37:53 +03:00
|
|
|
} else {
|
2017-05-01 03:41:19 +03:00
|
|
|
parts.push(printPropertyKey(path, options, print));
|
2017-01-11 22:37:53 +03:00
|
|
|
}
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.typeAnnotation) {
|
|
|
|
parts.push(": ", path.call(print, "typeAnnotation"));
|
|
|
|
}
|
|
|
|
if (n.value) {
|
|
|
|
parts.push(" = ", path.call(print, "value"));
|
|
|
|
}
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "ClassDeclaration":
|
|
|
|
case "ClassExpression":
|
2017-04-26 19:25:58 +03:00
|
|
|
case "TSAbstractClassDeclaration":
|
2017-04-27 19:37:42 +03:00
|
|
|
if (isNodeStartingWithDeclare(n, options)) {
|
|
|
|
parts.push("declare ");
|
|
|
|
}
|
|
|
|
parts.push(concat(printClass(path, options, print)));
|
|
|
|
return concat(parts);
|
2017-05-03 03:06:25 +03:00
|
|
|
case "TSHeritageClause":
|
|
|
|
return join(", ", path.map(print, "types"));
|
|
|
|
case "TSExpressionWithTypeArguments":
|
|
|
|
return path.call(print, "expression");
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TemplateElement":
|
2017-05-02 00:39:03 +03:00
|
|
|
return join(literalline, n.value.raw.split(/\r?\n/g));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TemplateLiteral":
|
|
|
|
var expressions = path.map(print, "expressions");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push("`");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(childPath) {
|
|
|
|
var i = childPath.getName();
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
parts.push(print(childPath));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
if (i < expressions.length) {
|
2017-05-02 00:28:11 +03:00
|
|
|
// For a template literal of the following form:
|
|
|
|
// `someQuery {
|
|
|
|
// ${call({
|
|
|
|
// a,
|
|
|
|
// b,
|
|
|
|
// })}
|
|
|
|
// }`
|
|
|
|
// the expression is on its own line (there is a \n in the previous
|
|
|
|
// quasi literal), therefore we want to indent the JavaScript
|
|
|
|
// expression inside at the beginning of ${ instead of the beginning
|
|
|
|
// of the `.
|
|
|
|
let size = 0;
|
|
|
|
const value = childPath.getValue().value.raw;
|
|
|
|
const index = value.lastIndexOf('\n');
|
|
|
|
const tabWidth = options.tabWidth;
|
|
|
|
if (index !== -1) {
|
|
|
|
for (let i = index + 1; i < value.length; ++i) {
|
|
|
|
if (value[i] === '\t') {
|
|
|
|
// Tabs behave in a way that they are aligned to the nearest
|
|
|
|
// multiple of tabWidth:
|
|
|
|
// 0 -> 4, 1 -> 4, 2 -> 4, 3 -> 4
|
|
|
|
// 4 -> 8, 5 -> 8, 6 -> 8, 7 -> 8 ...
|
|
|
|
size = size + tabWidth - size % tabWidth;
|
|
|
|
} else {
|
|
|
|
size++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let aligned = removeLines(expressions[i]);
|
|
|
|
if (size > 0) {
|
|
|
|
// Use indent to add tabs for all the levels of tabs we need
|
|
|
|
for (var i = 0; i < Math.floor(size / tabWidth); ++i) {
|
|
|
|
aligned = indent(aligned);
|
|
|
|
}
|
|
|
|
// Use align for all the spaces that are needed
|
|
|
|
aligned = align(size % tabWidth, aligned);
|
|
|
|
// size is absolute from 0 and not relative to the current
|
|
|
|
// indentation, so we use -Infinity to reset the indentation to 0
|
|
|
|
aligned = align(-Infinity, aligned);
|
|
|
|
}
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
parts.push(
|
|
|
|
"${",
|
2017-05-02 00:28:11 +03:00
|
|
|
aligned,
|
2017-04-12 20:16:11 +03:00
|
|
|
lineSuffixBoundary,
|
|
|
|
"}"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}, "quasis");
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push("`");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
// These types are unprintable because they serve as abstract
|
|
|
|
// supertypes for other (printable) types.
|
|
|
|
case "TaggedTemplateExpression":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat([path.call(print, "tag"), path.call(print, "quasi")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "Node":
|
|
|
|
case "Printable":
|
|
|
|
case "SourceLocation":
|
|
|
|
case "Position":
|
|
|
|
case "Statement":
|
|
|
|
case "Function":
|
|
|
|
case "Pattern":
|
|
|
|
case "Expression":
|
|
|
|
case "Declaration":
|
|
|
|
case "Specifier":
|
|
|
|
case "NamedSpecifier":
|
|
|
|
// Supertype of Block and Line.
|
|
|
|
case "Comment":
|
|
|
|
// Flow
|
2017-01-28 18:50:22 +03:00
|
|
|
case "MemberTypeAnnotation": // Flow
|
|
|
|
case "Type":
|
2017-01-13 23:03:53 +03:00
|
|
|
throw new Error("unprintable type: " + JSON.stringify(n.type));
|
|
|
|
// Type Annotations for Facebook Flow, typically stripped out or
|
|
|
|
// transformed away before printing.
|
|
|
|
case "TypeAnnotation":
|
|
|
|
if (n.typeAnnotation) {
|
2017-04-23 04:09:53 +03:00
|
|
|
return path.call(print, 'typeAnnotation')
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return "";
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSTupleType":
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TupleTypeAnnotation":
|
2017-04-12 20:16:11 +03:00
|
|
|
let typesField = n.type === "TSTupleType" ? "elementTypes" : "types";
|
2017-03-15 19:35:22 +03:00
|
|
|
return group(
|
|
|
|
concat([
|
|
|
|
"[",
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
softline,
|
2017-03-19 18:06:52 +03:00
|
|
|
printArrayItems(path, options, typesField, print)
|
2017-03-15 19:35:22 +03:00
|
|
|
])
|
|
|
|
),
|
|
|
|
ifBreak(shouldPrintComma(options) ? "," : ""),
|
2017-04-12 20:16:11 +03:00
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true),
|
2017-03-15 19:35:22 +03:00
|
|
|
softline,
|
|
|
|
"]"
|
|
|
|
])
|
|
|
|
);
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ExistsTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "*";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "EmptyTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "empty";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "AnyTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "any";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "MixedTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "mixed";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ArrayTypeAnnotation":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat([path.call(print, "elementType"), "[]"]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "BooleanTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "boolean";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "BooleanLiteralTypeAnnotation":
|
|
|
|
return "" + n.value;
|
|
|
|
case "DeclareClass":
|
2017-01-26 00:36:55 +03:00
|
|
|
return printFlowDeclaration(path, printClass(path, options, print));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "DeclareFunction":
|
2017-03-19 18:06:52 +03:00
|
|
|
// For TypeScript the DeclareFunction node shares the AST
|
|
|
|
// structure with FunctionDeclaration
|
|
|
|
if (n.params) {
|
|
|
|
return concat([
|
|
|
|
"declare ",
|
2017-04-12 20:16:11 +03:00
|
|
|
printFunctionDeclaration(path, print, options)
|
|
|
|
]);
|
2017-03-19 18:06:52 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
return printFlowDeclaration(path, [
|
|
|
|
"function ",
|
|
|
|
path.call(print, "id"),
|
|
|
|
n.predicate ? " " : "",
|
|
|
|
path.call(print, "predicate"),
|
2017-04-11 23:50:47 +03:00
|
|
|
semi
|
2017-01-13 23:03:53 +03:00
|
|
|
]);
|
|
|
|
case "DeclareModule":
|
|
|
|
return printFlowDeclaration(path, [
|
|
|
|
"module ",
|
|
|
|
path.call(print, "id"),
|
|
|
|
" ",
|
|
|
|
path.call(print, "body")
|
|
|
|
]);
|
|
|
|
case "DeclareModuleExports":
|
|
|
|
return printFlowDeclaration(path, [
|
|
|
|
"module.exports",
|
2017-04-23 04:09:53 +03:00
|
|
|
": ",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "typeAnnotation"),
|
2017-04-11 23:50:47 +03:00
|
|
|
semi
|
2017-01-13 23:03:53 +03:00
|
|
|
]);
|
|
|
|
case "DeclareVariable":
|
2017-04-11 23:50:47 +03:00
|
|
|
return printFlowDeclaration(path, ["var ", path.call(print, "id"), semi]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "DeclareExportAllDeclaration":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["declare export * from ", path.call(print, "source")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "DeclareExportDeclaration":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["declare ", printExportDeclaration(path, options, print)]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "FunctionTypeAnnotation":
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSFunctionType":
|
2017-01-13 23:03:53 +03:00
|
|
|
// FunctionTypeAnnotation is ambiguous:
|
|
|
|
// declare function foo(a: B): void; OR
|
|
|
|
// var A: (a: B) => void;
|
|
|
|
var parent = path.getParentNode(0);
|
2017-04-10 20:51:31 +03:00
|
|
|
var parentParent = path.getParentNode(1);
|
2017-04-12 20:16:11 +03:00
|
|
|
var isArrowFunctionTypeAnnotation =
|
|
|
|
n.type === "TSFunctionType" ||
|
|
|
|
!((!getFlowVariance(parent, options) &&
|
|
|
|
!parent.optional &&
|
|
|
|
namedTypes.ObjectTypeProperty.check(parent)) ||
|
|
|
|
namedTypes.ObjectTypeCallProperty.check(parent) ||
|
|
|
|
namedTypes.DeclareFunction.check(path.getParentNode(2)));
|
|
|
|
|
|
|
|
var needsColon =
|
|
|
|
isArrowFunctionTypeAnnotation &&
|
2017-01-13 23:03:53 +03:00
|
|
|
namedTypes.TypeAnnotation.check(parent);
|
|
|
|
|
2017-04-10 20:51:31 +03:00
|
|
|
// Sadly we can't put it inside of FastPath::needsColon because we are
|
|
|
|
// printing ":" as part of the expression and it would put parenthesis
|
|
|
|
// around :(
|
2017-04-12 20:16:11 +03:00
|
|
|
const needsParens =
|
|
|
|
needsColon &&
|
2017-04-10 20:51:31 +03:00
|
|
|
isArrowFunctionTypeAnnotation &&
|
|
|
|
parent.type === "TypeAnnotation" &&
|
|
|
|
parentParent.type === "ArrowFunctionExpression";
|
|
|
|
|
2017-02-05 05:23:37 +03:00
|
|
|
if (isObjectTypePropertyAFunction(parent)) {
|
|
|
|
isArrowFunctionTypeAnnotation = true;
|
|
|
|
needsColon = true;
|
|
|
|
}
|
|
|
|
|
2017-04-10 20:51:31 +03:00
|
|
|
if (needsParens) {
|
|
|
|
parts.push("(");
|
|
|
|
}
|
2017-04-24 03:33:00 +03:00
|
|
|
|
2017-05-06 05:44:26 +03:00
|
|
|
parts.push(
|
|
|
|
printFunctionTypeParameters(path, options, print),
|
|
|
|
printFunctionParams(path, print, options)
|
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
// The returnType is not wrapped in a TypeAnnotation, so the colon
|
|
|
|
// needs to be added separately.
|
2017-03-19 18:06:52 +03:00
|
|
|
if (n.returnType || n.predicate || n.typeAnnotation) {
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(
|
|
|
|
isArrowFunctionTypeAnnotation ? " => " : ": ",
|
|
|
|
path.call(print, "returnType"),
|
2017-03-19 18:06:52 +03:00
|
|
|
path.call(print, "predicate"),
|
|
|
|
path.call(print, "typeAnnotation")
|
2017-01-13 23:03:53 +03:00
|
|
|
);
|
|
|
|
}
|
2017-04-10 20:51:31 +03:00
|
|
|
if (needsParens) {
|
|
|
|
parts.push(")");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-20 19:35:30 +03:00
|
|
|
return group(concat(parts));
|
2017-01-13 23:03:53 +03:00
|
|
|
case "FunctionTypeParam":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "name"),
|
|
|
|
n.optional ? "?" : "",
|
|
|
|
n.name ? ": " : "",
|
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
]);
|
|
|
|
case "GenericTypeAnnotation":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "id"),
|
|
|
|
path.call(print, "typeParameters")
|
|
|
|
]);
|
|
|
|
case "DeclareInterface":
|
2017-01-14 07:15:30 +03:00
|
|
|
case "InterfaceDeclaration": {
|
2017-02-13 20:17:20 +03:00
|
|
|
if (
|
|
|
|
n.type === "DeclareInterface" ||
|
2017-04-27 19:37:42 +03:00
|
|
|
isNodeStartingWithDeclare(n, options)
|
2017-02-13 20:17:20 +03:00
|
|
|
) {
|
2017-01-14 07:15:30 +03:00
|
|
|
parts.push("declare ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
parts.push(
|
2017-01-20 00:20:03 +03:00
|
|
|
"interface ",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "id"),
|
2017-04-05 00:25:17 +03:00
|
|
|
path.call(print, "typeParameters")
|
2016-12-23 21:38:10 +03:00
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n["extends"].length > 0) {
|
2017-04-05 00:25:17 +03:00
|
|
|
parts.push(
|
|
|
|
group(
|
|
|
|
indent(
|
2017-04-12 20:16:11 +03:00
|
|
|
concat([line, "extends ", join(", ", path.map(print, "extends"))])
|
2017-04-05 00:25:17 +03:00
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-05 00:25:17 +03:00
|
|
|
parts.push(" ");
|
2017-01-14 07:15:30 +03:00
|
|
|
parts.push(path.call(print, "body"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-05 00:25:17 +03:00
|
|
|
return group(concat(parts));
|
2017-01-14 07:15:30 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ClassImplements":
|
|
|
|
case "InterfaceExtends":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "id"),
|
|
|
|
path.call(print, "typeParameters")
|
|
|
|
]);
|
2017-04-23 20:27:40 +03:00
|
|
|
case "TSIntersectionType":
|
2017-03-22 20:01:34 +03:00
|
|
|
case "IntersectionTypeAnnotation": {
|
|
|
|
const types = path.map(print, "types");
|
|
|
|
const result = [];
|
|
|
|
for (let i = 0; i < types.length; ++i) {
|
|
|
|
if (i === 0) {
|
|
|
|
result.push(types[i]);
|
|
|
|
} else if (
|
2017-04-10 20:50:38 +03:00
|
|
|
n.types[i - 1].type !== "ObjectTypeAnnotation" &&
|
|
|
|
n.types[i].type !== "ObjectTypeAnnotation"
|
2017-03-22 20:01:34 +03:00
|
|
|
) {
|
2017-04-10 20:50:38 +03:00
|
|
|
// If no object is involved, go to the next line if it breaks
|
2017-04-07 05:49:37 +03:00
|
|
|
result.push(indent(concat([" &", line, types[i]])));
|
2017-04-10 20:50:38 +03:00
|
|
|
} else {
|
|
|
|
// If you go from object to non-object or vis-versa, then inline it
|
|
|
|
result.push(" & ", i > 1 ? indent(types[i]) : types[i]);
|
2017-03-22 20:01:34 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return group(concat(result));
|
|
|
|
}
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSUnionType":
|
2017-01-13 23:03:53 +03:00
|
|
|
case "UnionTypeAnnotation": {
|
2017-01-27 05:41:50 +03:00
|
|
|
// single-line variation
|
|
|
|
// A | B | C
|
|
|
|
|
|
|
|
// multi-line variation
|
|
|
|
// | A
|
|
|
|
// | B
|
|
|
|
// | C
|
2017-02-20 18:18:39 +03:00
|
|
|
|
2017-03-04 00:54:45 +03:00
|
|
|
const parent = path.getParentNode();
|
|
|
|
// If there's a leading comment, the parent is doing the indentation
|
2017-05-05 05:06:30 +03:00
|
|
|
const shouldIndent = (
|
|
|
|
parent.type !== "TypeParameterInstantiation" &&
|
|
|
|
!(parent.type === "TypeAlias" &&
|
|
|
|
hasLeadingOwnLineComment(options.originalText, n))
|
|
|
|
);
|
2017-03-04 00:54:45 +03:00
|
|
|
|
2017-04-07 05:49:37 +03:00
|
|
|
//const token = isIntersection ? "&" : "|";
|
|
|
|
const code = concat([
|
|
|
|
ifBreak(concat([shouldIndent ? line : "", "| "])),
|
|
|
|
join(concat([line, "| "]), path.map(print, "types"))
|
|
|
|
]);
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
return group(shouldIndent ? indent(code) : code);
|
2016-12-31 07:03:22 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "NullableTypeAnnotation":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["?", path.call(print, "typeAnnotation")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "NullLiteralTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "null";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ThisTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "this";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "NumberTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "number";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "ObjectTypeCallProperty":
|
|
|
|
if (n.static) {
|
|
|
|
parts.push("static ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(path.call(print, "value"));
|
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "ObjectTypeIndexer":
|
2017-03-22 19:37:26 +03:00
|
|
|
var variance = getFlowVariance(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
2017-03-22 19:37:26 +03:00
|
|
|
variance || "",
|
2017-01-13 23:03:53 +03:00
|
|
|
"[",
|
|
|
|
path.call(print, "id"),
|
|
|
|
n.id ? ": " : "",
|
|
|
|
path.call(print, "key"),
|
|
|
|
"]: ",
|
|
|
|
path.call(print, "value")
|
|
|
|
]);
|
|
|
|
case "ObjectTypeProperty":
|
2017-03-22 19:37:26 +03:00
|
|
|
var variance = getFlowVariance(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
// TODO: This is a bad hack and we need a better way to know
|
|
|
|
// when to emit an arrow function or not.
|
2017-04-23 04:09:53 +03:00
|
|
|
var isFunctionNotation = util.locStart(n) === util.locStart(n.value)
|
|
|
|
var isGetterOrSetter = n.kind === "get" || n.kind === "set"
|
2017-02-05 05:23:37 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat([
|
|
|
|
n.static ? "static " : "",
|
2017-03-22 19:37:26 +03:00
|
|
|
variance || "",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "key"),
|
|
|
|
n.optional ? "?" : "",
|
2017-04-23 04:09:53 +03:00
|
|
|
(isFunctionNotation && !isGetterOrSetter) ? "" : ": ",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "value")
|
|
|
|
]);
|
|
|
|
case "QualifiedTypeIdentifier":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "qualification"),
|
|
|
|
".",
|
|
|
|
path.call(print, "id")
|
|
|
|
]);
|
|
|
|
case "StringLiteralTypeAnnotation":
|
2017-01-20 00:20:03 +03:00
|
|
|
return nodeStr(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "NumberLiteralTypeAnnotation":
|
|
|
|
assert.strictEqual(typeof n.value, "number");
|
|
|
|
|
2017-04-05 23:22:23 +03:00
|
|
|
if (n.extra != null) {
|
|
|
|
return printNumber(n.extra.raw);
|
|
|
|
} else {
|
|
|
|
return printNumber(n.raw);
|
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "StringTypeAnnotation":
|
2017-01-20 21:12:37 +03:00
|
|
|
return "string";
|
2017-01-13 23:03:53 +03:00
|
|
|
case "DeclareTypeAlias":
|
|
|
|
case "TypeAlias": {
|
2017-02-13 20:17:20 +03:00
|
|
|
if (
|
|
|
|
n.type === "DeclareTypeAlias" ||
|
2017-04-27 19:37:42 +03:00
|
|
|
isNodeStartingWithDeclare(n, options)
|
2017-02-13 20:17:20 +03:00
|
|
|
) {
|
2016-12-30 08:01:44 +03:00
|
|
|
parts.push("declare ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-27 21:21:42 +03:00
|
|
|
const canBreak = (
|
|
|
|
n.right.type === "StringLiteralTypeAnnotation"
|
|
|
|
);
|
|
|
|
|
|
|
|
const printed = printAssignmentRight(
|
|
|
|
n.right,
|
|
|
|
path.call(print, "right"),
|
|
|
|
canBreak,
|
|
|
|
options
|
|
|
|
);
|
|
|
|
|
2016-12-30 08:01:44 +03:00
|
|
|
parts.push(
|
2016-12-23 21:38:10 +03:00
|
|
|
"type ",
|
|
|
|
path.call(print, "id"),
|
|
|
|
path.call(print, "typeParameters"),
|
2017-03-04 00:54:45 +03:00
|
|
|
" =",
|
2017-04-27 21:21:42 +03:00
|
|
|
printed,
|
2017-04-11 23:50:47 +03:00
|
|
|
semi
|
2016-12-30 08:01:44 +03:00
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-27 21:21:42 +03:00
|
|
|
return group(concat(parts));
|
2016-12-30 08:01:44 +03:00
|
|
|
}
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TypeCastExpression":
|
|
|
|
return concat([
|
|
|
|
"(",
|
|
|
|
path.call(print, "expression"),
|
2017-04-23 04:09:53 +03:00
|
|
|
": ",
|
2017-01-13 23:03:53 +03:00
|
|
|
path.call(print, "typeAnnotation"),
|
|
|
|
")"
|
|
|
|
]);
|
|
|
|
case "TypeParameterDeclaration":
|
2017-05-03 18:01:45 +03:00
|
|
|
case "TypeParameterInstantiation":
|
|
|
|
return printTypeParameters(path, options, print, "params");
|
2017-01-13 23:03:53 +03:00
|
|
|
case "TypeParameter":
|
2017-03-22 19:37:26 +03:00
|
|
|
var variance = getFlowVariance(n, options);
|
2017-01-13 23:03:53 +03:00
|
|
|
|
2017-03-22 19:37:26 +03:00
|
|
|
if (variance) {
|
|
|
|
parts.push(variance);
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(path.call(print, "name"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n.bound) {
|
2017-04-23 04:09:53 +03:00
|
|
|
parts.push(": ");
|
2017-01-13 23:03:53 +03:00
|
|
|
parts.push(path.call(print, "bound"));
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
if (n.constraint) {
|
|
|
|
parts.push(" extends ", path.call(print, "constraint"));
|
|
|
|
}
|
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (n["default"]) {
|
2017-05-02 00:39:15 +03:00
|
|
|
parts.push(" = ", path.call(print, "default"));
|
2017-01-13 23:03:53 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "TypeofTypeAnnotation":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["typeof ", path.call(print, "argument")]);
|
2017-01-13 23:03:53 +03:00
|
|
|
case "VoidTypeAnnotation":
|
|
|
|
return "void";
|
|
|
|
case "NullTypeAnnotation":
|
|
|
|
return "null";
|
|
|
|
case "InferredPredicate":
|
|
|
|
return "%checks";
|
|
|
|
// 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 "DeclaredPredicate":
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat(["%checks(", path.call(print, "value"), ")"]);
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSAnyKeyword":
|
|
|
|
return "any";
|
2017-05-03 03:06:25 +03:00
|
|
|
case "TSAsyncKeyword":
|
|
|
|
return "async";
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSBooleanKeyword":
|
|
|
|
return "boolean";
|
2017-05-03 03:06:25 +03:00
|
|
|
case "TSExportKeyword":
|
|
|
|
return "export";
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSNumberKeyword":
|
|
|
|
return "number";
|
|
|
|
case "TSObjectKeyword":
|
|
|
|
return "object";
|
2017-05-03 03:06:25 +03:00
|
|
|
case "TSProtectedKeyword":
|
|
|
|
return "protected";
|
|
|
|
case "TSPrivateKeyword":
|
|
|
|
return "private";
|
|
|
|
case "TSPublicKeyword":
|
|
|
|
return "public";
|
|
|
|
case "TSStaticKeyword":
|
|
|
|
return "static";
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSStringKeyword":
|
|
|
|
return "string";
|
|
|
|
case "TSVoidKeyword":
|
|
|
|
return "void";
|
|
|
|
case "TSAsExpression":
|
|
|
|
return concat([
|
2017-04-05 23:28:02 +03:00
|
|
|
path.call(print, "expression"),
|
|
|
|
" as ",
|
2017-04-12 20:16:11 +03:00
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
]);
|
2017-03-19 18:06:52 +03:00
|
|
|
case "TSArrayType":
|
|
|
|
return concat([path.call(print, "elementType"), "[]"]);
|
|
|
|
case "TSPropertySignature":
|
|
|
|
parts.push(path.call(print, "name"));
|
2017-05-04 00:35:58 +03:00
|
|
|
|
2017-05-03 02:03:51 +03:00
|
|
|
if (n.typeAnnotation) {
|
|
|
|
parts.push(": ");
|
|
|
|
parts.push(path.call(print, "typeAnnotation"));
|
|
|
|
}
|
2017-03-19 18:06:52 +03:00
|
|
|
|
2017-04-26 19:25:58 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "TSParameterProperty":
|
|
|
|
if (n.accessibility) {
|
|
|
|
parts.push(n.accessibility + " ");
|
|
|
|
}
|
|
|
|
if (n.isReadonly) {
|
|
|
|
parts.push("readonly ");
|
|
|
|
}
|
|
|
|
|
|
|
|
parts.push(path.call(print, "parameter"));
|
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
return concat(parts);
|
|
|
|
case "TSTypeReference":
|
|
|
|
return concat([
|
2017-05-03 18:01:45 +03:00
|
|
|
path.call(print, "typeName"),
|
|
|
|
printTypeParameters(path, options, print, "typeArguments")
|
2017-03-19 18:06:52 +03:00
|
|
|
]);
|
|
|
|
case "TSTypeQuery":
|
|
|
|
return concat(["typeof ", path.call(print, "exprName")]);
|
|
|
|
case "TSParenthesizedType":
|
|
|
|
return concat(["(", path.call(print, "typeAnnotation"), ")"]);
|
|
|
|
case "TSIndexSignature":
|
|
|
|
return concat([
|
2017-04-05 23:28:02 +03:00
|
|
|
"[",
|
2017-03-19 18:06:52 +03:00
|
|
|
// This should only contain a single element, however TypeScript parses
|
|
|
|
// it using parseDelimitedList that uses commas as delimiter.
|
2017-04-05 23:28:02 +03:00
|
|
|
join(", ", path.map(print, "parameters")),
|
2017-03-19 18:06:52 +03:00
|
|
|
"]: ",
|
2017-04-12 20:16:11 +03:00
|
|
|
path.call(print, "typeAnnotation")
|
2017-03-19 18:06:52 +03:00
|
|
|
]);
|
2017-04-19 19:03:55 +03:00
|
|
|
case "TSFirstTypeNode":
|
|
|
|
return concat([n.parameterName.name, " is ", path.call(print, "typeAnnotation")])
|
2017-04-20 01:41:18 +03:00
|
|
|
case "TSNeverKeyword":
|
|
|
|
return "never";
|
|
|
|
case "TSUndefinedKeyword":
|
|
|
|
return "undefined";
|
|
|
|
case "TSSymbolKeyword":
|
|
|
|
return "symbol";
|
|
|
|
case "TSNonNullExpression":
|
|
|
|
return concat([path.call(print, "expression"), "!"]);
|
|
|
|
case "TSThisType":
|
|
|
|
return "this";
|
2017-04-21 04:01:34 +03:00
|
|
|
case "TSLastTypeNode":
|
|
|
|
return path.call(print, "literal")
|
|
|
|
case "TSIndexedAccessType":
|
|
|
|
return concat([
|
|
|
|
path.call(print, "objectType"),
|
|
|
|
"[",
|
|
|
|
path.call(print, "indexType"),
|
|
|
|
"]"
|
|
|
|
])
|
2017-05-03 18:01:45 +03:00
|
|
|
case "TSConstructSignature":
|
2017-04-21 17:57:26 +03:00
|
|
|
case "TSConstructorType":
|
2017-05-03 18:01:45 +03:00
|
|
|
case "TSCallSignature":
|
|
|
|
if (n.type !== "TSCallSignature") {
|
|
|
|
parts.push("new ");
|
|
|
|
}
|
2017-05-04 21:20:52 +03:00
|
|
|
var isType = n.type === "TSConstructorType";
|
2017-05-03 18:01:45 +03:00
|
|
|
parts.push(
|
|
|
|
printTypeParameters(path, options, print, "typeParameters"),
|
|
|
|
"(",
|
2017-04-21 17:57:26 +03:00
|
|
|
join(", ", path.map(print, "parameters")),
|
2017-05-03 18:01:45 +03:00
|
|
|
")"
|
|
|
|
);
|
|
|
|
if (n.typeAnnotation) {
|
|
|
|
parts.push(
|
|
|
|
isType ? " => " : ": ",
|
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return concat(parts);
|
2017-04-23 18:25:25 +03:00
|
|
|
case "TSTypeOperator":
|
|
|
|
return concat([
|
|
|
|
"keyof ",
|
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
])
|
2017-04-23 20:16:25 +03:00
|
|
|
case "TSMappedType":
|
|
|
|
return concat([
|
|
|
|
"{",
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
"[",
|
|
|
|
path.call(print, "typeParameter"),
|
|
|
|
"]: ",
|
|
|
|
path.call(print, "typeAnnotation"),
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
"}"
|
|
|
|
])
|
|
|
|
case "TSTypeParameter":
|
2017-05-03 18:01:45 +03:00
|
|
|
parts.push(path.call(print, "name"));
|
2017-04-25 19:48:56 +03:00
|
|
|
|
2017-04-23 20:16:25 +03:00
|
|
|
if (n.constraint) {
|
|
|
|
parts.push(
|
|
|
|
" in ",
|
|
|
|
path.call(print, "constraint")
|
2017-05-03 18:01:45 +03:00
|
|
|
);
|
2017-04-23 20:16:25 +03:00
|
|
|
}
|
2017-04-25 19:48:56 +03:00
|
|
|
|
2017-04-23 20:16:25 +03:00
|
|
|
return concat(parts)
|
2017-04-26 00:15:33 +03:00
|
|
|
case "TSMethodSignature":
|
2017-05-01 19:25:49 +03:00
|
|
|
parts.push(
|
2017-04-26 00:15:33 +03:00
|
|
|
path.call(print, 'name'),
|
2017-05-06 07:11:13 +03:00
|
|
|
printTypeParameters(path, options, print, "typeParameters"),
|
|
|
|
printFunctionParams(path, print, options)
|
2017-05-01 19:25:49 +03:00
|
|
|
)
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
if (n.typeAnnotation) {
|
|
|
|
parts.push(
|
|
|
|
": ",
|
|
|
|
path.call(print, "typeAnnotation")
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return concat(parts)
|
|
|
|
case "TSNamespaceExportDeclaration":
|
|
|
|
if (n.declaration) {
|
|
|
|
parts.push(
|
|
|
|
"export ",
|
|
|
|
path.call(print, "declaration")
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
parts.push(
|
2017-05-02 00:42:52 +03:00
|
|
|
"export as namespace ",
|
2017-05-01 19:25:49 +03:00
|
|
|
path.call(print, "name")
|
|
|
|
)
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
if (options.semi) {
|
|
|
|
parts.push(";")
|
|
|
|
}
|
|
|
|
}
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
return group(concat([softline, concat(parts)]));
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSEnumDeclaration":
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.modifiers) {
|
|
|
|
parts.push(printTypeScriptModifiers(path, options, print));
|
|
|
|
}
|
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
parts.push(
|
|
|
|
"enum ",
|
|
|
|
path.call(print, "name"),
|
|
|
|
" "
|
|
|
|
)
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
if (n.members.length === 0) {
|
|
|
|
parts.push(
|
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
"{",
|
|
|
|
comments.printDanglingComments(path, options),
|
|
|
|
softline,
|
|
|
|
"}"
|
|
|
|
])
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
parts.push(
|
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
"{",
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
softline,
|
|
|
|
printArrayItems(path, options, "members", print)
|
|
|
|
])
|
|
|
|
),
|
|
|
|
comments.printDanglingComments(
|
|
|
|
path,
|
|
|
|
options,
|
|
|
|
/* sameIndent */ true
|
|
|
|
),
|
|
|
|
softline,
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
"}"
|
|
|
|
])
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
case "TSEnumMember":
|
2017-05-06 05:44:26 +03:00
|
|
|
parts.push(path.call(print, "name"));
|
|
|
|
if (n.initializer) {
|
|
|
|
parts.push(" = ", path.call(print, "initializer"));
|
|
|
|
}
|
|
|
|
return concat(parts);
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSImportEqualsDeclaration":
|
|
|
|
parts.push(
|
2017-05-03 03:06:25 +03:00
|
|
|
softline,
|
|
|
|
printTypeScriptModifiers(path, options, print),
|
2017-05-01 19:25:49 +03:00
|
|
|
"import ",
|
|
|
|
path.call(print, "name"),
|
|
|
|
" = ",
|
|
|
|
path.call(print, "moduleReference")
|
|
|
|
)
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-01 19:25:49 +03:00
|
|
|
if (options.semi) {
|
|
|
|
parts.push(";")
|
|
|
|
}
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
return group(concat(parts));
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSExternalModuleReference":
|
|
|
|
return concat([
|
|
|
|
"require(",
|
|
|
|
path.call(print, "expression"),
|
|
|
|
")"
|
2017-04-26 00:15:33 +03:00
|
|
|
])
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSModuleDeclaration":
|
2017-05-06 07:14:07 +03:00
|
|
|
var isExternalModule = namedTypes.Literal.check(n.name);
|
|
|
|
var parentIsDeclaration = path.getParentNode().type === "TSModuleDeclaration";
|
|
|
|
var bodyIsDeclaration = n.body.type === "TSModuleDeclaration";
|
|
|
|
if (parentIsDeclaration) {
|
|
|
|
parts.push(".");
|
|
|
|
} else {
|
|
|
|
parts.push(
|
|
|
|
printTypeScriptModifiers(path, options, print),
|
|
|
|
isExternalModule? "module " : "namespace "
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
parts.push(path.call(print, "name"));
|
|
|
|
|
|
|
|
if (bodyIsDeclaration) {
|
|
|
|
parts.push(path.call(print, "body"));
|
|
|
|
} else {
|
|
|
|
parts.push(
|
|
|
|
" {",
|
|
|
|
indent(concat([line, group(path.call(print, "body"))])),
|
|
|
|
line,
|
|
|
|
"}"
|
|
|
|
)
|
|
|
|
};
|
2017-05-02 00:42:52 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
return concat(parts);
|
2017-05-01 19:25:49 +03:00
|
|
|
case "TSDeclareKeyword":
|
|
|
|
return "declare"
|
|
|
|
case "TSModuleBlock":
|
2017-05-06 05:44:26 +03:00
|
|
|
return path.call(function(bodyPath) {
|
|
|
|
return printStatementSequence(bodyPath, options, print);
|
|
|
|
}, "body");
|
2017-05-04 19:37:00 +03:00
|
|
|
case "TSConstKeyword":
|
|
|
|
return "const";
|
2017-05-04 19:48:24 +03:00
|
|
|
case "TSAbstractKeyword":
|
|
|
|
return "abstract";
|
2017-01-13 23:03:53 +03:00
|
|
|
// TODO
|
|
|
|
case "ClassHeritage":
|
|
|
|
// TODO
|
|
|
|
case "ComprehensionBlock":
|
|
|
|
// TODO
|
|
|
|
case "ComprehensionExpression":
|
|
|
|
// TODO
|
|
|
|
case "Glob":
|
|
|
|
// TODO
|
|
|
|
case "GeneratorExpression":
|
|
|
|
// TODO
|
|
|
|
case "LetStatement":
|
|
|
|
// TODO
|
|
|
|
case "LetExpression":
|
|
|
|
// TODO
|
|
|
|
case "GraphExpression":
|
|
|
|
// TODO
|
|
|
|
// XML types that nobody cares about or needs to print.
|
|
|
|
case "GraphIndexExpression":
|
|
|
|
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:
|
|
|
|
throw new Error("unknown type: " + JSON.stringify(n.type));
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function printStatementSequence(path, options, print) {
|
2016-12-31 07:10:22 +03:00
|
|
|
let printed = [];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
const bodyNode = path.getNode();
|
|
|
|
const isClass = bodyNode.type === "ClassBody";
|
|
|
|
|
|
|
|
path.map((stmtPath, i) => {
|
2017-01-05 06:27:25 +03:00
|
|
|
var stmt = stmtPath.getValue();
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-01-05 06:27:25 +03:00
|
|
|
// Just in case the AST has been modified to contain falsy
|
|
|
|
// "statements," it's safer simply to skip them.
|
|
|
|
if (!stmt) {
|
|
|
|
return;
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-05 06:27:25 +03:00
|
|
|
// Skip printing EmptyStatement nodes to avoid leaving stray
|
|
|
|
// semicolons lying around.
|
|
|
|
if (stmt.type === "EmptyStatement") {
|
|
|
|
return;
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-05 06:27:25 +03:00
|
|
|
const stmtPrinted = print(stmtPath);
|
2017-01-10 05:49:06 +03:00
|
|
|
const text = options.originalText;
|
2017-01-05 06:27:25 +03:00
|
|
|
const parts = [];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
// in no-semi mode, prepend statement with semicolon if it might break ASI
|
|
|
|
if (!options.semi && !isClass && stmtNeedsASIProtection(stmtPath)) {
|
2017-04-14 04:33:46 +03:00
|
|
|
if (
|
|
|
|
stmt.comments &&
|
|
|
|
stmt.comments.some(comment => comment.leading)
|
|
|
|
) {
|
|
|
|
// Note: stmtNeedsASIProtection requires stmtPath to already be printed
|
|
|
|
// as it reads needsParens which is mutated on the instance
|
|
|
|
parts.push(print(stmtPath, { needsSemi: true }));
|
|
|
|
} else {
|
|
|
|
parts.push(";", stmtPrinted);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
parts.push(stmtPrinted);
|
2017-04-11 23:50:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.semi && isClass) {
|
|
|
|
if (classPropMayCauseASIProblems(stmtPath)) {
|
|
|
|
parts.push(";");
|
|
|
|
} else if (stmt.type === "ClassProperty") {
|
|
|
|
const nextChild = bodyNode.body[i + 1];
|
|
|
|
if (classChildNeedsASIProtection(nextChild)) {
|
|
|
|
parts.push(";");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-30 20:10:54 +03:00
|
|
|
if (util.isNextLineEmpty(text, stmt) && !isLastStatement(stmtPath)) {
|
2017-01-05 06:27:25 +03:00
|
|
|
parts.push(hardline);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-05 06:27:25 +03:00
|
|
|
printed.push(concat(parts));
|
|
|
|
});
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-31 07:01:07 +03:00
|
|
|
return join(hardline, printed);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2017-01-19 20:37:24 +03:00
|
|
|
function printPropertyKey(path, options, print) {
|
2017-01-23 05:41:31 +03:00
|
|
|
const node = path.getNode();
|
|
|
|
const key = node.key;
|
|
|
|
|
2017-01-15 07:40:26 +03:00
|
|
|
if (
|
2017-01-23 05:41:31 +03:00
|
|
|
(key.type === "StringLiteral" ||
|
2017-02-23 20:57:51 +03:00
|
|
|
(key.type === "Literal" && typeof key.value === "string")) &&
|
2017-02-16 06:56:11 +03:00
|
|
|
isIdentifierName(key.value) &&
|
2017-04-28 00:59:18 +03:00
|
|
|
!node.computed
|
2017-01-15 07:40:26 +03:00
|
|
|
) {
|
2017-01-11 20:31:34 +03:00
|
|
|
// 'a' -> a
|
2017-04-05 23:10:10 +03:00
|
|
|
return path.call(
|
2017-04-25 19:48:56 +03:00
|
|
|
keyPath => comments.printComments(keyPath, () => key.value, options),
|
2017-04-05 23:10:10 +03:00
|
|
|
"key"
|
|
|
|
);
|
2017-01-11 08:48:49 +03:00
|
|
|
}
|
|
|
|
return path.call(print, "key");
|
|
|
|
}
|
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
function printMethod(path, options, print) {
|
|
|
|
var node = path.getNode();
|
2017-04-26 19:25:58 +03:00
|
|
|
var semi = options.semi ? ";" : "";
|
2016-12-23 21:38:10 +03:00
|
|
|
var kind = node.kind;
|
|
|
|
var parts = [];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (node.type === "ObjectMethod" || node.type === "ClassMethod") {
|
|
|
|
node.value = node;
|
|
|
|
} else {
|
|
|
|
namedTypes.FunctionExpression.assert(node.value);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (node.value.async) {
|
|
|
|
parts.push("async ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (!kind || kind === "init" || kind === "method" || kind === "constructor") {
|
|
|
|
if (node.value.generator) {
|
|
|
|
parts.push("*");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert.ok(kind === "get" || kind === "set");
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
parts.push(kind, " ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-19 20:37:24 +03:00
|
|
|
var key = printPropertyKey(path, options, print);
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (node.computed) {
|
2017-01-28 18:50:22 +03:00
|
|
|
key = concat(["[", key, "]"]);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-03 19:50:51 +03:00
|
|
|
parts.push(
|
|
|
|
key,
|
2017-05-06 05:44:26 +03:00
|
|
|
concat(path.call(valuePath => [
|
|
|
|
printFunctionTypeParameters(valuePath, options, print),
|
|
|
|
group(concat([
|
|
|
|
printFunctionParams(valuePath, print, options),
|
|
|
|
printReturnType(valuePath, print)
|
|
|
|
]))
|
|
|
|
], "value"))
|
2017-02-03 19:50:51 +03:00
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-26 19:25:58 +03:00
|
|
|
if (!node.value.body || node.value.body.length === 0) {
|
|
|
|
parts.push(semi);
|
|
|
|
} else {
|
|
|
|
parts.push(" ", path.call(print, "value", "body"));
|
|
|
|
}
|
|
|
|
|
2017-01-09 21:47:02 +03:00
|
|
|
return concat(parts);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2017-03-18 21:20:07 +03:00
|
|
|
function couldGroupArg(arg) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
(arg.type === "ObjectExpression" && arg.properties.length > 0) ||
|
|
|
|
(arg.type === "ArrayExpression" && arg.elements.length > 0) ||
|
|
|
|
arg.type === "FunctionExpression" ||
|
|
|
|
(arg.type === "ArrowFunctionExpression" &&
|
|
|
|
(arg.body.type === "BlockStatement" ||
|
|
|
|
arg.body.type === "ArrowFunctionExpression" ||
|
|
|
|
arg.body.type === "ObjectExpression" ||
|
|
|
|
arg.body.type === "ArrayExpression" ||
|
|
|
|
arg.body.type === "CallExpression" ||
|
|
|
|
arg.body.type === "JSXElement"))
|
|
|
|
);
|
2017-03-18 21:20:07 +03:00
|
|
|
}
|
|
|
|
|
2017-03-03 06:29:53 +03:00
|
|
|
function shouldGroupLastArg(args) {
|
2017-02-25 20:56:13 +03:00
|
|
|
const lastArg = util.getLast(args);
|
2017-03-04 02:39:37 +03:00
|
|
|
const penultimateArg = util.getPenultimate(args);
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
(!lastArg.comments || !lastArg.comments.length) &&
|
2017-03-18 21:20:07 +03:00
|
|
|
couldGroupArg(lastArg) &&
|
2017-03-01 20:37:02 +03:00
|
|
|
// If the last two arguments are of the same type,
|
|
|
|
// disable last element expansion.
|
2017-04-12 20:16:11 +03:00
|
|
|
(!penultimateArg || penultimateArg.type !== lastArg.type)
|
|
|
|
);
|
2017-03-03 06:29:53 +03:00
|
|
|
}
|
2017-01-04 23:24:10 +03:00
|
|
|
|
2017-03-18 21:20:07 +03:00
|
|
|
function shouldGroupFirstArg(args) {
|
|
|
|
if (args.length !== 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const firstArg = args[0];
|
|
|
|
const secondArg = args[1];
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
(!firstArg.comments || !firstArg.comments.length) &&
|
|
|
|
(firstArg.type === "FunctionExpression" ||
|
|
|
|
(firstArg.type === "ArrowFunctionExpression" &&
|
|
|
|
firstArg.body.type === "BlockStatement")) &&
|
|
|
|
!couldGroupArg(secondArg)
|
|
|
|
);
|
2017-03-18 21:20:07 +03:00
|
|
|
}
|
|
|
|
|
2017-03-03 06:29:53 +03:00
|
|
|
function printArgumentsList(path, options, print) {
|
|
|
|
var printed = path.map(print, "arguments");
|
2017-05-06 05:44:26 +03:00
|
|
|
var n = path.getValue();
|
2017-03-03 06:29:53 +03:00
|
|
|
if (printed.length === 0) {
|
2017-03-09 18:55:18 +03:00
|
|
|
return concat([
|
|
|
|
"(",
|
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true),
|
|
|
|
")"
|
|
|
|
]);
|
2017-03-03 06:29:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const args = path.getValue().arguments;
|
|
|
|
// This is just an optimization; I think we could return the
|
|
|
|
// conditional group for all function calls, but it's more expensive
|
|
|
|
// so only do it for specific forms.
|
2017-03-18 21:20:07 +03:00
|
|
|
const shouldGroupFirst = shouldGroupFirstArg(args);
|
2017-04-13 06:24:50 +03:00
|
|
|
const shouldGroupLast = shouldGroupLastArg(args);
|
|
|
|
if (shouldGroupFirst || shouldGroupLast) {
|
2017-03-18 21:20:07 +03:00
|
|
|
const shouldBreak = shouldGroupFirst
|
|
|
|
? printed.slice(1).some(willBreak)
|
|
|
|
: printed.slice(0, -1).some(willBreak);
|
2017-04-11 18:50:49 +03:00
|
|
|
|
2017-04-13 06:24:50 +03:00
|
|
|
// We want to print the last argument with a special flag
|
|
|
|
let printedExpanded;
|
|
|
|
let i = 0;
|
|
|
|
path.each(function(argPath) {
|
|
|
|
if (shouldGroupFirst && i === 0) {
|
|
|
|
printedExpanded =
|
|
|
|
[argPath.call(p => print(p, { expandFirstArg: true }))]
|
|
|
|
.concat(printed.slice(1));
|
|
|
|
}
|
|
|
|
if (shouldGroupLast && i === args.length - 1) {
|
|
|
|
printedExpanded = printed
|
|
|
|
.slice(0, -1)
|
|
|
|
.concat(argPath.call(p => print(p, { expandLastArg: true })));
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}, "arguments");
|
2017-04-11 18:50:49 +03:00
|
|
|
|
2017-02-04 00:15:21 +03:00
|
|
|
return concat([
|
|
|
|
printed.some(willBreak) ? breakParent : "",
|
|
|
|
conditionalGroup(
|
|
|
|
[
|
2017-04-13 06:24:50 +03:00
|
|
|
concat(["(", join(concat([", "]), printedExpanded), ")"]),
|
2017-03-18 21:20:07 +03:00
|
|
|
shouldGroupFirst
|
|
|
|
? concat([
|
|
|
|
"(",
|
2017-04-13 06:24:50 +03:00
|
|
|
group(printedExpanded[0], { shouldBreak: true }),
|
2017-03-18 21:20:07 +03:00
|
|
|
printed.length > 1 ? ", " : "",
|
|
|
|
join(concat([",", line]), printed.slice(1)),
|
|
|
|
")"
|
|
|
|
])
|
|
|
|
: concat([
|
|
|
|
"(",
|
|
|
|
join(concat([",", line]), printed.slice(0, -1)),
|
|
|
|
printed.length > 1 ? ", " : "",
|
2017-04-13 06:24:50 +03:00
|
|
|
group(util.getLast(printedExpanded), {
|
2017-04-12 20:16:11 +03:00
|
|
|
shouldBreak: true
|
|
|
|
}),
|
2017-03-18 21:20:07 +03:00
|
|
|
")"
|
|
|
|
]),
|
2017-02-04 00:15:21 +03:00
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
"(",
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([line, join(concat([",", line]), printed)])),
|
2017-02-18 06:44:55 +03:00
|
|
|
shouldPrintComma(options, "all") ? "," : "",
|
2017-02-04 00:15:21 +03:00
|
|
|
line,
|
|
|
|
")"
|
|
|
|
]),
|
|
|
|
{ shouldBreak: true }
|
|
|
|
)
|
|
|
|
],
|
|
|
|
{ shouldBreak }
|
|
|
|
)
|
|
|
|
]);
|
2017-01-04 23:24:10 +03:00
|
|
|
}
|
|
|
|
|
2017-01-24 21:54:01 +03:00
|
|
|
return group(
|
2017-01-04 23:24:10 +03:00
|
|
|
concat([
|
|
|
|
"(",
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([softline, join(concat([",", line]), printed)])),
|
2017-02-18 06:44:55 +03:00
|
|
|
ifBreak(shouldPrintComma(options, "all") ? "," : ""),
|
2017-01-04 23:24:10 +03:00
|
|
|
softline,
|
|
|
|
")"
|
2017-01-31 19:45:47 +03:00
|
|
|
]),
|
|
|
|
{ shouldBreak: printed.some(willBreak) }
|
2017-01-04 23:24:10 +03:00
|
|
|
);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2017-05-06 05:44:26 +03:00
|
|
|
function printFunctionTypeParameters(path, options, print) {
|
|
|
|
const fun = path.getValue();
|
|
|
|
// With TypeScript `typeParameters` is an array of `TSTypeParameter` and
|
|
|
|
// with flow they are one `TypeParameterDeclaration` node.
|
|
|
|
if (fun.type === "TSFunctionType") {
|
|
|
|
return printTypeParameters(path, options, print, "typeParameters")
|
|
|
|
} else if (fun.typeParameters) {
|
|
|
|
return path.call(print, "typeParameters");
|
|
|
|
} else {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 06:24:50 +03:00
|
|
|
function printFunctionParams(path, print, options, expandArg) {
|
2016-12-23 21:38:10 +03:00
|
|
|
var fun = path.getValue();
|
2016-12-30 08:01:44 +03:00
|
|
|
// namedTypes.Function.assert(fun);
|
2017-05-06 07:11:13 +03:00
|
|
|
var paramsField = (fun.type === "TSFunctionType" ||
|
|
|
|
fun.type === "TSMethodSignature")
|
|
|
|
? "parameters"
|
|
|
|
: "params";
|
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
var printed = path.map(print, paramsField);
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (fun.defaults) {
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(defExprPath) {
|
|
|
|
var i = defExprPath.getName();
|
|
|
|
var p = printed[i];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
if (p && defExprPath.getValue()) {
|
|
|
|
printed[i] = concat([p, " = ", print(defExprPath)]);
|
|
|
|
}
|
|
|
|
}, "defaults");
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (fun.rest) {
|
2017-01-28 18:50:22 +03:00
|
|
|
printed.push(concat(["...", path.call(print, "rest")]));
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-15 07:55:38 +03:00
|
|
|
if (printed.length === 0) {
|
2017-02-24 18:26:30 +03:00
|
|
|
return concat([
|
|
|
|
"(",
|
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true),
|
|
|
|
")"
|
2017-03-01 20:37:02 +03:00
|
|
|
]);
|
2017-01-15 07:55:38 +03:00
|
|
|
}
|
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
const lastParam = util.getLast(fun[paramsField]);
|
2017-01-18 20:42:20 +03:00
|
|
|
|
2017-03-18 21:20:07 +03:00
|
|
|
// If the parent is a call with the first/last argument expansion and this is the
|
|
|
|
// params of the first/last argument, we dont want the arguments to break and instead
|
2017-03-03 06:29:53 +03:00
|
|
|
// want the whole expression to be on a new line.
|
|
|
|
//
|
|
|
|
// Good: Bad:
|
|
|
|
// verylongcall( verylongcall((
|
|
|
|
// (a, b) => { a,
|
|
|
|
// } b,
|
|
|
|
// }) ) => {
|
|
|
|
// })
|
2017-04-13 06:24:50 +03:00
|
|
|
if (expandArg) {
|
2017-04-18 18:40:08 +03:00
|
|
|
return group(concat(["(", join(", ", printed.map(removeLines)), ")"]));
|
2017-03-03 06:29:53 +03:00
|
|
|
}
|
|
|
|
|
2017-03-22 19:58:33 +03:00
|
|
|
// Single object destructuring should hug
|
|
|
|
//
|
|
|
|
// function({
|
|
|
|
// a,
|
|
|
|
// b,
|
|
|
|
// c
|
|
|
|
// }) {}
|
2017-05-02 05:12:53 +03:00
|
|
|
if (shouldHugArguments(fun)) {
|
2017-03-22 19:58:33 +03:00
|
|
|
return concat(["(", join(", ", printed), ")"]);
|
|
|
|
}
|
|
|
|
|
2017-04-13 06:24:50 +03:00
|
|
|
const parent = path.getParentNode();
|
2017-04-14 03:54:20 +03:00
|
|
|
|
|
|
|
const flowTypeAnnotations = [
|
|
|
|
"AnyTypeAnnotation",
|
|
|
|
"NullLiteralTypeAnnotation",
|
|
|
|
"GenericTypeAnnotation",
|
|
|
|
"ThisTypeAnnotation",
|
|
|
|
"NumberTypeAnnotation",
|
|
|
|
"VoidTypeAnnotation",
|
|
|
|
"NullTypeAnnotation",
|
|
|
|
"EmptyTypeAnnotation",
|
|
|
|
"MixedTypeAnnotation",
|
|
|
|
"BooleanTypeAnnotation",
|
|
|
|
"BooleanLiteralTypeAnnotation",
|
|
|
|
"StringTypeAnnotation"
|
|
|
|
];
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const isFlowShorthandWithOneArg =
|
|
|
|
(isObjectTypePropertyAFunction(parent) ||
|
|
|
|
isTypeAnnotationAFunction(parent) ||
|
2017-04-24 23:58:30 +03:00
|
|
|
parent.type === "TypeAlias" ||
|
|
|
|
parent.type === "UnionTypeAnnotation" ||
|
|
|
|
parent.type === "IntersectionTypeAnnotation" ||
|
|
|
|
(parent.type === "FunctionTypeAnnotation" &&
|
|
|
|
parent.returnType === fun)) &&
|
2017-04-12 20:16:11 +03:00
|
|
|
fun[paramsField].length === 1 &&
|
|
|
|
fun[paramsField][0].name === null &&
|
2017-04-14 03:54:20 +03:00
|
|
|
fun[paramsField][0].typeAnnotation &&
|
|
|
|
flowTypeAnnotations.indexOf(fun[paramsField][0].typeAnnotation.type) !== -1 &&
|
2017-04-12 20:16:11 +03:00
|
|
|
!fun.rest;
|
2017-03-16 20:32:59 +03:00
|
|
|
|
2017-05-02 00:39:46 +03:00
|
|
|
if (isFlowShorthandWithOneArg) {
|
|
|
|
return concat(printed);
|
|
|
|
}
|
|
|
|
|
2017-04-21 00:46:41 +03:00
|
|
|
const canHaveTrailingComma =
|
|
|
|
!(lastParam && lastParam.type === "RestElement") &&
|
|
|
|
!fun.rest;
|
|
|
|
|
2017-01-05 00:52:49 +03:00
|
|
|
return concat([
|
2017-05-02 00:39:46 +03:00
|
|
|
"(",
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(concat([softline, join(concat([",", line]), printed)])),
|
2017-02-23 20:57:51 +03:00
|
|
|
ifBreak(
|
|
|
|
canHaveTrailingComma && shouldPrintComma(options, "all") ? "," : ""
|
|
|
|
),
|
2017-01-05 00:52:49 +03:00
|
|
|
softline,
|
2017-05-02 00:39:46 +03:00
|
|
|
")"
|
2017-01-05 00:52:49 +03:00
|
|
|
]);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
function canPrintParamsWithoutParens(node) {
|
|
|
|
return (
|
|
|
|
node.params.length === 1 &&
|
|
|
|
!node.rest &&
|
|
|
|
node.params[0].type === "Identifier" &&
|
|
|
|
!node.params[0].typeAnnotation &&
|
2017-05-06 07:44:42 +03:00
|
|
|
!hasBlockComments(node.params[0]) &&
|
2017-04-11 23:50:47 +03:00
|
|
|
!node.params[0].optional &&
|
|
|
|
!node.predicate &&
|
|
|
|
!node.returnType
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-19 18:06:52 +03:00
|
|
|
function printFunctionDeclaration(path, print, options) {
|
|
|
|
var n = path.getValue();
|
|
|
|
var parts = [];
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.async) {
|
|
|
|
parts.push("async ");
|
|
|
|
}
|
2017-03-19 18:06:52 +03:00
|
|
|
|
|
|
|
parts.push("function");
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (n.generator) {
|
|
|
|
parts.push("*");
|
|
|
|
}
|
2017-03-19 18:06:52 +03:00
|
|
|
if (n.id) {
|
|
|
|
parts.push(" ", path.call(print, "id"));
|
|
|
|
}
|
|
|
|
|
|
|
|
parts.push(
|
2017-05-06 05:44:26 +03:00
|
|
|
printFunctionTypeParameters(path, options, print),
|
2017-03-19 18:06:52 +03:00
|
|
|
group(
|
|
|
|
concat([
|
|
|
|
printFunctionParams(path, print, options),
|
|
|
|
printReturnType(path, print)
|
|
|
|
])
|
|
|
|
),
|
|
|
|
" ",
|
|
|
|
path.call(print, "body")
|
|
|
|
);
|
|
|
|
|
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
function printObjectMethod(path, options, print) {
|
|
|
|
var objMethod = path.getValue();
|
|
|
|
var parts = [];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
if (objMethod.async) {
|
|
|
|
parts.push("async ");
|
|
|
|
}
|
|
|
|
if (objMethod.generator) {
|
|
|
|
parts.push("*");
|
|
|
|
}
|
2016-12-31 07:03:22 +03:00
|
|
|
if (
|
|
|
|
objMethod.method || objMethod.kind === "get" || objMethod.kind === "set"
|
|
|
|
) {
|
2016-12-23 21:38:10 +03:00
|
|
|
return printMethod(path, options, print);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-19 20:37:24 +03:00
|
|
|
var key = printPropertyKey(path, options, print);
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (objMethod.computed) {
|
|
|
|
parts.push("[", key, "]");
|
|
|
|
} else {
|
|
|
|
parts.push(key);
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
parts.push(
|
2017-05-06 05:44:26 +03:00
|
|
|
printFunctionTypeParameters(path, options, print),
|
2017-01-24 21:54:01 +03:00
|
|
|
group(
|
2017-01-13 23:03:53 +03:00
|
|
|
concat([
|
|
|
|
printFunctionParams(path, print, options),
|
|
|
|
printReturnType(path, print)
|
|
|
|
])
|
|
|
|
),
|
2016-12-23 21:38:10 +03:00
|
|
|
" ",
|
|
|
|
path.call(print, "body")
|
|
|
|
);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-09 21:47:02 +03:00
|
|
|
return concat(parts);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2016-12-30 21:32:43 +03:00
|
|
|
function printReturnType(path, print) {
|
|
|
|
const n = path.getValue();
|
2017-01-28 18:50:22 +03:00
|
|
|
const parts = [path.call(print, "returnType")];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2017-04-23 04:09:53 +03:00
|
|
|
// prepend colon to TypeScript type annotation
|
|
|
|
if (n.returnType && n.returnType.typeAnnotation) {
|
2017-04-27 19:37:42 +03:00
|
|
|
parts.unshift(": ");
|
2017-04-23 04:09:53 +03:00
|
|
|
}
|
|
|
|
|
2016-12-31 07:03:22 +03:00
|
|
|
if (n.predicate) {
|
2016-12-31 07:10:22 +03:00
|
|
|
// The return type will already add the colon, but otherwise we
|
|
|
|
// need to do it ourselves
|
2017-01-09 20:09:04 +03:00
|
|
|
parts.push(n.returnType ? " " : ": ", path.call(print, "predicate"));
|
2016-12-30 21:32:43 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-30 21:32:43 +03:00
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
function printExportDeclaration(path, options, print) {
|
2017-03-16 02:29:15 +03:00
|
|
|
const decl = path.getValue();
|
2017-04-11 23:50:47 +03:00
|
|
|
const semi = options.semi ? ";" : "";
|
2017-03-16 02:29:15 +03:00
|
|
|
let parts = ["export "];
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
namedTypes.Declaration.assert(decl);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-31 07:03:22 +03:00
|
|
|
if (decl["default"] || decl.type === "ExportDefaultDeclaration") {
|
2016-12-23 21:38:10 +03:00
|
|
|
parts.push("default ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-02-23 20:57:51 +03:00
|
|
|
parts.push(
|
|
|
|
comments.printDanglingComments(path, options, /* sameIndent */ true)
|
|
|
|
);
|
2017-02-20 01:39:09 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (decl.declaration) {
|
|
|
|
parts.push(path.call(print, "declaration"));
|
2017-01-11 15:43:27 +03:00
|
|
|
|
2017-01-13 23:03:53 +03:00
|
|
|
if (
|
|
|
|
decl.type === "ExportDefaultDeclaration" &&
|
2017-02-16 06:56:11 +03:00
|
|
|
(decl.declaration.type !== "ClassDeclaration" &&
|
2017-04-12 20:16:11 +03:00
|
|
|
decl.declaration.type !== "FunctionDeclaration")
|
2017-01-13 23:03:53 +03:00
|
|
|
) {
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2017-01-11 15:43:27 +03:00
|
|
|
}
|
2017-01-16 19:58:23 +03:00
|
|
|
} else {
|
|
|
|
if (decl.specifiers && decl.specifiers.length > 0) {
|
|
|
|
if (
|
|
|
|
decl.specifiers.length === 1 &&
|
2017-02-16 06:56:11 +03:00
|
|
|
decl.specifiers[0].type === "ExportBatchSpecifier"
|
2017-01-16 19:58:23 +03:00
|
|
|
) {
|
|
|
|
parts.push("*");
|
|
|
|
} else {
|
2017-03-16 02:29:15 +03:00
|
|
|
let specifiers = [];
|
|
|
|
let defaultSpecifiers = [];
|
|
|
|
let namespaceSpecifiers = [];
|
|
|
|
|
|
|
|
path.map(specifierPath => {
|
|
|
|
const specifierType = path.getValue().type;
|
|
|
|
if (specifierType === "ExportSpecifier") {
|
|
|
|
specifiers.push(print(specifierPath));
|
|
|
|
} else if (specifierType === "ExportDefaultSpecifier") {
|
|
|
|
defaultSpecifiers.push(print(specifierPath));
|
|
|
|
} else if (specifierType === "ExportNamespaceSpecifier") {
|
|
|
|
namespaceSpecifiers.push(concat(["* as ", print(specifierPath)]));
|
|
|
|
}
|
|
|
|
}, "specifiers");
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const isNamespaceFollowed =
|
|
|
|
namespaceSpecifiers.length !== 0 &&
|
2017-03-16 02:29:15 +03:00
|
|
|
(specifiers.length !== 0 || defaultSpecifiers.length !== 0);
|
2017-04-12 20:16:11 +03:00
|
|
|
const isDefaultFollowed =
|
|
|
|
defaultSpecifiers.length !== 0 && specifiers.length !== 0;
|
2017-03-16 02:29:15 +03:00
|
|
|
|
2017-01-16 19:58:23 +03:00
|
|
|
parts.push(
|
|
|
|
decl.exportKind === "type" ? "type " : "",
|
2017-03-16 02:29:15 +03:00
|
|
|
concat(namespaceSpecifiers),
|
|
|
|
concat([isNamespaceFollowed ? ", " : ""]),
|
|
|
|
concat(defaultSpecifiers),
|
|
|
|
concat([isDefaultFollowed ? ", " : ""]),
|
|
|
|
specifiers.length !== 0
|
|
|
|
? group(
|
2017-04-12 20:16:11 +03:00
|
|
|
concat([
|
|
|
|
"{",
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
join(concat([",", line]), specifiers)
|
|
|
|
])
|
|
|
|
),
|
|
|
|
ifBreak(shouldPrintComma(options) ? "," : ""),
|
|
|
|
options.bracketSpacing ? line : softline,
|
|
|
|
"}"
|
|
|
|
])
|
|
|
|
)
|
|
|
|
: ""
|
2017-01-16 19:58:23 +03:00
|
|
|
);
|
|
|
|
}
|
2017-01-09 20:09:04 +03:00
|
|
|
} else {
|
2017-01-16 19:58:23 +03:00
|
|
|
parts.push("{}");
|
2017-01-09 20:09:04 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-09 20:09:04 +03:00
|
|
|
if (decl.source) {
|
|
|
|
parts.push(" from ", path.call(print, "source"));
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2017-01-11 15:43:27 +03:00
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
parts.push(semi);
|
2017-01-09 20:09:04 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
|
|
|
function printFlowDeclaration(path, parts) {
|
|
|
|
var parentExportDecl = util.getParentExportDeclaration(path);
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
if (parentExportDecl) {
|
2016-12-31 07:03:22 +03:00
|
|
|
assert.strictEqual(parentExportDecl.type, "DeclareExportDeclaration");
|
2016-12-23 21:38:10 +03:00
|
|
|
} 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 ");
|
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-23 21:38:10 +03:00
|
|
|
return concat(parts);
|
|
|
|
}
|
|
|
|
|
2017-04-25 19:48:56 +03:00
|
|
|
function getFlowVariance(path) {
|
2017-03-22 19:37:26 +03:00
|
|
|
if (!path.variance) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Babylon 7.0 currently uses variance node type, and flow should
|
|
|
|
// follow suit soon:
|
|
|
|
// https://github.com/babel/babel/issues/4722
|
|
|
|
const variance = path.variance.kind || path.variance;
|
|
|
|
|
|
|
|
switch (variance) {
|
|
|
|
case "plus":
|
|
|
|
return "+";
|
|
|
|
|
|
|
|
case "minus":
|
|
|
|
return "-";
|
|
|
|
|
|
|
|
default:
|
|
|
|
return variance;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-03 03:06:25 +03:00
|
|
|
function printTypeScriptModifiers(path, options, print) {
|
|
|
|
const n = path.getValue();
|
|
|
|
if (!n.modifiers || !n.modifiers.length) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return concat([
|
|
|
|
join(" ", path.map(print, "modifiers")),
|
|
|
|
" "
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2017-05-03 18:01:45 +03:00
|
|
|
function printTypeParameters(path, options, print, paramsKey) {
|
|
|
|
const n = path.getValue();
|
|
|
|
|
|
|
|
// In flow, Foo<> is acceptable. In TypeScript, it's a syntax error.
|
|
|
|
if (!n[paramsKey] || (n.type.startsWith("TS") && !n[paramsKey].length)) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
const shouldInline =
|
|
|
|
n[paramsKey].length === 1 &&
|
|
|
|
(n[paramsKey][0].type === "ObjectTypeAnnotation" ||
|
|
|
|
n[paramsKey][0].type === "NullableTypeAnnotation");
|
|
|
|
|
|
|
|
if (shouldInline) {
|
|
|
|
return concat(["<", join(", ", path.map(print, paramsKey)), ">"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return group(
|
|
|
|
concat([
|
|
|
|
"<",
|
|
|
|
indent(
|
|
|
|
concat([
|
|
|
|
softline,
|
|
|
|
join(concat([",", line]), path.map(print, paramsKey))
|
|
|
|
])
|
|
|
|
),
|
|
|
|
ifBreak(shouldPrintComma(options, "all") ? "," : ""),
|
|
|
|
softline,
|
|
|
|
">"
|
|
|
|
])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-01-26 00:36:55 +03:00
|
|
|
function printClass(path, options, print) {
|
2016-12-30 08:01:44 +03:00
|
|
|
const n = path.getValue();
|
2017-04-26 19:25:58 +03:00
|
|
|
const parts = [];
|
|
|
|
|
|
|
|
if (n.accessibility) {
|
|
|
|
parts.push(n.accessibility + " ");
|
|
|
|
}
|
|
|
|
if (n.type === "TSAbstractClassDeclaration") {
|
|
|
|
parts.push("abstract ");
|
|
|
|
}
|
|
|
|
|
|
|
|
parts.push("class");
|
2016-12-31 22:38:58 +03:00
|
|
|
|
2016-12-30 08:01:44 +03:00
|
|
|
if (n.id) {
|
2016-12-31 07:03:22 +03:00
|
|
|
parts.push(" ", path.call(print, "id"), path.call(print, "typeParameters"));
|
2016-12-30 08:01:44 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-26 00:36:55 +03:00
|
|
|
const partsGroup = [];
|
2016-12-30 08:01:44 +03:00
|
|
|
if (n.superClass) {
|
2017-01-26 00:36:55 +03:00
|
|
|
partsGroup.push(
|
|
|
|
line,
|
|
|
|
"extends ",
|
2017-01-09 20:09:04 +03:00
|
|
|
path.call(print, "superClass"),
|
|
|
|
path.call(print, "superTypeParameters")
|
|
|
|
);
|
|
|
|
} else if (n.extends && n.extends.length > 0) {
|
2017-01-26 00:36:55 +03:00
|
|
|
partsGroup.push(line, "extends ", join(", ", path.map(print, "extends")));
|
2017-01-09 20:09:04 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-31 07:03:22 +03:00
|
|
|
if (n["implements"] && n["implements"].length > 0) {
|
2017-01-28 18:50:22 +03:00
|
|
|
partsGroup.push(
|
|
|
|
line,
|
|
|
|
"implements ",
|
|
|
|
join(", ", path.map(print, "implements"))
|
|
|
|
);
|
2017-01-26 00:36:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (partsGroup.length > 0) {
|
2017-04-07 05:49:37 +03:00
|
|
|
parts.push(group(indent(concat(partsGroup))));
|
2016-12-30 08:01:44 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-30 08:01:44 +03:00
|
|
|
parts.push(" ", path.call(print, "body"));
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2016-12-30 08:01:44 +03:00
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
2017-01-26 22:58:47 +03:00
|
|
|
function printMemberLookup(path, options, print) {
|
2017-01-05 23:26:45 +03:00
|
|
|
const property = path.call(print, "property");
|
|
|
|
const n = path.getValue();
|
2017-01-26 22:58:47 +03:00
|
|
|
|
2017-05-02 00:41:34 +03:00
|
|
|
if (!n.computed) {
|
|
|
|
return concat([".", property]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
2017-05-04 21:20:52 +03:00
|
|
|
!n.property ||
|
2017-05-02 00:41:34 +03:00
|
|
|
(n.property.type === "Literal" && typeof n.property.value === "number") ||
|
|
|
|
n.property.type === "NumericLiteral"
|
|
|
|
) {
|
|
|
|
return concat(["[", property, "]"]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return group(
|
|
|
|
concat([
|
|
|
|
"[",
|
|
|
|
indent(concat([softline, property])),
|
|
|
|
softline,
|
|
|
|
"]"
|
|
|
|
])
|
2017-01-28 18:50:22 +03:00
|
|
|
);
|
2017-01-05 23:26:45 +03:00
|
|
|
}
|
|
|
|
|
2017-01-08 22:44:44 +03:00
|
|
|
// We detect calls on member expressions specially to format a
|
|
|
|
// comman pattern better. The pattern we are looking for is this:
|
|
|
|
//
|
|
|
|
// arr
|
|
|
|
// .map(x => x + 1)
|
|
|
|
// .filter(x => x > 10)
|
|
|
|
// .some(x => x % 2)
|
|
|
|
//
|
2017-01-31 23:32:42 +03:00
|
|
|
// The way it is structured in the AST is via a nested sequence of
|
|
|
|
// MemberExpression and CallExpression. We need to traverse the AST
|
|
|
|
// and make groups out of it to print it in the desired way.
|
|
|
|
function printMemberChain(path, options, print) {
|
|
|
|
// The first phase is to linearize the AST by traversing it down.
|
|
|
|
//
|
|
|
|
// a().b()
|
|
|
|
// has the following AST structure:
|
|
|
|
// CallExpression(MemberExpression(CallExpression(Identifier)))
|
|
|
|
// and we transform it into
|
|
|
|
// [Identifier, CallExpression, MemberExpression, CallExpression]
|
|
|
|
const printedNodes = [];
|
|
|
|
|
|
|
|
function rec(path) {
|
|
|
|
const node = path.getValue();
|
|
|
|
if (node.type === "CallExpression") {
|
|
|
|
printedNodes.unshift({
|
|
|
|
node: node,
|
2017-02-05 05:31:54 +03:00
|
|
|
printed: comments.printComments(
|
|
|
|
path,
|
2017-05-06 05:44:26 +03:00
|
|
|
() => concat([
|
|
|
|
printFunctionTypeParameters(path, options, print),
|
|
|
|
printArgumentsList(path, options, print)
|
|
|
|
]),
|
2017-02-05 05:31:54 +03:00
|
|
|
options
|
|
|
|
)
|
2017-01-31 23:32:42 +03:00
|
|
|
});
|
|
|
|
path.call(callee => rec(callee), "callee");
|
|
|
|
} else if (node.type === "MemberExpression") {
|
|
|
|
printedNodes.unshift({
|
|
|
|
node: node,
|
2017-02-03 19:50:51 +03:00
|
|
|
printed: comments.printComments(
|
|
|
|
path,
|
2017-04-25 19:48:56 +03:00
|
|
|
() => printMemberLookup(path, options, print),
|
2017-02-03 19:50:51 +03:00
|
|
|
options
|
|
|
|
)
|
2017-01-31 23:32:42 +03:00
|
|
|
});
|
|
|
|
path.call(object => rec(object), "object");
|
|
|
|
} else {
|
|
|
|
printedNodes.unshift({
|
|
|
|
node: node,
|
|
|
|
printed: path.call(print)
|
|
|
|
});
|
2017-01-08 22:44:44 +03:00
|
|
|
}
|
|
|
|
}
|
2017-02-05 05:31:54 +03:00
|
|
|
// Note: the comments of the root node have already been printed, so we
|
|
|
|
// need to extract this first call without printing them as they would
|
|
|
|
// if handled inside of the recursive call.
|
|
|
|
printedNodes.unshift({
|
|
|
|
node: path.getValue(),
|
2017-05-06 05:44:26 +03:00
|
|
|
printed: concat([
|
|
|
|
printFunctionTypeParameters(path, options, print),
|
|
|
|
printArgumentsList(path, options, print)
|
|
|
|
])
|
2017-02-05 05:31:54 +03:00
|
|
|
});
|
|
|
|
path.call(callee => rec(callee), "callee");
|
2017-01-31 23:32:42 +03:00
|
|
|
|
|
|
|
// Once we have a linear list of printed nodes, we want to create groups out
|
|
|
|
// of it.
|
|
|
|
//
|
|
|
|
// a().b.c().d().e
|
|
|
|
// will be grouped as
|
|
|
|
// [
|
|
|
|
// [Identifier, CallExpression],
|
|
|
|
// [MemberExpression, MemberExpression, CallExpression],
|
|
|
|
// [MemberExpression, CallExpression],
|
|
|
|
// [MemberExpression],
|
|
|
|
// ]
|
|
|
|
// so that we can print it as
|
|
|
|
// a()
|
|
|
|
// .b.c()
|
|
|
|
// .d()
|
|
|
|
// .e
|
|
|
|
|
2017-02-04 00:18:54 +03:00
|
|
|
// The first group is the first node followed by
|
|
|
|
// - as many CallExpression as possible
|
|
|
|
// < fn()()() >.something()
|
|
|
|
// - then, as many MemberExpression as possible but the last one
|
|
|
|
// < this.items >.something()
|
2017-01-31 23:32:42 +03:00
|
|
|
var groups = [];
|
|
|
|
var currentGroup = [printedNodes[0]];
|
|
|
|
var i = 1;
|
|
|
|
for (; i < printedNodes.length; ++i) {
|
|
|
|
if (printedNodes[i].node.type === "CallExpression") {
|
|
|
|
currentGroup.push(printedNodes[i]);
|
2017-01-09 20:09:04 +03:00
|
|
|
} else {
|
2017-01-31 23:32:42 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-02-04 00:18:54 +03:00
|
|
|
for (; i + 1 < printedNodes.length; ++i) {
|
2017-02-09 18:44:56 +03:00
|
|
|
if (
|
|
|
|
printedNodes[i].node.type === "MemberExpression" &&
|
2017-02-16 06:56:11 +03:00
|
|
|
printedNodes[i + 1].node.type === "MemberExpression"
|
2017-02-09 18:44:56 +03:00
|
|
|
) {
|
2017-02-04 00:18:54 +03:00
|
|
|
currentGroup.push(printedNodes[i]);
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-01-31 23:32:42 +03:00
|
|
|
groups.push(currentGroup);
|
|
|
|
currentGroup = [];
|
|
|
|
|
|
|
|
// Then, each following group is a sequence of MemberExpression followed by
|
|
|
|
// a sequence of CallExpression. To compute it, we keep adding things to the
|
|
|
|
// group until we has seen a CallExpression in the past and reach a
|
|
|
|
// MemberExpression
|
|
|
|
var hasSeenCallExpression = false;
|
|
|
|
for (; i < printedNodes.length; ++i) {
|
2017-02-03 19:50:51 +03:00
|
|
|
if (
|
|
|
|
hasSeenCallExpression && printedNodes[i].node.type === "MemberExpression"
|
|
|
|
) {
|
2017-02-23 18:34:52 +03:00
|
|
|
// [0] should be appended at the end of the group instead of the
|
|
|
|
// beginning of the next one
|
|
|
|
if (printedNodes[i].node.computed) {
|
|
|
|
currentGroup.push(printedNodes[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-31 23:32:42 +03:00
|
|
|
groups.push(currentGroup);
|
|
|
|
currentGroup = [];
|
|
|
|
hasSeenCallExpression = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (printedNodes[i].node.type === "CallExpression") {
|
|
|
|
hasSeenCallExpression = true;
|
2017-01-08 22:44:44 +03:00
|
|
|
}
|
2017-01-31 23:32:42 +03:00
|
|
|
currentGroup.push(printedNodes[i]);
|
|
|
|
}
|
|
|
|
if (currentGroup.length > 0) {
|
|
|
|
groups.push(currentGroup);
|
2017-01-08 22:44:44 +03:00
|
|
|
}
|
2017-01-31 23:32:42 +03:00
|
|
|
|
|
|
|
// There are cases like Object.keys(), Observable.of(), _.values() where
|
|
|
|
// they are the subject of all the chained calls and therefore should
|
|
|
|
// be kept on the same line:
|
|
|
|
//
|
|
|
|
// Object.keys(items)
|
|
|
|
// .filter(x => x)
|
|
|
|
// .map(x => x)
|
|
|
|
//
|
|
|
|
// In order to detect those cases, we use an heuristic: if the first
|
|
|
|
// node is just an identifier with the name starting with a capital
|
2017-02-23 17:41:44 +03:00
|
|
|
// letter, just a sequence of _$ or this. The rationale is that they are
|
2017-01-31 23:32:42 +03:00
|
|
|
// likely to be factories.
|
2017-04-12 20:16:11 +03:00
|
|
|
const shouldMerge =
|
2017-04-13 03:26:58 +03:00
|
|
|
groups.length >= 2 &&
|
|
|
|
!groups[1][0].node.comments &&
|
2017-04-12 20:16:11 +03:00
|
|
|
groups[0].length === 1 &&
|
2017-02-23 17:41:44 +03:00
|
|
|
(groups[0][0].node.type === "ThisExpression" ||
|
2017-02-23 20:57:51 +03:00
|
|
|
(groups[0][0].node.type === "Identifier" &&
|
2017-04-13 03:26:58 +03:00
|
|
|
groups[0][0].node.name.match(/(^[A-Z])|^[_$]+$/)));
|
2017-01-31 23:32:42 +03:00
|
|
|
|
|
|
|
function printGroup(printedGroup) {
|
|
|
|
return concat(printedGroup.map(tuple => tuple.printed));
|
|
|
|
}
|
|
|
|
|
2017-02-28 18:55:32 +03:00
|
|
|
function printIndentedGroup(groups) {
|
2017-02-13 18:07:33 +03:00
|
|
|
return indent(
|
2017-02-28 18:55:32 +03:00
|
|
|
group(concat([hardline, join(hardline, groups.map(printGroup))]))
|
2017-02-13 18:07:33 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-01-31 23:32:42 +03:00
|
|
|
const printedGroups = groups.map(printGroup);
|
|
|
|
const oneLine = concat(printedGroups);
|
2017-03-20 19:32:49 +03:00
|
|
|
const hasComment =
|
|
|
|
(groups.length >= 2 && groups[1][0].node.comments) ||
|
|
|
|
(groups.length >= 3 && groups[2][0].node.comments);
|
2017-01-31 23:32:42 +03:00
|
|
|
|
|
|
|
// If we only have a single `.`, we shouldn't do anything fancy and just
|
|
|
|
// render everything concatenated together.
|
2017-03-01 20:37:02 +03:00
|
|
|
if (
|
|
|
|
groups.length <= (shouldMerge ? 3 : 2) &&
|
|
|
|
!hasComment &&
|
|
|
|
// (a || b).map() should be break before .map() instead of ||
|
|
|
|
groups[0][0].node.type !== "LogicalExpression"
|
|
|
|
) {
|
2017-01-31 23:32:42 +03:00
|
|
|
return group(oneLine);
|
|
|
|
}
|
|
|
|
|
|
|
|
const expanded = concat([
|
|
|
|
printGroup(groups[0]),
|
2017-02-28 18:55:32 +03:00
|
|
|
shouldMerge ? concat(groups.slice(1, 2).map(printGroup)) : "",
|
|
|
|
printIndentedGroup(groups.slice(shouldMerge ? 2 : 1))
|
2017-01-31 23:32:42 +03:00
|
|
|
]);
|
|
|
|
|
2017-02-13 20:05:18 +03:00
|
|
|
// If there's a comment, we don't want to print in one line.
|
|
|
|
if (hasComment) {
|
|
|
|
return group(expanded);
|
|
|
|
}
|
|
|
|
|
2017-01-31 23:32:42 +03:00
|
|
|
// If any group but the last one has a hard line, we want to force expand
|
|
|
|
// it. If the last group is a function it's okay to inline if it fits.
|
|
|
|
if (printedGroups.slice(0, -1).some(willBreak)) {
|
|
|
|
return group(expanded);
|
|
|
|
}
|
|
|
|
|
2017-04-12 19:26:27 +03:00
|
|
|
return concat([
|
|
|
|
// We only need to check `oneLine` because if `expanded` is chosen
|
|
|
|
// that means that the parent group has already been broken
|
|
|
|
// naturally
|
|
|
|
willBreak(oneLine) ? breakParent : "",
|
|
|
|
conditionalGroup([oneLine, expanded])
|
2017-04-12 20:16:11 +03:00
|
|
|
]);
|
2017-01-08 22:44:44 +03:00
|
|
|
}
|
|
|
|
|
2017-01-19 00:25:20 +03:00
|
|
|
function isEmptyJSXElement(node) {
|
2017-05-03 03:06:25 +03:00
|
|
|
if (node.children.length === 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (node.children.length > 1) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
|
|
|
|
// if there is one child but it's just a newline, treat as empty
|
|
|
|
const value = node.children[0].value;
|
|
|
|
if (!/\S/.test(value) && /\n/.test(value)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSX Children are strange, mostly for two reasons:
|
|
|
|
// 1. JSX reads newlines into string values, instead of skipping them like JS
|
|
|
|
// 2. up to one whitespace between elements within a line is significant,
|
|
|
|
// but not between lines.
|
|
|
|
//
|
|
|
|
// So for one thing, '\n' needs to be parsed out of string literals
|
|
|
|
// and turned into hardlines (with string boundaries otherwise using softline)
|
|
|
|
//
|
|
|
|
// For another, leading, trailing, and lone whitespace all need to
|
|
|
|
// turn themselves into the rather ugly `{' '}` when breaking.
|
2017-02-07 21:47:34 +03:00
|
|
|
function printJSXChildren(path, options, print, jsxWhitespace) {
|
2017-01-19 00:25:20 +03:00
|
|
|
const n = path.getValue();
|
|
|
|
const children = [];
|
|
|
|
|
|
|
|
// using `map` instead of `each` because it provides `i`
|
2017-04-12 20:16:11 +03:00
|
|
|
path.map(function(childPath, i) {
|
|
|
|
const child = childPath.getValue();
|
|
|
|
const isLiteral = namedTypes.Literal.check(child);
|
|
|
|
|
|
|
|
if (isLiteral && typeof child.value === "string") {
|
2017-05-03 18:47:15 +03:00
|
|
|
const value = child.raw || child.extra.raw;
|
2017-04-12 20:16:11 +03:00
|
|
|
|
|
|
|
if (/\S/.test(value)) {
|
|
|
|
// treat each line of text as its own entity
|
|
|
|
value.split(/(\r?\n\s*)/).forEach(line => {
|
|
|
|
const newlines = line.match(/\n/g);
|
|
|
|
if (newlines) {
|
|
|
|
children.push(hardline);
|
2017-01-27 22:20:01 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
// allow one extra newline
|
|
|
|
if (newlines.length > 1) {
|
|
|
|
children.push(hardline);
|
2017-01-27 22:20:01 +03:00
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-01-27 22:20:01 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const beginSpace = /^\s+/.test(line);
|
|
|
|
if (beginSpace) {
|
|
|
|
children.push(jsxWhitespace);
|
|
|
|
children.push(softline);
|
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const stripped = line.replace(/^\s+|\s+$/g, "");
|
|
|
|
if (stripped) {
|
|
|
|
children.push(stripped);
|
|
|
|
}
|
2017-02-07 17:58:25 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
const endSpace = /\s+$/.test(line);
|
|
|
|
if (endSpace) {
|
2017-02-15 00:41:51 +03:00
|
|
|
children.push(softline);
|
2017-04-12 20:16:11 +03:00
|
|
|
children.push(jsxWhitespace);
|
2017-02-15 00:41:51 +03:00
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
});
|
2017-01-27 22:20:01 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
if (!isLineNext(util.getLast(children))) {
|
2017-01-19 00:25:20 +03:00
|
|
|
children.push(softline);
|
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
} else if (/\n/.test(value)) {
|
|
|
|
children.push(hardline);
|
2017-01-19 00:25:20 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
// allow one extra newline
|
|
|
|
if (value.match(/\n/g).length > 1) {
|
|
|
|
children.push(hardline);
|
2017-01-19 02:31:46 +03:00
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
} else if (/\s/.test(value)) {
|
2017-05-03 18:47:15 +03:00
|
|
|
// whitespace(s)-only without newlines,
|
|
|
|
// eg; one or more spaces separating two elements
|
|
|
|
for (let i = 0; i < value.length; ++i) {
|
|
|
|
children.push(jsxWhitespace);
|
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
children.push(softline);
|
2017-01-19 00:25:20 +03:00
|
|
|
}
|
2017-04-12 20:16:11 +03:00
|
|
|
} else {
|
|
|
|
children.push(print(childPath));
|
|
|
|
|
|
|
|
// add a line unless it's followed by a JSX newline
|
|
|
|
let next = n.children[i + 1];
|
|
|
|
if (!(next && /^\s*\n/.test(next.value))) {
|
|
|
|
children.push(softline);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, "children");
|
2017-01-19 00:25:20 +03:00
|
|
|
|
|
|
|
return children;
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSX expands children from the inside-out, instead of the outside-in.
|
|
|
|
// This is both to break children before attributes,
|
|
|
|
// and to ensure that when children break, their parents do as well.
|
|
|
|
//
|
|
|
|
// Any element that is written without any newlines and fits on a single line
|
|
|
|
// is left that way.
|
|
|
|
// Not only that, any user-written-line containing multiple JSX siblings
|
|
|
|
// should also be kept on one line if possible,
|
|
|
|
// so each user-written-line is wrapped in its own group.
|
|
|
|
//
|
|
|
|
// Elements that contain newlines or don't fit on a single line (recursively)
|
|
|
|
// are fully-split, using hardline and shouldBreak: true.
|
|
|
|
//
|
|
|
|
// To support that case properly, all leading and trailing spaces
|
|
|
|
// are stripped from the list of children, and replaced with a single hardline.
|
2017-01-12 02:15:12 +03:00
|
|
|
function printJSXElement(path, options, print) {
|
|
|
|
const n = path.getValue();
|
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
// Turn <div></div> into <div />
|
2017-01-19 00:25:20 +03:00
|
|
|
if (isEmptyJSXElement(n)) {
|
|
|
|
n.openingElement.selfClosing = true;
|
|
|
|
delete n.closingElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
const openingLines = path.call(print, "openingElement");
|
2017-04-11 19:33:02 +03:00
|
|
|
const closingLines = path.call(print, "closingElement");
|
|
|
|
|
|
|
|
if (
|
|
|
|
n.children.length === 1 &&
|
|
|
|
n.children[0].type === "JSXExpressionContainer" &&
|
|
|
|
(n.children[0].expression.type === "TemplateLiteral" ||
|
|
|
|
n.children[0].expression.type === "TaggedTemplateExpression")
|
|
|
|
) {
|
|
|
|
return concat([
|
|
|
|
openingLines,
|
|
|
|
concat(path.map(print, "children")),
|
|
|
|
closingLines
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no children, just print the opening element
|
2017-01-12 02:15:12 +03:00
|
|
|
if (n.openingElement.selfClosing) {
|
|
|
|
assert.ok(!n.closingElement);
|
2017-01-19 00:25:20 +03:00
|
|
|
return openingLines;
|
|
|
|
}
|
2017-03-08 04:19:05 +03:00
|
|
|
// Record any breaks. Should never go from true to false, only false to true.
|
|
|
|
let forcedBreak = willBreak(openingLines);
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-02-07 21:47:34 +03:00
|
|
|
const jsxWhitespace = options.singleQuote
|
|
|
|
? ifBreak("{' '}", " ")
|
|
|
|
: ifBreak('{" "}', " ");
|
|
|
|
const children = printJSXChildren(path, options, print, jsxWhitespace);
|
2017-01-19 00:25:20 +03:00
|
|
|
|
2017-01-27 22:20:01 +03:00
|
|
|
// Trim trailing lines, recording if there was a hardline
|
|
|
|
let numTrailingHard = 0;
|
2017-01-24 02:47:11 +03:00
|
|
|
while (children.length && isLineNext(util.getLast(children))) {
|
|
|
|
if (willBreak(util.getLast(children))) {
|
2017-01-27 22:20:01 +03:00
|
|
|
++numTrailingHard;
|
2017-01-24 02:47:11 +03:00
|
|
|
forcedBreak = true;
|
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
children.pop();
|
|
|
|
}
|
2017-01-27 22:20:01 +03:00
|
|
|
// allow one extra newline
|
|
|
|
if (numTrailingHard > 1) {
|
|
|
|
children.push(hardline);
|
|
|
|
}
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-01-27 22:20:01 +03:00
|
|
|
// Trim leading lines, recording if there was a hardline
|
|
|
|
let numLeadingHard = 0;
|
2017-01-24 02:47:11 +03:00
|
|
|
while (children.length && isLineNext(children[0])) {
|
|
|
|
if (willBreak(children[0])) {
|
2017-01-27 22:20:01 +03:00
|
|
|
++numLeadingHard;
|
2017-01-24 02:47:11 +03:00
|
|
|
forcedBreak = true;
|
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
children.shift();
|
|
|
|
}
|
2017-01-27 22:20:01 +03:00
|
|
|
// allow one extra newline
|
|
|
|
if (numLeadingHard > 1) {
|
|
|
|
children.unshift(hardline);
|
|
|
|
}
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
// Group by line, recording if there was a hardline.
|
2017-02-07 21:47:34 +03:00
|
|
|
let groups = [[]]; // Initialize the first line's group
|
|
|
|
children.forEach((child, i) => {
|
|
|
|
// leading and trailing JSX whitespace don't go into a group
|
|
|
|
if (child === jsxWhitespace) {
|
|
|
|
if (i === 0) {
|
|
|
|
groups.unshift(child);
|
|
|
|
return;
|
|
|
|
} else if (i === children.length - 1) {
|
|
|
|
groups.push(child);
|
|
|
|
return;
|
|
|
|
}
|
2017-01-24 02:47:11 +03:00
|
|
|
}
|
2017-01-12 02:15:12 +03:00
|
|
|
|
2017-02-07 21:47:34 +03:00
|
|
|
let prev = children[i - 1];
|
|
|
|
if (prev && willBreak(prev)) {
|
|
|
|
forcedBreak = true;
|
2017-01-12 23:45:47 +03:00
|
|
|
|
2017-02-07 21:47:34 +03:00
|
|
|
// On a new line, so create a new group and put this element in it.
|
|
|
|
groups.push([child]);
|
|
|
|
} else {
|
|
|
|
// Not on a newline, so add this element to the current group.
|
|
|
|
util.getLast(groups).push(child);
|
|
|
|
}
|
2017-01-24 02:47:11 +03:00
|
|
|
|
2017-02-07 21:47:34 +03:00
|
|
|
// Ensure we record hardline of last element.
|
|
|
|
if (!forcedBreak && i === children.length - 1) {
|
|
|
|
if (willBreak(child)) forcedBreak = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const childrenGroupedByLine = [
|
|
|
|
hardline,
|
|
|
|
// Conditional groups suppress break propagation; we want to output
|
|
|
|
// hard lines without breaking up the entire jsx element.
|
|
|
|
// Note that leading and trailing JSX Whitespace don't go into a group.
|
2017-02-16 06:56:11 +03:00
|
|
|
concat(
|
|
|
|
groups.map(
|
|
|
|
contents =>
|
2017-04-12 20:16:11 +03:00
|
|
|
(Array.isArray(contents)
|
2017-02-16 06:56:11 +03:00
|
|
|
? conditionalGroup([concat(contents)])
|
2017-04-12 20:16:11 +03:00
|
|
|
: contents)
|
2017-02-16 06:56:11 +03:00
|
|
|
)
|
|
|
|
)
|
2017-02-07 21:47:34 +03:00
|
|
|
];
|
2017-01-12 23:45:47 +03:00
|
|
|
|
2017-01-19 02:31:46 +03:00
|
|
|
const multiLineElem = group(
|
|
|
|
concat([
|
|
|
|
openingLines,
|
2017-04-12 20:16:11 +03:00
|
|
|
indent(group(concat(childrenGroupedByLine), { shouldBreak: true })),
|
2017-01-19 02:31:46 +03:00
|
|
|
hardline,
|
|
|
|
closingLines
|
|
|
|
])
|
|
|
|
);
|
2017-01-19 00:25:20 +03:00
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
if (forcedBreak) {
|
|
|
|
return multiLineElem;
|
2017-01-12 02:15:12 +03:00
|
|
|
}
|
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
return conditionalGroup([
|
2017-01-28 18:50:22 +03:00
|
|
|
group(concat([openingLines, concat(children), closingLines])),
|
2017-01-24 02:47:11 +03:00
|
|
|
multiLineElem
|
|
|
|
]);
|
2017-01-19 00:25:20 +03:00
|
|
|
}
|
|
|
|
|
2017-04-25 19:48:56 +03:00
|
|
|
function maybeWrapJSXElementInParens(path, elem) {
|
2017-01-12 02:15:12 +03:00
|
|
|
const parent = path.getParentNode();
|
2017-05-03 03:06:25 +03:00
|
|
|
if (!parent) {
|
|
|
|
return elem;
|
|
|
|
}
|
2017-01-19 00:25:20 +03:00
|
|
|
|
|
|
|
const NO_WRAP_PARENTS = {
|
2017-03-05 19:56:07 +03:00
|
|
|
ArrayExpression: true,
|
2017-01-19 02:31:46 +03:00
|
|
|
JSXElement: true,
|
2017-03-01 23:05:57 +03:00
|
|
|
JSXExpressionContainer: true,
|
2017-01-19 02:31:46 +03:00
|
|
|
ExpressionStatement: true,
|
|
|
|
CallExpression: true,
|
2017-01-26 22:51:08 +03:00
|
|
|
ConditionalExpression: true,
|
2017-01-28 18:50:22 +03:00
|
|
|
LogicalExpression: true
|
2017-01-19 00:25:20 +03:00
|
|
|
};
|
|
|
|
if (NO_WRAP_PARENTS[parent.type]) {
|
2017-01-12 02:15:12 +03:00
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
|
2017-01-24 21:54:01 +03:00
|
|
|
return group(
|
2017-01-13 23:03:53 +03:00
|
|
|
concat([
|
|
|
|
ifBreak("("),
|
2017-04-07 05:49:37 +03:00
|
|
|
indent(concat([softline, elem])),
|
2017-01-13 23:03:53 +03:00
|
|
|
softline,
|
|
|
|
ifBreak(")")
|
|
|
|
])
|
|
|
|
);
|
2017-01-12 02:15:12 +03:00
|
|
|
}
|
|
|
|
|
2017-01-19 01:01:17 +03:00
|
|
|
function isBinaryish(node) {
|
|
|
|
return node.type === "BinaryExpression" || node.type === "LogicalExpression";
|
|
|
|
}
|
|
|
|
|
2017-02-15 17:41:06 +03:00
|
|
|
function shouldInlineLogicalExpression(node) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
node.type === "LogicalExpression" &&
|
2017-02-16 06:56:11 +03:00
|
|
|
(node.right.type === "ObjectExpression" ||
|
2017-04-12 20:16:11 +03:00
|
|
|
node.right.type === "ArrayExpression")
|
|
|
|
);
|
2017-02-15 17:41:06 +03:00
|
|
|
}
|
|
|
|
|
2017-01-19 01:01:17 +03:00
|
|
|
// For binary expressions to be consistent, we need to group
|
|
|
|
// subsequent operators with the same precedence level under a single
|
|
|
|
// group. Otherwise they will be nested such that some of them break
|
|
|
|
// onto new lines but not all. Operators with the same precedence
|
|
|
|
// level should either all break or not. Because we group them by
|
|
|
|
// precedence level and the AST is structured based on precedence
|
|
|
|
// level, things are naturally broken up correctly, i.e. `&&` is
|
|
|
|
// broken before `+`.
|
2017-04-19 20:43:48 +03:00
|
|
|
function printBinaryishExpressions(path, print, options, isNested, isInsideParenthesis) {
|
2017-03-22 00:49:08 +03:00
|
|
|
let parts = [];
|
2017-01-19 01:01:17 +03:00
|
|
|
let node = path.getValue();
|
|
|
|
|
|
|
|
// We treat BinaryExpression and LogicalExpression nodes the same.
|
2017-01-19 02:31:46 +03:00
|
|
|
if (isBinaryish(node)) {
|
2017-01-19 01:01:17 +03:00
|
|
|
// Put all operators with the same precedence level in the same
|
|
|
|
// group. The reason we only need to do this with the `left`
|
|
|
|
// expression is because given an expression like `1 + 2 - 3`, it
|
|
|
|
// is always parsed like `((1 + 2) - 3)`, meaning the `left` side
|
|
|
|
// is where the rest of the expression will exist. Binary
|
|
|
|
// expressions on the right side mean they have a difference
|
|
|
|
// precedence level and should be treated as a separate group, so
|
2017-03-09 00:11:53 +03:00
|
|
|
// print them normally. (This doesn't hold for the `**` operator,
|
|
|
|
// which is unique in that it is right-associative.)
|
2017-01-19 02:31:46 +03:00
|
|
|
if (
|
|
|
|
util.getPrecedence(node.left.operator) ===
|
2017-04-12 20:16:11 +03:00
|
|
|
util.getPrecedence(node.operator) && node.operator !== "**"
|
2017-01-19 02:31:46 +03:00
|
|
|
) {
|
2017-03-22 00:49:08 +03:00
|
|
|
// Flatten them out by recursively calling this function.
|
2017-04-12 20:16:11 +03:00
|
|
|
parts = parts.concat(
|
|
|
|
path.call(
|
|
|
|
left =>
|
|
|
|
printBinaryishExpressions(
|
|
|
|
left,
|
|
|
|
print,
|
|
|
|
options,
|
2017-04-19 20:43:48 +03:00
|
|
|
/* isNested */ true,
|
|
|
|
isInsideParenthesis
|
2017-04-12 20:16:11 +03:00
|
|
|
),
|
|
|
|
"left"
|
|
|
|
)
|
|
|
|
);
|
2017-01-19 02:31:46 +03:00
|
|
|
} else {
|
2017-01-19 01:01:17 +03:00
|
|
|
parts.push(path.call(print, "left"));
|
|
|
|
}
|
|
|
|
|
2017-02-15 17:41:06 +03:00
|
|
|
const right = concat([
|
|
|
|
node.operator,
|
|
|
|
shouldInlineLogicalExpression(node) ? " " : line,
|
|
|
|
path.call(print, "right")
|
|
|
|
]);
|
2017-02-09 18:44:03 +03:00
|
|
|
|
2017-03-03 06:45:26 +03:00
|
|
|
// If there's only a single binary expression, we want to create a group
|
|
|
|
// in order to avoid having a small right part like -1 be on its own line.
|
2017-02-09 18:44:03 +03:00
|
|
|
const parent = path.getParentNode();
|
2017-04-12 20:16:11 +03:00
|
|
|
const shouldGroup =
|
2017-04-19 23:18:01 +03:00
|
|
|
!(isInsideParenthesis && node.type === "LogicalExpression") &&
|
2017-04-12 20:16:11 +03:00
|
|
|
parent.type !== node.type &&
|
2017-03-03 06:45:26 +03:00
|
|
|
node.left.type !== node.type &&
|
|
|
|
node.right.type !== node.type;
|
2017-02-09 18:44:03 +03:00
|
|
|
|
|
|
|
parts.push(" ", shouldGroup ? group(right) : right);
|
2017-01-27 22:03:44 +03:00
|
|
|
|
|
|
|
// The root comments are already printed, but we need to manually print
|
|
|
|
// the other ones since we don't call the normal print on BinaryExpression,
|
|
|
|
// only for the left and right parts
|
|
|
|
if (isNested && node.comments) {
|
2017-04-25 19:48:56 +03:00
|
|
|
parts = comments.printComments(path, () => concat(parts), options);
|
2017-01-27 22:03:44 +03:00
|
|
|
}
|
2017-01-19 02:31:46 +03:00
|
|
|
} else {
|
2017-01-19 01:01:17 +03:00
|
|
|
// Our stopping case. Simply print the node normally.
|
|
|
|
parts.push(path.call(print));
|
|
|
|
}
|
|
|
|
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
2017-04-27 21:21:42 +03:00
|
|
|
function printAssignmentRight(rightNode, printedRight, canBreak, options) {
|
|
|
|
if (hasLeadingOwnLineComment(options.originalText, rightNode)) {
|
|
|
|
return indent(concat([hardline, printedRight]));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canBreak) {
|
|
|
|
return indent(concat([line, printedRight]));
|
|
|
|
}
|
|
|
|
|
|
|
|
return concat([" ", printedRight]);
|
|
|
|
}
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
function printAssignment(
|
2017-04-14 03:09:00 +03:00
|
|
|
leftNode,
|
2017-04-12 20:16:11 +03:00
|
|
|
printedLeft,
|
|
|
|
operator,
|
|
|
|
rightNode,
|
|
|
|
printedRight,
|
|
|
|
options
|
|
|
|
) {
|
2017-03-15 19:45:40 +03:00
|
|
|
if (!rightNode) {
|
|
|
|
return printedLeft;
|
|
|
|
}
|
|
|
|
|
2017-04-27 21:21:42 +03:00
|
|
|
const canBreak = (
|
2017-04-07 20:51:02 +03:00
|
|
|
(isBinaryish(rightNode) && !shouldInlineLogicalExpression(rightNode)) ||
|
2017-04-14 04:31:21 +03:00
|
|
|
(leftNode.type === "Identifier" || leftNode.type === "MemberExpression") &&
|
|
|
|
(rightNode.type === "StringLiteral" ||
|
|
|
|
(rightNode.type === "Literal" && typeof rightNode.value === "string") ||
|
|
|
|
isMemberExpressionChain(rightNode))
|
2017-04-27 21:21:42 +03:00
|
|
|
);
|
|
|
|
|
|
|
|
const printed = printAssignmentRight(
|
|
|
|
rightNode,
|
|
|
|
printedRight,
|
|
|
|
canBreak,
|
|
|
|
options
|
|
|
|
);
|
2017-03-15 19:45:40 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
return group(concat([printedLeft, " ", operator, printed]));
|
2017-03-15 19:45:40 +03:00
|
|
|
}
|
|
|
|
|
2017-04-13 06:25:44 +03:00
|
|
|
function adjustClause(node, clause, forceSpace) {
|
|
|
|
if (node.type === "EmptyStatement") {
|
2017-01-16 20:54:39 +03:00
|
|
|
return ";";
|
|
|
|
}
|
|
|
|
|
2017-04-13 06:25:44 +03:00
|
|
|
if (node.type === "BlockStatement" || forceSpace) {
|
2017-01-28 18:50:22 +03:00
|
|
|
return concat([" ", clause]);
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-04-07 05:49:37 +03:00
|
|
|
return indent(concat([line, clause]));
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
|
|
|
|
2017-01-18 00:47:20 +03:00
|
|
|
function nodeStr(node, options) {
|
|
|
|
const str = node.value;
|
2016-12-23 21:38:10 +03:00
|
|
|
isString.assert(str);
|
2016-12-31 07:10:22 +03:00
|
|
|
|
2017-01-22 23:32:43 +03:00
|
|
|
const raw = node.extra ? node.extra.raw : node.raw;
|
|
|
|
// `rawContent` is the string exactly like it appeared in the input source
|
|
|
|
// code, with its enclosing quote.
|
|
|
|
const rawContent = raw.slice(1, -1);
|
2017-01-12 07:36:47 +03:00
|
|
|
|
2017-01-22 23:32:43 +03:00
|
|
|
const double = { quote: '"', regex: /"/g };
|
|
|
|
const single = { quote: "'", regex: /'/g };
|
2017-01-12 07:36:47 +03:00
|
|
|
|
2017-01-22 23:32:43 +03:00
|
|
|
const preferred = options.singleQuote ? single : double;
|
|
|
|
const alternate = preferred === single ? double : single;
|
|
|
|
|
|
|
|
let shouldUseAlternateQuote = false;
|
2017-01-18 00:47:20 +03:00
|
|
|
|
2017-01-22 23:32:43 +03:00
|
|
|
// If `rawContent` contains at least one of the quote preferred for enclosing
|
|
|
|
// the string, we might want to enclose with the alternate quote instead, to
|
|
|
|
// minimize the number of escaped quotes.
|
|
|
|
if (rawContent.includes(preferred.quote)) {
|
|
|
|
const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
|
|
|
|
const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
|
|
|
|
|
|
|
|
shouldUseAlternateQuote = numPreferredQuotes > numAlternateQuotes;
|
2017-01-18 00:47:20 +03:00
|
|
|
}
|
|
|
|
|
2017-01-22 23:32:43 +03:00
|
|
|
const enclosingQuote = shouldUseAlternateQuote
|
|
|
|
? alternate.quote
|
|
|
|
: preferred.quote;
|
|
|
|
|
|
|
|
// It might sound unnecessary to use `makeString` even if `node.raw` already
|
|
|
|
// is enclosed with `enclosingQuote`, but it isn't. `node.raw` could contain
|
|
|
|
// unnecessary escapes (such as in `"\'"`). Always using `makeString` makes
|
|
|
|
// sure that we consistently output the minimum amount of escaped quotes.
|
|
|
|
return makeString(rawContent, enclosingQuote);
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeString(rawContent, enclosingQuote) {
|
|
|
|
const otherQuote = enclosingQuote === '"' ? "'" : '"';
|
|
|
|
|
|
|
|
// Matches _any_ escape and unescaped quotes (both single and double).
|
|
|
|
const regex = /\\([\s\S])|(['"])/g;
|
|
|
|
|
|
|
|
// Escape and unescape single and double quotes as needed to be able to
|
|
|
|
// enclose `rawContent` with `enclosingQuote`.
|
|
|
|
const newContent = rawContent.replace(regex, (match, escaped, quote) => {
|
|
|
|
// If we matched an escape, and the escaped character is a quote of the
|
|
|
|
// other type than we intend to enclose the string with, there's no need for
|
|
|
|
// it to be escaped, so return it _without_ the backslash.
|
|
|
|
if (escaped === otherQuote) {
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we matched an unescaped quote and it is of the _same_ type as we
|
|
|
|
// intend to enclose the string with, it must be escaped, so return it with
|
|
|
|
// a backslash.
|
|
|
|
if (quote === enclosingQuote) {
|
|
|
|
return "\\" + quote;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise return the escape or unescaped quote as-is.
|
|
|
|
return match;
|
|
|
|
});
|
|
|
|
|
2017-02-02 20:54:10 +03:00
|
|
|
return enclosingQuote + newContent + enclosingQuote;
|
2016-12-23 21:38:10 +03:00
|
|
|
}
|
2016-12-31 07:01:07 +03:00
|
|
|
|
2017-04-19 20:24:13 +03:00
|
|
|
function printRegex(node) {
|
|
|
|
const flags = node.flags.split('').sort().join('');
|
|
|
|
return `/${node.pattern}/${flags}`;
|
|
|
|
}
|
|
|
|
|
2017-01-30 20:36:23 +03:00
|
|
|
function printNumber(rawNumber) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
rawNumber
|
|
|
|
.toLowerCase()
|
|
|
|
// Remove unnecessary plus and zeroes from scientific notation.
|
|
|
|
.replace(/^([\d.]+e)(?:\+|(-))?0*(\d)/, "$1$2$3")
|
|
|
|
// Remove unnecessary scientific notation (1e0).
|
|
|
|
.replace(/^([\d.]+)e[+-]?0+$/, "$1")
|
|
|
|
// Make sure numbers always start with a digit.
|
|
|
|
.replace(/^\./, "0.")
|
|
|
|
// Remove trailing dot.
|
|
|
|
.replace(/\.(?=e|$)/, "")
|
|
|
|
);
|
2017-01-30 20:36:23 +03:00
|
|
|
}
|
|
|
|
|
2016-12-31 07:01:07 +03:00
|
|
|
function isLastStatement(path) {
|
|
|
|
const parent = path.getParentNode();
|
2017-05-03 03:06:25 +03:00
|
|
|
if (!parent) {
|
|
|
|
return true;
|
|
|
|
}
|
2016-12-31 07:01:07 +03:00
|
|
|
const node = path.getValue();
|
2017-04-22 17:57:52 +03:00
|
|
|
const body = parent.body.filter(stmt => stmt.type !== "EmptyStatement");
|
2016-12-31 07:01:07 +03:00
|
|
|
return body && body[body.length - 1] === node;
|
|
|
|
}
|
2017-01-19 23:43:10 +03:00
|
|
|
|
2017-02-28 18:00:28 +03:00
|
|
|
function hasLeadingOwnLineComment(text, node) {
|
2017-04-12 20:16:11 +03:00
|
|
|
const res =
|
|
|
|
node.comments &&
|
2017-03-01 20:37:02 +03:00
|
|
|
node.comments.some(
|
2017-04-12 20:16:11 +03:00
|
|
|
comment => comment.leading && util.hasNewline(text, util.locEnd(comment))
|
2017-02-28 18:00:28 +03:00
|
|
|
);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
function hasNakedLeftSide(node) {
|
|
|
|
return (
|
|
|
|
node.type === "AssignmentExpression" ||
|
|
|
|
node.type === "BinaryExpression" ||
|
|
|
|
node.type === "LogicalExpression" ||
|
|
|
|
node.type === "ConditionalExpression" ||
|
|
|
|
node.type === "CallExpression" ||
|
|
|
|
node.type === "MemberExpression" ||
|
|
|
|
node.type === "SequenceExpression" ||
|
2017-04-28 00:00:53 +03:00
|
|
|
node.type === "TaggedTemplateExpression" ||
|
|
|
|
(node.type === "UpdateExpression" && !node.prefix)
|
2017-04-11 23:50:47 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLeftSide(node) {
|
|
|
|
if (node.expressions) {
|
|
|
|
return node.expressions[0];
|
|
|
|
}
|
2017-04-28 00:00:53 +03:00
|
|
|
return node.left || node.test || node.callee || node.object || node.tag || node.argument;
|
2017-04-11 23:50:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function exprNeedsASIProtection(node) {
|
|
|
|
// HACK: node.needsParens is added in `genericPrint()` for the sole purpose
|
|
|
|
// of being used here. It'd be preferable to find a cleaner way to do this.
|
2017-04-12 20:16:11 +03:00
|
|
|
const maybeASIProblem =
|
|
|
|
node.needsParens ||
|
2017-04-11 23:50:47 +03:00
|
|
|
node.type === "ParenthesizedExpression" ||
|
|
|
|
node.type === "TypeCastExpression" ||
|
|
|
|
(node.type === "ArrowFunctionExpression" &&
|
|
|
|
!canPrintParamsWithoutParens(node)) ||
|
|
|
|
node.type === "ArrayExpression" ||
|
|
|
|
node.type === "ArrayPattern" ||
|
|
|
|
(node.type === "UnaryExpression" &&
|
|
|
|
node.prefix &&
|
|
|
|
(node.operator === "+" || node.operator === "-")) ||
|
|
|
|
node.type === "TemplateLiteral" ||
|
|
|
|
node.type === "TemplateElement" ||
|
|
|
|
node.type === "JSXElement" ||
|
2017-04-28 00:00:04 +03:00
|
|
|
node.type === "BindExpression" ||
|
2017-04-11 23:50:47 +03:00
|
|
|
node.type === "RegExpLiteral" ||
|
|
|
|
(node.type === "Literal" && node.pattern) ||
|
|
|
|
(node.type === "Literal" && node.regex);
|
|
|
|
|
|
|
|
if (maybeASIProblem) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasNakedLeftSide(node)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return exprNeedsASIProtection(getLeftSide(node));
|
|
|
|
}
|
|
|
|
|
|
|
|
function stmtNeedsASIProtection(path) {
|
2017-05-03 03:06:25 +03:00
|
|
|
if (!path) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-11 23:50:47 +03:00
|
|
|
const node = path.getNode();
|
|
|
|
|
|
|
|
if (node.type !== "ExpressionStatement") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return exprNeedsASIProtection(node.expression);
|
|
|
|
}
|
|
|
|
|
|
|
|
function classPropMayCauseASIProblems(path) {
|
|
|
|
const node = path.getNode();
|
|
|
|
|
|
|
|
if (node.type !== "ClassProperty") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const name = node.key && node.key.name;
|
|
|
|
if (!name) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this isn't actually possible yet with most parsers available today
|
|
|
|
// so isn't properly tested yet.
|
|
|
|
if (name === "static" || name === "get" || name === "set") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function classChildNeedsASIProtection(node) {
|
2017-05-03 03:06:25 +03:00
|
|
|
if (!node) {
|
|
|
|
return;
|
|
|
|
}
|
2017-04-11 23:50:47 +03:00
|
|
|
|
|
|
|
switch (node.type) {
|
|
|
|
case "ClassProperty":
|
2017-05-01 03:41:19 +03:00
|
|
|
case "TSAbstractClassProperty":
|
2017-04-11 23:50:47 +03:00
|
|
|
return node.computed;
|
|
|
|
// flow
|
|
|
|
case "MethodDefinition":
|
2017-04-26 19:25:58 +03:00
|
|
|
// typescript
|
|
|
|
case "TSAbstractMethodDefinition":
|
2017-04-11 23:50:47 +03:00
|
|
|
// babylon
|
|
|
|
case "ClassMethod": {
|
2017-04-12 20:16:11 +03:00
|
|
|
const isAsync = node.value ? node.value.async : node.async;
|
|
|
|
const isGenerator = node.value ? node.value.generator : node.generator;
|
|
|
|
if (
|
|
|
|
isAsync || node.static || node.kind === "get" || node.kind === "set"
|
|
|
|
) {
|
2017-04-11 23:50:47 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (node.computed || isGenerator) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 04:06:18 +03:00
|
|
|
// This recurses the return argument, looking for the first token
|
|
|
|
// (the leftmost leaf node) and, if it (or its parents) has any
|
|
|
|
// leadingComments, returns true (so it can be wrapped in parens).
|
|
|
|
function returnArgumentHasLeadingComment(options, argument) {
|
|
|
|
if (hasLeadingOwnLineComment(options.originalText, argument)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-11 23:50:47 +03:00
|
|
|
if (hasNakedLeftSide(argument)) {
|
2017-03-09 04:06:18 +03:00
|
|
|
let leftMost = argument;
|
|
|
|
let newLeftMost;
|
2017-04-12 20:16:11 +03:00
|
|
|
while ((newLeftMost = getLeftSide(leftMost))) {
|
2017-03-09 04:06:18 +03:00
|
|
|
leftMost = newLeftMost;
|
|
|
|
|
|
|
|
if (hasLeadingOwnLineComment(options.originalText, leftMost)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-11 21:37:46 +03:00
|
|
|
function isMemberExpressionChain(node) {
|
|
|
|
if (node.type !== "MemberExpression") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (node.object.type === "Identifier") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return isMemberExpressionChain(node.object);
|
|
|
|
}
|
|
|
|
|
2017-02-05 05:23:37 +03:00
|
|
|
// Hack to differentiate between the following two which have the same ast
|
|
|
|
// type T = { method: () => void };
|
|
|
|
// type T = { method(): void };
|
|
|
|
function isObjectTypePropertyAFunction(node) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
node.type === "ObjectTypeProperty" &&
|
2017-02-05 05:23:37 +03:00
|
|
|
node.value.type === "FunctionTypeAnnotation" &&
|
|
|
|
!node.static &&
|
2017-04-12 20:16:11 +03:00
|
|
|
util.locStart(node.key) !== util.locStart(node.value)
|
|
|
|
);
|
2017-02-05 05:23:37 +03:00
|
|
|
}
|
|
|
|
|
2017-03-16 20:32:59 +03:00
|
|
|
// Hack to differentiate between the following two which have the same ast
|
|
|
|
// declare function f(a): void;
|
|
|
|
// var f: (a) => void;
|
|
|
|
function isTypeAnnotationAFunction(node) {
|
2017-04-12 20:16:11 +03:00
|
|
|
return (
|
|
|
|
node.type === "TypeAnnotation" &&
|
2017-03-16 20:32:59 +03:00
|
|
|
node.typeAnnotation.type === "FunctionTypeAnnotation" &&
|
|
|
|
!node.static &&
|
|
|
|
util.locStart(node) !== util.locStart(node.typeAnnotation)
|
2017-04-12 20:16:11 +03:00
|
|
|
);
|
2017-03-16 20:32:59 +03:00
|
|
|
}
|
|
|
|
|
2017-04-27 19:37:42 +03:00
|
|
|
function isNodeStartingWithDeclare(node, options) {
|
|
|
|
if (!(options.parser === "flow" || options.parser === "typescript")) {
|
2017-02-13 20:17:20 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-04-27 19:37:42 +03:00
|
|
|
return (
|
|
|
|
options.originalText.slice(0, util.locStart(node)).match(/declare\s*$/) ||
|
|
|
|
options.originalText
|
|
|
|
.slice(node.range[0], node.range[1])
|
|
|
|
.startsWith("declare ")
|
|
|
|
);
|
2017-02-13 20:17:20 +03:00
|
|
|
}
|
|
|
|
|
2017-05-02 05:12:53 +03:00
|
|
|
function shouldHugArguments(fun) {
|
|
|
|
return (
|
|
|
|
fun &&
|
|
|
|
fun.params &&
|
|
|
|
fun.params.length === 1 &&
|
|
|
|
!fun.params[0].comments &&
|
|
|
|
(fun.params[0].type === "ObjectPattern" ||
|
|
|
|
(fun.params[0].type === "Identifier" &&
|
|
|
|
fun.params[0].typeAnnotation &&
|
|
|
|
fun.params[0].typeAnnotation.type === "TypeAnnotation" &&
|
|
|
|
fun.params[0].typeAnnotation.typeAnnotation.type === "ObjectTypeAnnotation") ||
|
|
|
|
fun.params[0].type === "FunctionTypeParam" &&
|
|
|
|
fun.params[0].typeAnnotation.type === "ObjectTypeAnnotation") &&
|
|
|
|
!fun.rest
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-05-04 00:35:58 +03:00
|
|
|
function templateLiteralHasNewLines(template) {
|
|
|
|
return template.quasis.some(quasi => quasi.value.raw.includes('\n'));
|
|
|
|
}
|
|
|
|
|
|
|
|
function isTemplateOnItsOwnLine(n, text) {
|
|
|
|
return (
|
|
|
|
(n.type === "TemplateLiteral" && templateLiteralHasNewLines(n) ||
|
|
|
|
n.type === "TaggedTemplateExpression" && templateLiteralHasNewLines(n.quasi)) &&
|
|
|
|
!util.hasNewline(
|
|
|
|
text,
|
|
|
|
util.locStart(n),
|
|
|
|
{backwards: true}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-03-15 19:35:22 +03:00
|
|
|
function printArrayItems(path, options, printPath, print) {
|
|
|
|
const printedElements = [];
|
|
|
|
let separatorParts = [];
|
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
path.each(function(childPath) {
|
|
|
|
printedElements.push(concat(separatorParts));
|
|
|
|
printedElements.push(group(print(childPath)));
|
2017-03-15 19:35:22 +03:00
|
|
|
|
2017-04-12 20:16:11 +03:00
|
|
|
separatorParts = [",", line];
|
|
|
|
if (
|
|
|
|
childPath.getValue() &&
|
|
|
|
util.isNextLineEmpty(options.originalText, childPath.getValue())
|
|
|
|
) {
|
|
|
|
separatorParts.push(softline);
|
|
|
|
}
|
|
|
|
}, printPath);
|
2017-03-15 19:35:22 +03:00
|
|
|
|
|
|
|
return concat(printedElements);
|
|
|
|
}
|
|
|
|
|
2017-05-02 00:41:18 +03:00
|
|
|
function hasDanglingComments(node) {
|
|
|
|
return node.comments &&
|
|
|
|
node.comments.some(comment => !comment.leading && !comment.trailing);
|
|
|
|
}
|
|
|
|
|
2017-05-06 07:44:42 +03:00
|
|
|
function hasBlockComments(node) {
|
|
|
|
return node.comments &&
|
|
|
|
node.comments.some(comment =>
|
|
|
|
comment.type === "Block" || comment.type === "CommentBlock"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-04-18 18:40:08 +03:00
|
|
|
function removeLines(doc) {
|
|
|
|
// Force this doc into flat mode by statically converting all
|
|
|
|
// lines into spaces (or soft lines into nothing). Hard lines
|
|
|
|
// should still output because there's too great of a chance
|
|
|
|
// of breaking existing assumptions otherwise.
|
|
|
|
return docUtils.mapDoc(doc, d => {
|
|
|
|
if (d.type === "line" && !d.hard) {
|
|
|
|
return d.soft ? "" : " ";
|
|
|
|
} else if (d.type === "if-break") {
|
|
|
|
return d.flatContents || "";
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-01-19 23:43:10 +03:00
|
|
|
function printAstToDoc(ast, options) {
|
2017-04-11 18:50:49 +03:00
|
|
|
function printGenerically(path, args) {
|
2017-01-19 23:43:10 +03:00
|
|
|
return comments.printComments(
|
|
|
|
path,
|
2017-04-11 18:50:49 +03:00
|
|
|
p => genericPrint(p, options, printGenerically, args),
|
2017-04-14 04:33:46 +03:00
|
|
|
options,
|
|
|
|
args && args.needsSemi
|
2017-01-19 23:43:10 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-01-24 02:47:11 +03:00
|
|
|
const doc = printGenerically(FastPath.from(ast));
|
|
|
|
docUtils.propagateBreaks(doc);
|
|
|
|
return doc;
|
2017-01-19 23:43:10 +03:00
|
|
|
}
|
|
|
|
|
2017-01-20 21:12:37 +03:00
|
|
|
module.exports = { printAstToDoc };
|