BVB Source Codes

prettier Show printer.js Source code

Return Download prettier: download printer.js Source code - Download prettier Source code - Type:.js
  1. "use strict";
  2.  
  3. const assert = require("assert");
  4. const comments = require("./comments");
  5. const FastPath = require("./fast-path");
  6. const util = require("./util");
  7. const isIdentifierName = require("esutils").keyword.isIdentifierNameES6;
  8.  
  9. const docBuilders = require("./doc-builders");
  10. const concat = docBuilders.concat;
  11. const join = docBuilders.join;
  12. const line = docBuilders.line;
  13. const hardline = docBuilders.hardline;
  14. const softline = docBuilders.softline;
  15. const literalline = docBuilders.literalline;
  16. const group = docBuilders.group;
  17. const indent = docBuilders.indent;
  18. const align = docBuilders.align;
  19. const conditionalGroup = docBuilders.conditionalGroup;
  20. const fill = docBuilders.fill;
  21. const ifBreak = docBuilders.ifBreak;
  22. const breakParent = docBuilders.breakParent;
  23. const lineSuffixBoundary = docBuilders.lineSuffixBoundary;
  24. const addAlignmentToDoc = docBuilders.addAlignmentToDoc;
  25.  
  26. const docUtils = require("./doc-utils");
  27. const willBreak = docUtils.willBreak;
  28. const isLineNext = docUtils.isLineNext;
  29. const isEmpty = docUtils.isEmpty;
  30.  
  31. function shouldPrintComma(options, level) {
  32.   level = level || "es5";
  33.  
  34.   switch (options.trailingComma) {
  35.     case "all":
  36.       if (level === "all") {
  37.         return true;
  38.       }
  39.     // fallthrough
  40.     case "es5":
  41.       if (level === "es5") {
  42.         return true;
  43.       }
  44.     // fallthrough
  45.     case "none":
  46.     default:
  47.       return false;
  48.   }
  49. }
  50.  
  51. function genericPrint(path, options, printPath, args) {
  52.   assert.ok(path instanceof FastPath);
  53.  
  54.   const node = path.getValue();
  55.  
  56.   // Escape hatch
  57.   if (
  58.     node &&
  59.     node.comments &&
  60.     node.comments.length > 0 &&
  61.     node.comments.some(comment => comment.value.trim() === "prettier-ignore")
  62.   ) {
  63.     return options.originalText.slice(util.locStart(node), util.locEnd(node));
  64.   }
  65.  
  66.   const parts = [];
  67.   let needsParens = false;
  68.   const linesWithoutParens = genericPrintNoParens(
  69.     path,
  70.     options,
  71.     printPath,
  72.     args
  73.   );
  74.  
  75.   if (!node || isEmpty(linesWithoutParens)) {
  76.     return linesWithoutParens;
  77.   }
  78.  
  79.   if (
  80.     node.decorators &&
  81.     node.decorators.length > 0 &&
  82.     // If the parent node is an export declaration, it will be
  83.     // responsible for printing node.decorators.
  84.     !util.getParentExportDeclaration(path)
  85.   ) {
  86.     let separator = hardline;
  87.     path.each(decoratorPath => {
  88.       let prefix = "@";
  89.       let decorator = decoratorPath.getValue();
  90.       if (decorator.expression) {
  91.         decorator = decorator.expression;
  92.         prefix = "";
  93.       }
  94.  
  95.       // #1817
  96.       if (
  97.         node.decorators.length === 1 &&
  98.         node.type !== "ClassDeclaration" &&
  99.         node.type !== "MethodDefinition" &&
  100.         node.type !== "ClassMethod" &&
  101.         (decorator.type === "Identifier" ||
  102.           decorator.type === "MemberExpression" ||
  103.           (decorator.type === "CallExpression" &&
  104.             (decorator.arguments.length === 0 ||
  105.               (decorator.arguments.length === 1 &&
  106.                 (isStringLiteral(decorator.arguments[0]) ||
  107.                   decorator.arguments[0].type === "Identifier" ||
  108.                   decorator.arguments[0].type === "MemberExpression")))))
  109.       ) {
  110.         separator = " ";
  111.       }
  112.  
  113.       parts.push(prefix, printPath(decoratorPath), separator);
  114.     }, "decorators");
  115.   } else if (
  116.     util.isExportDeclaration(node) &&
  117.     node.declaration &&
  118.     node.declaration.decorators
  119.   ) {
  120.     // Export declarations are responsible for printing any decorators
  121.     // that logically apply to node.declaration.
  122.     path.each(
  123.       decoratorPath => {
  124.         const decorator = decoratorPath.getValue();
  125.         const prefix = decorator.type === "Decorator" ||
  126.           decorator.type === "TSDecorator"
  127.           ? ""
  128.           : "@";
  129.         parts.push(prefix, printPath(decoratorPath), line);
  130.       },
  131.       "declaration",
  132.       "decorators"
  133.     );
  134.   } else {
  135.     // Nodes with decorators can't have parentheses, so we can avoid
  136.     // computing path.needsParens() except in this case.
  137.     needsParens = path.needsParens();
  138.   }
  139.  
  140.   if (node.type) {
  141.     // HACK: ASI prevention in no-semi mode relies on knowledge of whether
  142.     // or not a paren has been inserted (see `exprNeedsASIProtection()`).
  143.     // For now, we're just passing that information by mutating the AST here,
  144.     // but it would be nice to find a cleaner way to do this.
  145.     node.needsParens = needsParens;
  146.   }
  147.  
  148.   if (needsParens) {
  149.     parts.unshift("(");
  150.   }
  151.  
  152.   parts.push(linesWithoutParens);
  153.  
  154.   if (needsParens) {
  155.     parts.push(")");
  156.   }
  157.  
  158.   return concat(parts);
  159. }
  160.  
  161. function genericPrintNoParens(path, options, print, args) {
  162.   const n = path.getValue();
  163.   const semi = options.semi ? ";" : "";
  164.  
  165.   if (!n) {
  166.     return "";
  167.   }
  168.  
  169.   if (typeof n === "string") {
  170.     return n;
  171.   }
  172.  
  173.   let parts = [];
  174.   switch (n.type) {
  175.     case "File":
  176.       return path.call(print, "program");
  177.     case "Program":
  178.       // Babel 6
  179.       if (n.directives) {
  180.         path.each(childPath => {
  181.           parts.push(print(childPath), semi, hardline);
  182.           if (
  183.             util.isNextLineEmpty(options.originalText, childPath.getValue())
  184.           ) {
  185.             parts.push(hardline);
  186.           }
  187.         }, "directives");
  188.       }
  189.  
  190.       parts.push(
  191.         path.call(bodyPath => {
  192.           return printStatementSequence(bodyPath, options, print);
  193.         }, "body")
  194.       );
  195.  
  196.       parts.push(
  197.         comments.printDanglingComments(path, options, /* sameIndent */ true)
  198.       );
  199.  
  200.       // Only force a trailing newline if there were any contents.
  201.       if (n.body.length || n.comments) {
  202.         parts.push(hardline);
  203.       }
  204.  
  205.       return concat(parts);
  206.     // Babel extension.
  207.     case "Noop":
  208.     case "EmptyStatement":
  209.       return "";
  210.     case "ExpressionStatement":
  211.       // Detect Flow-parsed directives
  212.       if (n.directive) {
  213.         return concat([nodeStr(n.expression, options, true), semi]);
  214.       }
  215.       return concat([path.call(print, "expression"), semi]); // Babel extension.
  216.     case "ParenthesizedExpression":
  217.       return concat(["(", path.call(print, "expression"), ")"]);
  218.     case "AssignmentExpression":
  219.       return printAssignment(
  220.         n.left,
  221.         path.call(print, "left"),
  222.         concat([" ", n.operator]),
  223.         n.right,
  224.         path.call(print, "right"),
  225.         options
  226.       );
  227.     case "BinaryExpression":
  228.     case "LogicalExpression": {
  229.       const parent = path.getParentNode();
  230.       const parentParent = path.getParentNode(1);
  231.       const isInsideParenthesis =
  232.         n !== parent.body &&
  233.         (parent.type === "IfStatement" ||
  234.           parent.type === "WhileStatement" ||
  235.           parent.type === "DoStatement");
  236.  
  237.       const parts = printBinaryishExpressions(
  238.         path,
  239.         print,
  240.         options,
  241.         /* isNested */ false,
  242.         isInsideParenthesis
  243.       );
  244.  
  245.       //   if (
  246.       //     this.hasPlugin("dynamicImports") && this.lookahead().type === tt.parenLeft
  247.       //   ) {
  248.       //
  249.       // looks super weird, we want to break the children if the parent breaks
  250.       //
  251.       //   if (
  252.       //     this.hasPlugin("dynamicImports") &&
  253.       //     this.lookahead().type === tt.parenLeft
  254.       //   ) {
  255.       if (isInsideParenthesis) {
  256.         return concat(parts);
  257.       }
  258.  
  259.       if (parent.type === "UnaryExpression") {
  260.         return group(
  261.           concat([indent(concat([softline, concat(parts)])), softline])
  262.         );
  263.       }
  264.  
  265.       // Avoid indenting sub-expressions in assignment/return/etc statements.
  266.       if (
  267.         parent.type === "AssignmentExpression" ||
  268.         parent.type === "VariableDeclarator" ||
  269.         shouldInlineLogicalExpression(n) ||
  270.         parent.type === "ReturnStatement" ||
  271.         (parent.type === "JSXExpressionContainer" &&
  272.           parentParent.type === "JSXAttribute") ||
  273.         (n === parent.body && parent.type === "ArrowFunctionExpression") ||
  274.         (n !== parent.body && parent.type === "ForStatement")
  275.       ) {
  276.         return group(concat(parts));
  277.       }
  278.  
  279.       const rest = concat(parts.slice(1));
  280.  
  281.       return group(
  282.         concat([
  283.           // Don't include the initial expression in the indentation
  284.           // level. The first item is guaranteed to be the first
  285.           // left-most expression.
  286.           parts.length > 0 ? parts[0] : "",
  287.           indent(rest)
  288.         ])
  289.       );
  290.     }
  291.     case "AssignmentPattern":
  292.       return concat([
  293.         path.call(print, "left"),
  294.         " = ",
  295.         path.call(print, "right")
  296.       ]);
  297.     case "TSTypeAssertionExpression":
  298.       return concat([
  299.         "<",
  300.         path.call(print, "typeAnnotation"),
  301.         ">",
  302.         path.call(print, "expression")
  303.       ]);
  304.     case "MemberExpression": {
  305.       const parent = path.getParentNode();
  306.       let firstNonMemberParent;
  307.       let i = 0;
  308.       do {
  309.         firstNonMemberParent = path.getParentNode(i);
  310.         i++;
  311.       } while (
  312.         firstNonMemberParent && firstNonMemberParent.type === "MemberExpression"
  313.       );
  314.  
  315.       const shouldInline =
  316.         (firstNonMemberParent &&
  317.           ((firstNonMemberParent.type === "VariableDeclarator" &&
  318.             firstNonMemberParent.id.type !== "Identifier") ||
  319.             (firstNonMemberParent.type === "AssignmentExpression" &&
  320.               firstNonMemberParent.left.type !== "Identifier"))) ||
  321.         n.computed ||
  322.         (n.object.type === "Identifier" &&
  323.           n.property.type === "Identifier" &&
  324.           parent.type !== "MemberExpression");
  325.  
  326.       return concat([
  327.         path.call(print, "object"),
  328.         shouldInline
  329.           ? printMemberLookup(path, options, print)
  330.           : group(
  331.               indent(
  332.                 concat([softline, printMemberLookup(path, options, print)])
  333.               )
  334.             )
  335.       ]);
  336.     }
  337.     case "MetaProperty":
  338.       return concat([
  339.         path.call(print, "meta"),
  340.         ".",
  341.         path.call(print, "property")
  342.       ]);
  343.     case "BindExpression":
  344.       if (n.object) {
  345.         parts.push(path.call(print, "object"));
  346.       }
  347.  
  348.       parts.push("::", path.call(print, "callee"));
  349.  
  350.       return concat(parts);
  351.     case "Path":
  352.       return join(".", n.body);
  353.     case "Identifier": {
  354.       const parentNode = path.getParentNode();
  355.       const isFunctionDeclarationIdentifier =
  356.         parentNode.type === "DeclareFunction" && parentNode.id === n;
  357.  
  358.       return concat([
  359.         n.name,
  360.         n.optional ? "?" : "",
  361.         n.typeAnnotation && !isFunctionDeclarationIdentifier ? ": " : "",
  362.         path.call(print, "typeAnnotation")
  363.       ]);
  364.     }
  365.     case "SpreadElement":
  366.     case "SpreadElementPattern":
  367.     case "RestProperty":
  368.     case "ExperimentalRestProperty":
  369.     case "ExperimentalSpreadProperty":
  370.     case "SpreadProperty":
  371.     case "SpreadPropertyPattern":
  372.     case "RestElement":
  373.     case "ObjectTypeSpreadProperty":
  374.       return concat([
  375.         "...",
  376.         path.call(print, "argument"),
  377.         n.typeAnnotation ? ": " : "",
  378.         path.call(print, "typeAnnotation")
  379.       ]);
  380.     case "FunctionDeclaration":
  381.     case "FunctionExpression":
  382.     case "TSNamespaceFunctionDeclaration":
  383.       if (isNodeStartingWithDeclare(n, options)) {
  384.         parts.push("declare ");
  385.       }
  386.       parts.push(printFunctionDeclaration(path, print, options));
  387.       if (n.type === "TSNamespaceFunctionDeclaration" && !n.body) {
  388.         parts.push(semi);
  389.       }
  390.       return concat(parts);
  391.     case "ArrowFunctionExpression": {
  392.       if (n.async) {
  393.         parts.push("async ");
  394.       }
  395.  
  396.       parts.push(printFunctionTypeParameters(path, options, print));
  397.  
  398.       if (canPrintParamsWithoutParens(n)) {
  399.         parts.push(path.call(print, "params", 0));
  400.       } else {
  401.         parts.push(
  402.           group(
  403.             concat([
  404.               printFunctionParams(
  405.                 path,
  406.                 print,
  407.                 options,
  408.                 args && (args.expandLastArg || args.expandFirstArg)
  409.               ),
  410.               printReturnType(path, print)
  411.             ])
  412.           )
  413.         );
  414.       }
  415.  
  416.       parts.push(" =>");
  417.  
  418.       const body = path.call(bodyPath => print(bodyPath, args), "body");
  419.       const collapsed = concat([concat(parts), " ", body]);
  420.  
  421.       // We want to always keep these types of nodes on the same line
  422.       // as the arrow.
  423.       if (
  424.         !hasLeadingOwnLineComment(options.originalText, n.body) &&
  425.         (n.body.type === "ArrayExpression" ||
  426.           n.body.type === "ObjectExpression" ||
  427.           n.body.type === "BlockStatement" ||
  428.           n.body.type === "SequenceExpression" ||
  429.           isTemplateOnItsOwnLine(n.body, options.originalText) ||
  430.           n.body.type === "ArrowFunctionExpression")
  431.       ) {
  432.         return group(collapsed);
  433.       }
  434.  
  435.       // if the arrow function is expanded as last argument, we are adding a
  436.       // level of indentation and need to add a softline to align the closing )
  437.       // with the opening (.
  438.       const shouldAddSoftLine = args && args.expandLastArg;
  439.  
  440.       // In order to avoid confusion between
  441.       // a => a ? a : a
  442.       // a <= a ? a : a
  443.       const shouldAddParens =
  444.         n.body.type === "ConditionalExpression" &&
  445.         !util.startsWithNoLookaheadToken(
  446.           n.body,
  447.           /* forbidFunctionAndClass */ false
  448.         );
  449.  
  450.       return group(
  451.         concat([
  452.           concat(parts),
  453.           group(
  454.             concat([
  455.               indent(
  456.                 concat([
  457.                   line,
  458.                   shouldAddParens ? ifBreak("", "(") : "",
  459.                   body,
  460.                   shouldAddParens ? ifBreak("", ")") : ""
  461.                 ])
  462.               ),
  463.               shouldAddSoftLine
  464.                 ? concat([
  465.                     ifBreak(shouldPrintComma(options, "all") ? "," : ""),
  466.                     softline
  467.                   ])
  468.                 : ""
  469.             ])
  470.           )
  471.         ])
  472.       );
  473.     }
  474.     case "MethodDefinition":
  475.     case "TSAbstractMethodDefinition":
  476.       if (n.accessibility) {
  477.         parts.push(n.accessibility + " ");
  478.       }
  479.       if (n.static) {
  480.         parts.push("static ");
  481.       }
  482.       if (n.type === "TSAbstractMethodDefinition") {
  483.         parts.push("abstract ");
  484.       }
  485.  
  486.       parts.push(printMethod(path, options, print));
  487.  
  488.       return concat(parts);
  489.     case "YieldExpression":
  490.       parts.push("yield");
  491.  
  492.       if (n.delegate) {
  493.         parts.push("*");
  494.       }
  495.       if (n.argument) {
  496.         parts.push(" ", path.call(print, "argument"));
  497.       }
  498.  
  499.       return concat(parts);
  500.     case "AwaitExpression":
  501.       parts.push("await");
  502.  
  503.       if (n.all) {
  504.         parts.push("*");
  505.       }
  506.       if (n.argument) {
  507.         parts.push(" ", path.call(print, "argument"));
  508.       }
  509.  
  510.       return concat(parts);
  511.     case "ModuleDeclaration":
  512.       parts.push("module", path.call(print, "id"));
  513.  
  514.       if (n.source) {
  515.         assert.ok(!n.body);
  516.  
  517.         parts.push("from", path.call(print, "source"));
  518.       } else {
  519.         parts.push(path.call(print, "body"));
  520.       }
  521.  
  522.       return join(" ", parts);
  523.     case "ImportSpecifier":
  524.       if (n.imported) {
  525.         if (n.importKind) {
  526.           parts.push(path.call(print, "importKind"), " ");
  527.         }
  528.  
  529.         parts.push(path.call(print, "imported"));
  530.  
  531.         if (n.local && n.local.name !== n.imported.name) {
  532.           parts.push(" as ", path.call(print, "local"));
  533.         }
  534.       } else if (n.id) {
  535.         parts.push(path.call(print, "id"));
  536.  
  537.         if (n.name) {
  538.           parts.push(" as ", path.call(print, "name"));
  539.         }
  540.       }
  541.  
  542.       return concat(parts);
  543.     case "ExportSpecifier":
  544.       if (n.local) {
  545.         parts.push(path.call(print, "local"));
  546.  
  547.         if (n.exported && n.exported.name !== n.local.name) {
  548.           parts.push(" as ", path.call(print, "exported"));
  549.         }
  550.       } else if (n.id) {
  551.         parts.push(path.call(print, "id"));
  552.  
  553.         if (n.name) {
  554.           parts.push(" as ", path.call(print, "name"));
  555.         }
  556.       }
  557.  
  558.       return concat(parts);
  559.     case "ExportBatchSpecifier":
  560.       return "*";
  561.     case "ImportNamespaceSpecifier":
  562.       parts.push("* as ");
  563.  
  564.       if (n.local) {
  565.         parts.push(path.call(print, "local"));
  566.       } else if (n.id) {
  567.         parts.push(path.call(print, "id"));
  568.       }
  569.  
  570.       return concat(parts);
  571.     case "ImportDefaultSpecifier":
  572.       if (n.local) {
  573.         return path.call(print, "local");
  574.       }
  575.  
  576.       return path.call(print, "id");
  577.     case "ExportDeclaration":
  578.     case "ExportDefaultDeclaration":
  579.     case "ExportNamedDeclaration":
  580.       return printExportDeclaration(path, options, print);
  581.     case "ExportAllDeclaration":
  582.       parts.push("export *");
  583.  
  584.       if (n.exported) {
  585.         parts.push(" as ", path.call(print, "exported"));
  586.       }
  587.  
  588.       parts.push(" from ", path.call(print, "source"), semi);
  589.  
  590.       return concat(parts);
  591.     case "ExportNamespaceSpecifier":
  592.     case "ExportDefaultSpecifier":
  593.       return path.call(print, "exported");
  594.     case "ImportDeclaration": {
  595.       parts.push("import ");
  596.  
  597.       if (n.importKind && n.importKind !== "value") {
  598.         parts.push(n.importKind + " ");
  599.       }
  600.  
  601.       const standalones = [];
  602.       const grouped = [];
  603.       if (n.specifiers && n.specifiers.length > 0) {
  604.         path.each(specifierPath => {
  605.           const value = specifierPath.getValue();
  606.           if (
  607.             value.type === "ImportDefaultSpecifier" ||
  608.             value.type === "ImportNamespaceSpecifier"
  609.           ) {
  610.             standalones.push(print(specifierPath));
  611.           } else {
  612.             grouped.push(print(specifierPath));
  613.           }
  614.         }, "specifiers");
  615.  
  616.         if (standalones.length > 0) {
  617.           parts.push(join(", ", standalones));
  618.         }
  619.  
  620.         if (standalones.length > 0 && grouped.length > 0) {
  621.           parts.push(", ");
  622.         }
  623.  
  624.         if (
  625.           grouped.length === 1 &&
  626.           n.specifiers &&
  627.           !n.specifiers.some(node => node.comments)
  628.         ) {
  629.           parts.push(
  630.             concat([
  631.               "{",
  632.               options.bracketSpacing ? " " : "",
  633.               concat(grouped),
  634.               options.bracketSpacing ? " " : "",
  635.               "}"
  636.             ])
  637.           );
  638.         } else if (grouped.length >= 1) {
  639.           parts.push(
  640.             group(
  641.               concat([
  642.                 "{",
  643.                 indent(
  644.                   concat([
  645.                     options.bracketSpacing ? line : softline,
  646.                     join(concat([",", line]), grouped)
  647.                   ])
  648.                 ),
  649.                 ifBreak(shouldPrintComma(options) ? "," : ""),
  650.                 options.bracketSpacing ? line : softline,
  651.                 "}"
  652.               ])
  653.             )
  654.           );
  655.         }
  656.  
  657.         parts.push(" ", "from ");
  658.       } else if (n.importKind && n.importKind === "type") {
  659.         parts.push("{} from ");
  660.       }
  661.  
  662.       parts.push(path.call(print, "source"), semi);
  663.  
  664.       return concat(parts);
  665.     }
  666.  
  667.     case "Import":
  668.       return "import";
  669.     case "BlockStatement": {
  670.       const naked = path.call(bodyPath => {
  671.         return printStatementSequence(bodyPath, options, print);
  672.       }, "body");
  673.  
  674.       const hasContent = n.body.find(node => node.type !== "EmptyStatement");
  675.       const hasDirectives = n.directives && n.directives.length > 0;
  676.  
  677.       const parent = path.getParentNode();
  678.       const parentParent = path.getParentNode(1);
  679.       if (
  680.         !hasContent &&
  681.         !hasDirectives &&
  682.         !n.comments &&
  683.         (parent.type === "ArrowFunctionExpression" ||
  684.           parent.type === "FunctionExpression" ||
  685.           parent.type === "FunctionDeclaration" ||
  686.           parent.type === "ObjectMethod" ||
  687.           parent.type === "ClassMethod" ||
  688.           parent.type === "ForStatement" ||
  689.           parent.type === "WhileStatement" ||
  690.           parent.type === "DoWhileStatement" ||
  691.           (parent.type === "CatchClause" && !parentParent.finalizer))
  692.       ) {
  693.         return "{}";
  694.       }
  695.  
  696.       parts.push("{");
  697.  
  698.       // Babel 6
  699.       if (hasDirectives) {
  700.         path.each(childPath => {
  701.           parts.push(indent(concat([hardline, print(childPath), semi])));
  702.         }, "directives");
  703.       }
  704.  
  705.       if (hasContent) {
  706.         parts.push(indent(concat([hardline, naked])));
  707.       }
  708.  
  709.       parts.push(comments.printDanglingComments(path, options));
  710.       parts.push(hardline, "}");
  711.  
  712.       return concat(parts);
  713.     }
  714.     case "ReturnStatement":
  715.       parts.push("return");
  716.  
  717.       if (n.argument) {
  718.         if (returnArgumentHasLeadingComment(options, n.argument)) {
  719.           parts.push(
  720.             concat([
  721.               " (",
  722.               indent(concat([softline, path.call(print, "argument")])),
  723.               line,
  724.               ")"
  725.             ])
  726.           );
  727.         } else if (
  728.           n.argument.type === "LogicalExpression" ||
  729.           n.argument.type === "BinaryExpression"
  730.         ) {
  731.           parts.push(
  732.             group(
  733.               concat([
  734.                 ifBreak(" (", " "),
  735.                 indent(concat([softline, path.call(print, "argument")])),
  736.                 softline,
  737.                 ifBreak(")")
  738.               ])
  739.             )
  740.           );
  741.         } else {
  742.           parts.push(" ", path.call(print, "argument"));
  743.         }
  744.       }
  745.  
  746.       if (hasDanglingComments(n)) {
  747.         parts.push(
  748.           " ",
  749.           comments.printDanglingComments(path, options, /* sameIndent */ true)
  750.         );
  751.       }
  752.  
  753.       parts.push(semi);
  754.  
  755.       return concat(parts);
  756.     case "CallExpression": {
  757.       if (
  758.         // We want to keep require calls as a unit
  759.         (n.callee.type === "Identifier" && n.callee.name === "require") ||
  760.         // Template literals as single arguments
  761.         (n.arguments.length === 1 &&
  762.           isTemplateOnItsOwnLine(n.arguments[0], options.originalText)) ||
  763.         // Keep test declarations on a single line
  764.         // e.g. `it('long name', () => {`
  765.         (n.callee.type === "Identifier" &&
  766.           (n.callee.name === "it" ||
  767.             n.callee.name === "test" ||
  768.             n.callee.name === "describe") &&
  769.           n.arguments.length === 2 &&
  770.           (n.arguments[0].type === "StringLiteral" ||
  771.             n.arguments[0].type === "TemplateLiteral" ||
  772.             (n.arguments[0].type === "Literal" &&
  773.               typeof n.arguments[0].value === "string")) &&
  774.           (n.arguments[1].type === "FunctionExpression" ||
  775.             n.arguments[1].type === "ArrowFunctionExpression") &&
  776.           n.arguments[1].params.length <= 1)
  777.       ) {
  778.         return concat([
  779.           path.call(print, "callee"),
  780.           path.call(print, "typeParameters"),
  781.           concat(["(", join(", ", path.map(print, "arguments")), ")"])
  782.         ]);
  783.       }
  784.  
  785.       // We detect calls on member lookups and possibly print them in a
  786.       // special chain format. See `printMemberChain` for more info.
  787.       if (n.callee.type === "MemberExpression") {
  788.         return printMemberChain(path, options, print);
  789.       }
  790.  
  791.       return concat([
  792.         path.call(print, "callee"),
  793.         printFunctionTypeParameters(path, options, print),
  794.         printArgumentsList(path, options, print)
  795.       ]);
  796.     }
  797.     case "TSInterfaceDeclaration":
  798.       parts.push(
  799.         n.abstract ? "abstract " : "",
  800.         printTypeScriptModifiers(path, options, print),
  801.         "interface ",
  802.         path.call(print, "id"),
  803.         n.typeParameters ? path.call(print, "typeParameters") : "",
  804.         " "
  805.       );
  806.  
  807.       if (n.heritage.length) {
  808.         parts.push("extends ", join(", ", path.map(print, "heritage")), " ");
  809.       }
  810.  
  811.       parts.push(path.call(print, "body"));
  812.  
  813.       return concat(parts);
  814.     case "ObjectExpression":
  815.     case "ObjectPattern":
  816.     case "ObjectTypeAnnotation":
  817.     case "TSInterfaceBody":
  818.     case "TSTypeLiteral": {
  819.       const isTypeAnnotation = n.type === "ObjectTypeAnnotation";
  820.       const shouldBreak =
  821.         n.type !== "ObjectPattern" &&
  822.         util.hasNewlineInRange(
  823.           options.originalText,
  824.           util.locStart(n),
  825.           util.locEnd(n)
  826.         );
  827.       const separator = n.type === "TSInterfaceBody" ||
  828.         n.type === "TSTypeLiteral"
  829.         ? shouldBreak ? semi : ";"
  830.         : ",";
  831.       const fields = [];
  832.       const leftBrace = n.exact ? "{|" : "{";
  833.       const rightBrace = n.exact ? "|}" : "}";
  834.       const parent = path.getParentNode(0);
  835.  
  836.       let propertiesField;
  837.  
  838.       if (n.type === "TSTypeLiteral") {
  839.         propertiesField = "members";
  840.       } else if (n.type === "TSInterfaceBody") {
  841.         propertiesField = "body";
  842.       } else {
  843.         propertiesField = "properties";
  844.       }
  845.  
  846.       if (isTypeAnnotation) {
  847.         fields.push("indexers", "callProperties");
  848.       }
  849.       fields.push(propertiesField);
  850.  
  851.       // Unfortunately, things are grouped together in the ast can be
  852.       // interleaved in the source code. So we need to reorder them before
  853.       // printing them.
  854.       const propsAndLoc = [];
  855.       fields.forEach(field => {
  856.         path.each(childPath => {
  857.           const node = childPath.getValue();
  858.           propsAndLoc.push({
  859.             node: node,
  860.             printed: print(childPath),
  861.             loc: util.locStart(node)
  862.           });
  863.         }, field);
  864.       });
  865.  
  866.       let separatorParts = [];
  867.       const props = propsAndLoc.sort((a, b) => a.loc - b.loc).map(prop => {
  868.         const result = concat(separatorParts.concat(group(prop.printed)));
  869.         separatorParts = [separator, line];
  870.         if (util.isNextLineEmpty(options.originalText, prop.node)) {
  871.           separatorParts.push(hardline);
  872.         }
  873.         return result;
  874.       });
  875.  
  876.       const lastElem = util.getLast(n[propertiesField]);
  877.  
  878.       const canHaveTrailingSeparator = !(
  879.         lastElem &&
  880.         (lastElem.type === "RestProperty" || lastElem.type === "RestElement")
  881.       );
  882.  
  883.       let content;
  884.       if (props.length === 0 && !n.typeAnnotation) {
  885.         if (!hasDanglingComments(n)) {
  886.           return concat([leftBrace, rightBrace]);
  887.         }
  888.  
  889.         content = group(
  890.           concat([
  891.             leftBrace,
  892.             comments.printDanglingComments(path, options),
  893.             softline,
  894.             rightBrace
  895.           ])
  896.         );
  897.       } else {
  898.         content = concat([
  899.           leftBrace,
  900.           indent(
  901.             concat([options.bracketSpacing ? line : softline, concat(props)])
  902.           ),
  903.           ifBreak(
  904.             canHaveTrailingSeparator &&
  905.               (separator !== "," || shouldPrintComma(options))
  906.               ? separator
  907.               : ""
  908.           ),
  909.           concat([options.bracketSpacing ? line : softline, rightBrace]),
  910.           n.typeAnnotation ? ": " : "",
  911.           path.call(print, "typeAnnotation")
  912.         ]);
  913.       }
  914.  
  915.       // If we inline the object as first argument of the parent, we don't want
  916.       // to create another group so that the object breaks before the return
  917.       // type
  918.       const parentParentParent = path.getParentNode(2);
  919.       if (
  920.         (n.type === "ObjectPattern" &&
  921.           parent &&
  922.           shouldHugArguments(parent) &&
  923.           parent.params[0] === n) ||
  924.         (shouldHugType(n) &&
  925.           parentParentParent &&
  926.           shouldHugArguments(parentParentParent) &&
  927.           parentParentParent.params[0].typeAnnotation.typeAnnotation === n)
  928.       ) {
  929.         return content;
  930.       }
  931.  
  932.       return group(content, { shouldBreak });
  933.     }
  934.     case "PropertyPattern":
  935.       return concat([
  936.         path.call(print, "key"),
  937.         ": ",
  938.         path.call(print, "pattern")
  939.       ]);
  940.     // Babel 6
  941.     case "ObjectProperty": // Non-standard AST node type.
  942.     case "Property":
  943.       if (n.method || n.kind === "get" || n.kind === "set") {
  944.         return printMethod(path, options, print);
  945.       }
  946.  
  947.       if (n.shorthand) {
  948.         parts.push(path.call(print, "value"));
  949.       } else {
  950.         let printedLeft;
  951.         if (n.computed) {
  952.           printedLeft = concat(["[", path.call(print, "key"), "]"]);
  953.         } else {
  954.           printedLeft = printPropertyKey(path, options, print);
  955.         }
  956.         parts.push(
  957.           printAssignment(
  958.             n.key,
  959.             printedLeft,
  960.             ":",
  961.             n.value,
  962.             path.call(print, "value"),
  963.             options
  964.           )
  965.         );
  966.       }
  967.  
  968.       return concat(parts); // Babel 6
  969.     case "ClassMethod":
  970.       if (n.static) {
  971.         parts.push("static ");
  972.       }
  973.  
  974.       parts = parts.concat(printObjectMethod(path, options, print));
  975.  
  976.       return concat(parts); // Babel 6
  977.     case "ObjectMethod":
  978.       return printObjectMethod(path, options, print);
  979.     case "TSDecorator":
  980.     case "Decorator":
  981.       return concat(["@", path.call(print, "expression")]);
  982.     case "ArrayExpression":
  983.     case "ArrayPattern":
  984.       if (n.elements.length === 0) {
  985.         if (!hasDanglingComments(n)) {
  986.           parts.push("[]");
  987.         } else {
  988.           parts.push(
  989.             group(
  990.               concat([
  991.                 "[",
  992.                 comments.printDanglingComments(path, options),
  993.                 softline,
  994.                 "]"
  995.               ])
  996.             )
  997.           );
  998.         }
  999.       } else {
  1000.         const lastElem = util.getLast(n.elements);
  1001.         const canHaveTrailingComma = !(
  1002.           lastElem && lastElem.type === "RestElement"
  1003.         );
  1004.  
  1005.         // JavaScript allows you to have empty elements in an array which
  1006.         // changes its length based on the number of commas. The algorithm
  1007.         // is that if the last argument is null, we need to force insert
  1008.         // a comma to ensure JavaScript recognizes it.
  1009.         //   [,].length === 1
  1010.         //   [1,].length === 1
  1011.         //   [1,,].length === 2
  1012.         //
  1013.         // Note that util.getLast returns null if the array is empty, but
  1014.         // we already check for an empty array just above so we are safe
  1015.         const needsForcedTrailingComma =
  1016.           canHaveTrailingComma && lastElem === null;
  1017.  
  1018.         parts.push(
  1019.           group(
  1020.             concat([
  1021.               "[",
  1022.               indent(
  1023.                 concat([
  1024.                   softline,
  1025.                   printArrayItems(path, options, "elements", print)
  1026.                 ])
  1027.               ),
  1028.               needsForcedTrailingComma ? "," : "",
  1029.               ifBreak(
  1030.                 canHaveTrailingComma &&
  1031.                   !needsForcedTrailingComma &&
  1032.                   shouldPrintComma(options)
  1033.                   ? ","
  1034.                   : ""
  1035.               ),
  1036.               comments.printDanglingComments(
  1037.                 path,
  1038.                 options,
  1039.                 /* sameIndent */ true
  1040.               ),
  1041.               softline,
  1042.               "]"
  1043.             ])
  1044.           )
  1045.         );
  1046.       }
  1047.  
  1048.       if (n.typeAnnotation) {
  1049.         parts.push(": ", path.call(print, "typeAnnotation"));
  1050.       }
  1051.  
  1052.       return concat(parts);
  1053.     case "SequenceExpression": {
  1054.       const parent = path.getParentNode();
  1055.       const shouldInline =
  1056.         parent.type === "ReturnStatement" ||
  1057.         parent.type === "ForStatement" ||
  1058.         parent.type === "ExpressionStatement";
  1059.  
  1060.       if (shouldInline) {
  1061.         return join(", ", path.map(print, "expressions"));
  1062.       }
  1063.       return group(
  1064.         concat([
  1065.           indent(
  1066.             concat([
  1067.               softline,
  1068.               join(concat([",", line]), path.map(print, "expressions"))
  1069.             ])
  1070.           ),
  1071.           softline
  1072.         ])
  1073.       );
  1074.     }
  1075.     case "ThisExpression":
  1076.       return "this";
  1077.     case "Super":
  1078.       return "super";
  1079.     case "NullLiteral": // Babel 6 Literal split
  1080.       return "null";
  1081.     case "RegExpLiteral": // Babel 6 Literal split
  1082.       return printRegex(n);
  1083.     case "NumericLiteral": // Babel 6 Literal split
  1084.       return printNumber(n.extra.raw);
  1085.     case "BooleanLiteral": // Babel 6 Literal split
  1086.     case "StringLiteral": // Babel 6 Literal split
  1087.     case "Literal":
  1088.       if (n.regex) {
  1089.         return printRegex(n.regex);
  1090.       }
  1091.       if (typeof n.value === "number") {
  1092.         return printNumber(n.raw);
  1093.       }
  1094.       if (typeof n.value !== "string") {
  1095.         return "" + n.value;
  1096.       }
  1097.       return nodeStr(n, options); // Babel 6
  1098.     case "Directive":
  1099.       return path.call(print, "value"); // Babel 6
  1100.     case "DirectiveLiteral":
  1101.       return nodeStr(n, options);
  1102.     case "ModuleSpecifier":
  1103.       if (n.local) {
  1104.         throw new Error("The ESTree ModuleSpecifier type should be abstract");
  1105.       }
  1106.  
  1107.       // The Esprima ModuleSpecifier type is just a string-valued
  1108.       // Literal identifying the imported-from module.
  1109.       return nodeStr(n, options);
  1110.     case "UnaryExpression":
  1111.       parts.push(n.operator);
  1112.  
  1113.       if (/[a-z]$/.test(n.operator)) {
  1114.         parts.push(" ");
  1115.       }
  1116.  
  1117.       parts.push(path.call(print, "argument"));
  1118.  
  1119.       return concat(parts);
  1120.     case "UpdateExpression":
  1121.       parts.push(path.call(print, "argument"), n.operator);
  1122.  
  1123.       if (n.prefix) {
  1124.         parts.reverse();
  1125.       }
  1126.  
  1127.       return concat(parts);
  1128.     case "ConditionalExpression": {
  1129.       const parent = path.getParentNode();
  1130.       const printed = concat([
  1131.         line,
  1132.         "? ",
  1133.         n.consequent.type === "ConditionalExpression" ? ifBreak("", "(") : "",
  1134.         align(2, path.call(print, "consequent")),
  1135.         n.consequent.type === "ConditionalExpression" ? ifBreak("", ")") : "",
  1136.         line,
  1137.         ": ",
  1138.         align(2, path.call(print, "alternate"))
  1139.       ]);
  1140.  
  1141.       return group(
  1142.         concat([
  1143.           path.call(print, "test"),
  1144.           parent.type === "ConditionalExpression" ? printed : indent(printed)
  1145.         ])
  1146.       );
  1147.     }
  1148.     case "NewExpression":
  1149.       parts.push(
  1150.         "new ",
  1151.         path.call(print, "callee"),
  1152.         printFunctionTypeParameters(path, options, print)
  1153.       );
  1154.  
  1155.       if (n.arguments) {
  1156.         parts.push(printArgumentsList(path, options, print));
  1157.       }
  1158.  
  1159.       return concat(parts);
  1160.     case "VariableDeclaration": {
  1161.       const printed = path.map(childPath => {
  1162.         return print(childPath);
  1163.       }, "declarations");
  1164.  
  1165.       // We generally want to terminate all variable declarations with a
  1166.       // semicolon, except when they in the () part of for loops.
  1167.       const parentNode = path.getParentNode();
  1168.  
  1169.       const isParentForLoop =
  1170.         parentNode.type === "ForStatement" ||
  1171.         parentNode.type === "ForInStatement" ||
  1172.         parentNode.type === "ForOfStatement" ||
  1173.         parentNode.type === "ForAwaitStatement";
  1174.  
  1175.       const hasValue = n.declarations.some(decl => decl.init);
  1176.  
  1177.       parts = [
  1178.         isNodeStartingWithDeclare(n, options) ? "declare " : "",
  1179.         n.kind,
  1180.         printed.length ? concat([" ", printed[0]]) : "",
  1181.         indent(
  1182.           concat(
  1183.             printed
  1184.               .slice(1)
  1185.               .map(p =>
  1186.                 concat([",", hasValue && !isParentForLoop ? hardline : line, p])
  1187.               )
  1188.           )
  1189.         )
  1190.       ];
  1191.  
  1192.       if (!(isParentForLoop && parentNode.body !== n)) {
  1193.         parts.push(semi);
  1194.       }
  1195.  
  1196.       return group(concat(parts));
  1197.     }
  1198.     case "VariableDeclarator":
  1199.       return printAssignment(
  1200.         n.id,
  1201.         concat([path.call(print, "id"), path.call(print, "typeParameters")]),
  1202.         " =",
  1203.         n.init,
  1204.         n.init && path.call(print, "init"),
  1205.         options
  1206.       );
  1207.     case "WithStatement":
  1208.       return group(
  1209.         concat([
  1210.           "with (",
  1211.           path.call(print, "object"),
  1212.           ")",
  1213.           adjustClause(n.body, path.call(print, "body"))
  1214.         ])
  1215.       );
  1216.     case "IfStatement": {
  1217.       const con = adjustClause(n.consequent, path.call(print, "consequent"));
  1218.       const opening = group(
  1219.         concat([
  1220.           "if (",
  1221.           group(
  1222.             concat([
  1223.               indent(concat([softline, path.call(print, "test")])),
  1224.               softline
  1225.             ])
  1226.           ),
  1227.           ")",
  1228.           con
  1229.         ])
  1230.       );
  1231.  
  1232.       parts.push(opening);
  1233.  
  1234.       if (n.alternate) {
  1235.         if (n.consequent.type === "BlockStatement") {
  1236.           parts.push(" else");
  1237.         } else {
  1238.           parts.push(hardline, "else");
  1239.         }
  1240.  
  1241.         parts.push(
  1242.           group(
  1243.             adjustClause(
  1244.               n.alternate,
  1245.               path.call(print, "alternate"),
  1246.               n.alternate.type === "IfStatement"
  1247.             )
  1248.           )
  1249.         );
  1250.       }
  1251.  
  1252.       return concat(parts);
  1253.     }
  1254.     case "ForStatement": {
  1255.       const body = adjustClause(n.body, path.call(print, "body"));
  1256.  
  1257.       // We want to keep dangling comments above the loop to stay consistent.
  1258.       // Any comment positioned between the for statement and the parentheses
  1259.       // is going to be printed before the statement.
  1260.       const dangling = comments.printDanglingComments(
  1261.         path,
  1262.         options,
  1263.         /* sameLine */ true
  1264.       );
  1265.       const printedComments = dangling ? concat([dangling, softline]) : "";
  1266.  
  1267.       if (!n.init && !n.test && !n.update) {
  1268.         return concat([printedComments, group(concat(["for (;;)", body]))]);
  1269.       }
  1270.  
  1271.       return concat([
  1272.         printedComments,
  1273.         group(
  1274.           concat([
  1275.             "for (",
  1276.             group(
  1277.               concat([
  1278.                 indent(
  1279.                   concat([
  1280.                     softline,
  1281.                     path.call(print, "init"),
  1282.                     ";",
  1283.                     line,
  1284.                     path.call(print, "test"),
  1285.                     ";",
  1286.                     line,
  1287.                     path.call(print, "update")
  1288.                   ])
  1289.                 ),
  1290.                 softline
  1291.               ])
  1292.             ),
  1293.             ")",
  1294.             body
  1295.           ])
  1296.         )
  1297.       ]);
  1298.     }
  1299.     case "WhileStatement":
  1300.       return group(
  1301.         concat([
  1302.           "while (",
  1303.           group(
  1304.             concat([
  1305.               indent(concat([softline, path.call(print, "test")])),
  1306.               softline
  1307.             ])
  1308.           ),
  1309.           ")",
  1310.           adjustClause(n.body, path.call(print, "body"))
  1311.         ])
  1312.       );
  1313.     case "ForInStatement":
  1314.       // Note: esprima can't actually parse "for each (".
  1315.       return group(
  1316.         concat([
  1317.           n.each ? "for each (" : "for (",
  1318.           path.call(print, "left"),
  1319.           " in ",
  1320.           path.call(print, "right"),
  1321.           ")",
  1322.           adjustClause(n.body, path.call(print, "body"))
  1323.         ])
  1324.       );
  1325.  
  1326.     case "ForOfStatement":
  1327.     case "ForAwaitStatement": {
  1328.       // Babylon 7 removed ForAwaitStatement in favor of ForOfStatement
  1329.       // with `"await": true`:
  1330.       // https://github.com/estree/estree/pull/138
  1331.       const isAwait = n.type === "ForAwaitStatement" || n.await;
  1332.  
  1333.       return group(
  1334.         concat([
  1335.           "for",
  1336.           isAwait ? " await" : "",
  1337.           " (",
  1338.           path.call(print, "left"),
  1339.           " of ",
  1340.           path.call(print, "right"),
  1341.           ")",
  1342.           adjustClause(n.body, path.call(print, "body"))
  1343.         ])
  1344.       );
  1345.     }
  1346.  
  1347.     case "DoWhileStatement": {
  1348.       const clause = adjustClause(n.body, path.call(print, "body"));
  1349.       const doBody = group(concat(["do", clause]));
  1350.       parts = [doBody];
  1351.  
  1352.       if (n.body.type === "BlockStatement") {
  1353.         parts.push(" ");
  1354.       } else {
  1355.         parts.push(hardline);
  1356.       }
  1357.       parts.push("while (");
  1358.  
  1359.       parts.push(
  1360.         group(concat([indent(softline), path.call(print, "test"), softline])),
  1361.         ")",
  1362.         semi
  1363.       );
  1364.  
  1365.       return concat(parts);
  1366.     }
  1367.     case "DoExpression":
  1368.       return concat(["do ", path.call(print, "body")]);
  1369.     case "BreakStatement":
  1370.       parts.push("break");
  1371.  
  1372.       if (n.label) {
  1373.         parts.push(" ", path.call(print, "label"));
  1374.       }
  1375.  
  1376.       parts.push(semi);
  1377.  
  1378.       return concat(parts);
  1379.     case "ContinueStatement":
  1380.       parts.push("continue");
  1381.  
  1382.       if (n.label) {
  1383.         parts.push(" ", path.call(print, "label"));
  1384.       }
  1385.  
  1386.       parts.push(semi);
  1387.  
  1388.       return concat(parts);
  1389.     case "LabeledStatement":
  1390.       if (n.body.type === "EmptyStatement") {
  1391.         return concat([path.call(print, "label"), ":;"]);
  1392.       }
  1393.  
  1394.       return concat([
  1395.         path.call(print, "label"),
  1396.         ": ",
  1397.         path.call(print, "body")
  1398.       ]);
  1399.     case "TryStatement":
  1400.       parts.push("try ", path.call(print, "block"));
  1401.  
  1402.       if (n.handler) {
  1403.         parts.push(" ", path.call(print, "handler"));
  1404.       } else if (n.handlers) {
  1405.         path.each(handlerPath => {
  1406.           parts.push(" ", print(handlerPath));
  1407.         }, "handlers");
  1408.       }
  1409.  
  1410.       if (n.finalizer) {
  1411.         parts.push(" finally ", path.call(print, "finalizer"));
  1412.       }
  1413.  
  1414.       return concat(parts);
  1415.     case "CatchClause":
  1416.       parts.push("catch (", path.call(print, "param"));
  1417.  
  1418.       if (n.guard) {
  1419.         // Note: esprima does not recognize conditional catch clauses.
  1420.         parts.push(" if ", path.call(print, "guard"));
  1421.       }
  1422.  
  1423.       parts.push(") ", path.call(print, "body"));
  1424.  
  1425.       return concat(parts);
  1426.     case "ThrowStatement":
  1427.       return concat(["throw ", path.call(print, "argument"), semi]);
  1428.     // Note: ignoring n.lexical because it has no printing consequences.
  1429.     case "SwitchStatement":
  1430.       return concat([
  1431.         "switch (",
  1432.         path.call(print, "discriminant"),
  1433.         ") {",
  1434.         n.cases.length > 0
  1435.           ? indent(
  1436.               concat([
  1437.                 hardline,
  1438.                 join(
  1439.                   hardline,
  1440.                   path.map(casePath => {
  1441.                     const caseNode = casePath.getValue();
  1442.                     return concat([
  1443.                       casePath.call(print),
  1444.                       n.cases.indexOf(caseNode) !== n.cases.length - 1 &&
  1445.                         util.isNextLineEmpty(options.originalText, caseNode)
  1446.                         ? hardline
  1447.                         : ""
  1448.                     ]);
  1449.                   }, "cases")
  1450.                 )
  1451.               ])
  1452.             )
  1453.           : "",
  1454.         hardline,
  1455.         "}"
  1456.       ]);
  1457.     case "SwitchCase": {
  1458.       if (n.test) {
  1459.         parts.push("case ", path.call(print, "test"), ":");
  1460.       } else {
  1461.         parts.push("default:");
  1462.       }
  1463.  
  1464.       const consequent = n.consequent.filter(
  1465.         node => node.type !== "EmptyStatement"
  1466.       );
  1467.  
  1468.       if (consequent.length > 0) {
  1469.         const cons = path.call(consequentPath => {
  1470.           return join(
  1471.             hardline,
  1472.             consequentPath
  1473.               .map((p, i) => {
  1474.                 if (n.consequent[i].type === "EmptyStatement") {
  1475.                   return null;
  1476.                 }
  1477.                 const shouldAddLine =
  1478.                   i !== n.consequent.length - 1 &&
  1479.                   util.isNextLineEmpty(options.originalText, p.getValue());
  1480.                 return concat([print(p), shouldAddLine ? hardline : ""]);
  1481.               })
  1482.               .filter(e => e !== null)
  1483.           );
  1484.         }, "consequent");
  1485.  
  1486.         parts.push(
  1487.           consequent.length === 1 && consequent[0].type === "BlockStatement"
  1488.             ? concat([" ", cons])
  1489.             : indent(concat([hardline, cons]))
  1490.         );
  1491.       }
  1492.  
  1493.       return concat(parts);
  1494.     }
  1495.     // JSX extensions below.
  1496.     case "DebuggerStatement":
  1497.       return concat(["debugger", semi]);
  1498.     case "JSXAttribute":
  1499.       parts.push(path.call(print, "name"));
  1500.  
  1501.       if (n.value) {
  1502.         let res;
  1503.         if (isStringLiteral(n.value)) {
  1504.           const value = n.value.extra ? n.value.extra.raw : n.value.raw;
  1505.           res = '"' + value.slice(1, -1).replace(/"/g, "&quot;") + '"';
  1506.         } else {
  1507.           res = path.call(print, "value");
  1508.         }
  1509.         parts.push("=", res);
  1510.       }
  1511.  
  1512.       return concat(parts);
  1513.     case "JSXIdentifier":
  1514.       // Can be removed when this is fixed:
  1515.       // https://github.com/eslint/typescript-eslint-parser/issues/307
  1516.       if (!n.name) {
  1517.         return "this";
  1518.       }
  1519.       return "" + n.name;
  1520.     case "JSXNamespacedName":
  1521.       return join(":", [
  1522.         path.call(print, "namespace"),
  1523.         path.call(print, "name")
  1524.       ]);
  1525.     case "JSXMemberExpression":
  1526.       return join(".", [
  1527.         path.call(print, "object"),
  1528.         path.call(print, "property")
  1529.       ]);
  1530.     case "TSQualifiedName":
  1531.       return join(".", [path.call(print, "left"), path.call(print, "right")]);
  1532.     case "JSXSpreadAttribute":
  1533.       return concat(["{...", path.call(print, "argument"), "}"]);
  1534.     case "JSXExpressionContainer": {
  1535.       const parent = path.getParentNode(0);
  1536.  
  1537.       const shouldInline =
  1538.         n.expression.type === "ArrayExpression" ||
  1539.         n.expression.type === "ObjectExpression" ||
  1540.         n.expression.type === "ArrowFunctionExpression" ||
  1541.         n.expression.type === "CallExpression" ||
  1542.         n.expression.type === "FunctionExpression" ||
  1543.         n.expression.type === "JSXEmptyExpression" ||
  1544.         n.expression.type === "TemplateLiteral" ||
  1545.         n.expression.type === "TaggedTemplateExpression" ||
  1546.         (parent.type === "JSXElement" &&
  1547.           (n.expression.type === "ConditionalExpression" ||
  1548.             isBinaryish(n.expression)));
  1549.  
  1550.       if (shouldInline) {
  1551.         return group(
  1552.           concat(["{", path.call(print, "expression"), lineSuffixBoundary, "}"])
  1553.         );
  1554.       }
  1555.  
  1556.       return group(
  1557.         concat([
  1558.           "{",
  1559.           indent(concat([softline, path.call(print, "expression")])),
  1560.           softline,
  1561.           lineSuffixBoundary,
  1562.           "}"
  1563.         ])
  1564.       );
  1565.     }
  1566.     case "JSXElement": {
  1567.       const elem = comments.printComments(
  1568.         path,
  1569.         () => printJSXElement(path, options, print),
  1570.         options
  1571.       );
  1572.       return maybeWrapJSXElementInParens(path, elem);
  1573.     }
  1574.     case "JSXOpeningElement": {
  1575.       const n = path.getValue();
  1576.  
  1577.       // don't break up opening elements with a single long text attribute
  1578.       if (
  1579.         n.attributes.length === 1 &&
  1580.         n.attributes[0].value &&
  1581.         isStringLiteral(n.attributes[0].value)
  1582.       ) {
  1583.         return group(
  1584.           concat([
  1585.             "<",
  1586.             path.call(print, "name"),
  1587.             " ",
  1588.             concat(path.map(print, "attributes")),
  1589.             n.selfClosing ? " />" : ">"
  1590.           ])
  1591.         );
  1592.       }
  1593.  
  1594.       return group(
  1595.         concat([
  1596.           "<",
  1597.           path.call(print, "name"),
  1598.           concat([
  1599.             indent(
  1600.               concat(
  1601.                 path.map(attr => concat([line, print(attr)]), "attributes")
  1602.               )
  1603.             ),
  1604.             n.selfClosing ? line : options.jsxBracketSameLine ? ">" : softline
  1605.           ]),
  1606.           n.selfClosing ? "/>" : options.jsxBracketSameLine ? "" : ">"
  1607.         ])
  1608.       );
  1609.     }
  1610.     case "JSXClosingElement":
  1611.       return concat(["</", path.call(print, "name"), ">"]);
  1612.     case "JSXText":
  1613.       throw new Error("JSXTest should be handled by JSXElement");
  1614.     case "JSXEmptyExpression": {
  1615.       const requiresHardline =
  1616.         n.comments && !n.comments.every(util.isBlockComment);
  1617.  
  1618.       return concat([
  1619.         comments.printDanglingComments(
  1620.           path,
  1621.           options,
  1622.           /* sameIndent */ !requiresHardline
  1623.         ),
  1624.         requiresHardline ? hardline : ""
  1625.       ]);
  1626.     }
  1627.     case "TypeAnnotatedIdentifier":
  1628.       return concat([
  1629.         path.call(print, "annotation"),
  1630.         " ",
  1631.         path.call(print, "identifier")
  1632.       ]);
  1633.     case "ClassBody":
  1634.       if (!n.comments && n.body.length === 0) {
  1635.         return "{}";
  1636.       }
  1637.  
  1638.       return concat([
  1639.         "{",
  1640.         n.body.length > 0
  1641.           ? indent(
  1642.               concat([
  1643.                 hardline,
  1644.                 path.call(bodyPath => {
  1645.                   return printStatementSequence(bodyPath, options, print);
  1646.                 }, "body")
  1647.               ])
  1648.             )
  1649.           : comments.printDanglingComments(path, options),
  1650.         hardline,
  1651.         "}"
  1652.       ]);
  1653.     case "ClassPropertyDefinition":
  1654.       parts.push("static ", path.call(print, "definition"));
  1655.  
  1656.       if (
  1657.         n.definition.type !== "MethodDefinition" &&
  1658.         n.definition.type !== "TSAbstractMethodDefinition"
  1659.       ) {
  1660.         parts.push(semi);
  1661.       }
  1662.  
  1663.       return concat(parts);
  1664.     case "ClassProperty":
  1665.     case "TSAbstractClassProperty": {
  1666.       const variance = getFlowVariance(n);
  1667.       if (variance) {
  1668.         parts.push(variance);
  1669.       }
  1670.       if (n.accessibility) {
  1671.         parts.push(n.accessibility + " ");
  1672.       }
  1673.       if (n.static) {
  1674.         parts.push("static ");
  1675.       }
  1676.       if (n.type === "TSAbstractClassProperty") {
  1677.         parts.push("abstract ");
  1678.       }
  1679.       if (n.readonly) {
  1680.         parts.push("readonly ");
  1681.       }
  1682.       if (n.computed) {
  1683.         parts.push("[", path.call(print, "key"), "]");
  1684.       } else {
  1685.         parts.push(printPropertyKey(path, options, print));
  1686.       }
  1687.       if (n.typeAnnotation) {
  1688.         parts.push(": ", path.call(print, "typeAnnotation"));
  1689.       }
  1690.       if (n.value) {
  1691.         parts.push(
  1692.           " =",
  1693.           printAssignmentRight(
  1694.             n.value,
  1695.             path.call(print, "value"),
  1696.             false, // canBreak
  1697.             options
  1698.           )
  1699.         );
  1700.       }
  1701.  
  1702.       parts.push(semi);
  1703.  
  1704.       return concat(parts);
  1705.     }
  1706.     case "ClassDeclaration":
  1707.     case "ClassExpression":
  1708.     case "TSAbstractClassDeclaration":
  1709.       if (isNodeStartingWithDeclare(n, options)) {
  1710.         parts.push("declare ");
  1711.       }
  1712.       parts.push(concat(printClass(path, options, print)));
  1713.       return concat(parts);
  1714.     case "TSInterfaceHeritage":
  1715.       parts.push(path.call(print, "id"));
  1716.  
  1717.       if (n.typeParameters) {
  1718.         parts.push(path.call(print, "typeParameters"));
  1719.       }
  1720.  
  1721.       return concat(parts);
  1722.     case "TSHeritageClause":
  1723.       return join(", ", path.map(print, "types"));
  1724.     case "TSExpressionWithTypeArguments":
  1725.       return concat([
  1726.         path.call(print, "expression"),
  1727.         printTypeParameters(path, options, print, "typeArguments")
  1728.       ]);
  1729.     case "TemplateElement":
  1730.       return join(literalline, n.value.raw.split(/\r?\n/g));
  1731.     case "TemplateLiteral": {
  1732.       const expressions = path.map(print, "expressions");
  1733.  
  1734.       parts.push("`");
  1735.  
  1736.       path.each(childPath => {
  1737.         const i = childPath.getName();
  1738.  
  1739.         parts.push(print(childPath));
  1740.  
  1741.         if (i < expressions.length) {
  1742.           // For a template literal of the following form:
  1743.           //   `someQuery {
  1744.           //     ${call({
  1745.           //       a,
  1746.           //       b,
  1747.           //     })}
  1748.           //   }`
  1749.           // the expression is on its own line (there is a \n in the previous
  1750.           // quasi literal), therefore we want to indent the JavaScript
  1751.           // expression inside at the beginning of ${ instead of the beginning
  1752.           // of the `.
  1753.           let size = 0;
  1754.           const value = childPath.getValue().value.raw;
  1755.           const index = value.lastIndexOf("\n");
  1756.           const tabWidth = options.tabWidth;
  1757.           if (index !== -1) {
  1758.             size = util.getAlignmentSize(
  1759.               // All the leading whitespaces
  1760.               value.slice(index + 1).match(/^[ \t]*/)[0],
  1761.               tabWidth
  1762.             );
  1763.           }
  1764.  
  1765.           const aligned = addAlignmentToDoc(expressions[i], size, tabWidth);
  1766.  
  1767.           parts.push("${", aligned, lineSuffixBoundary, "}");
  1768.         }
  1769.       }, "quasis");
  1770.  
  1771.       parts.push("`");
  1772.  
  1773.       return concat(parts);
  1774.     }
  1775.     // These types are unprintable because they serve as abstract
  1776.     // supertypes for other (printable) types.
  1777.     case "TaggedTemplateExpression":
  1778.       return concat([path.call(print, "tag"), path.call(print, "quasi")]);
  1779.     case "Node":
  1780.     case "Printable":
  1781.     case "SourceLocation":
  1782.     case "Position":
  1783.     case "Statement":
  1784.     case "Function":
  1785.     case "Pattern":
  1786.     case "Expression":
  1787.     case "Declaration":
  1788.     case "Specifier":
  1789.     case "NamedSpecifier":
  1790.     case "Comment":
  1791.     case "MemberTypeAnnotation": // Flow
  1792.     case "Type":
  1793.       throw new Error("unprintable type: " + JSON.stringify(n.type));
  1794.     // Type Annotations for Facebook Flow, typically stripped out or
  1795.     // transformed away before printing.
  1796.     case "TypeAnnotation":
  1797.       if (n.typeAnnotation) {
  1798.         return path.call(print, "typeAnnotation");
  1799.       }
  1800.  
  1801.       return "";
  1802.     case "TSTupleType":
  1803.     case "TupleTypeAnnotation": {
  1804.       const typesField = n.type === "TSTupleType" ? "elementTypes" : "types";
  1805.       return group(
  1806.         concat([
  1807.           "[",
  1808.           indent(
  1809.             concat([
  1810.               softline,
  1811.               printArrayItems(path, options, typesField, print)
  1812.             ])
  1813.           ),
  1814.           // TypeScript doesn't support trailing commas in tuple types
  1815.           n.type === "TSTupleType"
  1816.             ? ""
  1817.             : ifBreak(shouldPrintComma(options) ? "," : ""),
  1818.           comments.printDanglingComments(path, options, /* sameIndent */ true),
  1819.           softline,
  1820.           "]"
  1821.         ])
  1822.       );
  1823.     }
  1824.  
  1825.     case "ExistsTypeAnnotation":
  1826.       return "*";
  1827.     case "EmptyTypeAnnotation":
  1828.       return "empty";
  1829.     case "AnyTypeAnnotation":
  1830.       return "any";
  1831.     case "MixedTypeAnnotation":
  1832.       return "mixed";
  1833.     case "ArrayTypeAnnotation":
  1834.       return concat([path.call(print, "elementType"), "[]"]);
  1835.     case "BooleanTypeAnnotation":
  1836.       return "boolean";
  1837.     case "BooleanLiteralTypeAnnotation":
  1838.       return "" + n.value;
  1839.     case "DeclareClass":
  1840.       return printFlowDeclaration(path, printClass(path, options, print));
  1841.     case "DeclareFunction":
  1842.       // For TypeScript the DeclareFunction node shares the AST
  1843.       // structure with FunctionDeclaration
  1844.       if (n.params) {
  1845.         return concat([
  1846.           "declare ",
  1847.           printFunctionDeclaration(path, print, options)
  1848.         ]);
  1849.       }
  1850.       return printFlowDeclaration(path, [
  1851.         "function ",
  1852.         path.call(print, "id"),
  1853.         n.predicate ? " " : "",
  1854.         path.call(print, "predicate"),
  1855.         semi
  1856.       ]);
  1857.     case "DeclareModule":
  1858.       return printFlowDeclaration(path, [
  1859.         "module ",
  1860.         path.call(print, "id"),
  1861.         " ",
  1862.         path.call(print, "body")
  1863.       ]);
  1864.     case "DeclareModuleExports":
  1865.       return printFlowDeclaration(path, [
  1866.         "module.exports",
  1867.         ": ",
  1868.         path.call(print, "typeAnnotation"),
  1869.         semi
  1870.       ]);
  1871.     case "DeclareVariable":
  1872.       return printFlowDeclaration(path, ["var ", path.call(print, "id"), semi]);
  1873.     case "DeclareExportAllDeclaration":
  1874.       return concat(["declare export * from ", path.call(print, "source")]);
  1875.     case "DeclareExportDeclaration":
  1876.       return concat(["declare ", printExportDeclaration(path, options, print)]);
  1877.     case "FunctionTypeAnnotation":
  1878.     case "TSFunctionType": {
  1879.       // FunctionTypeAnnotation is ambiguous:
  1880.       // declare function foo(a: B): void; OR
  1881.       // var A: (a: B) => void;
  1882.       const parent = path.getParentNode(0);
  1883.       const parentParent = path.getParentNode(1);
  1884.       const parentParentParent = path.getParentNode(2);
  1885.       let isArrowFunctionTypeAnnotation =
  1886.         n.type === "TSFunctionType" ||
  1887.         !(
  1888.           (parent.type === "ObjectTypeProperty" &&
  1889.             !getFlowVariance(parent) &&
  1890.             !parent.optional &&
  1891.             util.locStart(parent) === util.locStart(n)) ||
  1892.           parent.type === "ObjectTypeCallProperty" ||
  1893.           (parentParentParent && parentParentParent.type === "DeclareFunction")
  1894.         );
  1895.  
  1896.       let needsColon =
  1897.         isArrowFunctionTypeAnnotation && parent.type === "TypeAnnotation";
  1898.  
  1899.       // Sadly we can't put it inside of FastPath::needsColon because we are
  1900.       // printing ":" as part of the expression and it would put parenthesis
  1901.       // around :(
  1902.       const needsParens =
  1903.         needsColon &&
  1904.         isArrowFunctionTypeAnnotation &&
  1905.         parent.type === "TypeAnnotation" &&
  1906.         parentParent.type === "ArrowFunctionExpression";
  1907.  
  1908.       if (isObjectTypePropertyAFunction(parent)) {
  1909.         isArrowFunctionTypeAnnotation = true;
  1910.         needsColon = true;
  1911.       }
  1912.  
  1913.       if (needsParens) {
  1914.         parts.push("(");
  1915.       }
  1916.  
  1917.       parts.push(
  1918.         printFunctionTypeParameters(path, options, print),
  1919.         printFunctionParams(path, print, options)
  1920.       );
  1921.  
  1922.       // The returnType is not wrapped in a TypeAnnotation, so the colon
  1923.       // needs to be added separately.
  1924.       if (n.returnType || n.predicate || n.typeAnnotation) {
  1925.         parts.push(
  1926.           isArrowFunctionTypeAnnotation ? " => " : ": ",
  1927.           path.call(print, "returnType"),
  1928.           path.call(print, "predicate"),
  1929.           path.call(print, "typeAnnotation")
  1930.         );
  1931.       }
  1932.       if (needsParens) {
  1933.         parts.push(")");
  1934.       }
  1935.  
  1936.       return group(concat(parts));
  1937.     }
  1938.     case "FunctionTypeParam":
  1939.       return concat([
  1940.         path.call(print, "name"),
  1941.         n.optional ? "?" : "",
  1942.         n.name ? ": " : "",
  1943.         path.call(print, "typeAnnotation")
  1944.       ]);
  1945.     case "GenericTypeAnnotation":
  1946.       return concat([
  1947.         path.call(print, "id"),
  1948.         path.call(print, "typeParameters")
  1949.       ]);
  1950.     case "DeclareInterface":
  1951.     case "InterfaceDeclaration": {
  1952.       if (
  1953.         n.type === "DeclareInterface" ||
  1954.         isNodeStartingWithDeclare(n, options)
  1955.       ) {
  1956.         parts.push("declare ");
  1957.       }
  1958.  
  1959.       parts.push(
  1960.         "interface ",
  1961.         path.call(print, "id"),
  1962.         path.call(print, "typeParameters")
  1963.       );
  1964.  
  1965.       if (n["extends"].length > 0) {
  1966.         parts.push(
  1967.           group(
  1968.             indent(
  1969.               concat([line, "extends ", join(", ", path.map(print, "extends"))])
  1970.             )
  1971.           )
  1972.         );
  1973.       }
  1974.  
  1975.       parts.push(" ");
  1976.       parts.push(path.call(print, "body"));
  1977.  
  1978.       return group(concat(parts));
  1979.     }
  1980.     case "ClassImplements":
  1981.     case "InterfaceExtends":
  1982.       return concat([
  1983.         path.call(print, "id"),
  1984.         path.call(print, "typeParameters")
  1985.       ]);
  1986.     case "TSIntersectionType":
  1987.     case "IntersectionTypeAnnotation": {
  1988.       const types = path.map(print, "types");
  1989.       const result = [];
  1990.       for (let i = 0; i < types.length; ++i) {
  1991.         if (i === 0) {
  1992.           result.push(types[i]);
  1993.         } else if (!isObjectType(n.types[i - 1]) && !isObjectType(n.types[i])) {
  1994.           // If no object is involved, go to the next line if it breaks
  1995.           result.push(indent(concat([" &", line, types[i]])));
  1996.         } else {
  1997.           // If you go from object to non-object or vis-versa, then inline it
  1998.           result.push(" & ", i > 1 ? indent(types[i]) : types[i]);
  1999.         }
  2000.       }
  2001.       return group(concat(result));
  2002.     }
  2003.     case "TSUnionType":
  2004.     case "UnionTypeAnnotation": {
  2005.       // single-line variation
  2006.       // A | B | C
  2007.  
  2008.       // multi-line variation
  2009.       // | A
  2010.       // | B
  2011.       // | C
  2012.  
  2013.       const parent = path.getParentNode();
  2014.       // If there's a leading comment, the parent is doing the indentation
  2015.       const shouldIndent =
  2016.         parent.type !== "TypeParameterInstantiation" &&
  2017.         parent.type !== "GenericTypeAnnotation" &&
  2018.         !(
  2019.           (parent.type === "TypeAlias" ||
  2020.             parent.type === "VariableDeclarator") &&
  2021.           hasLeadingOwnLineComment(options.originalText, n)
  2022.         );
  2023.  
  2024.       // {
  2025.       //   a: string
  2026.       // } | null | void
  2027.       // should be inlined and not be printed in the multi-line variant
  2028.       const shouldHug = shouldHugType(n);
  2029.  
  2030.       // We want to align the children but without its comment, so it looks like
  2031.       // | child1
  2032.       // // comment
  2033.       // | child2
  2034.       const printed = path.map(typePath => {
  2035.         let printedType = typePath.call(print);
  2036.         if (!shouldHug && shouldIndent) {
  2037.           printedType = align(2, printedType);
  2038.         }
  2039.         return comments.printComments(typePath, () => printedType, options);
  2040.       }, "types");
  2041.  
  2042.       if (shouldHug) {
  2043.         return join(" | ", printed);
  2044.       }
  2045.  
  2046.       const code = concat([
  2047.         ifBreak(concat([shouldIndent ? line : "", "| "])),
  2048.         join(concat([line, "| "]), printed)
  2049.       ]);
  2050.  
  2051.       return group(shouldIndent ? indent(code) : code);
  2052.     }
  2053.     case "NullableTypeAnnotation":
  2054.       return concat(["?", path.call(print, "typeAnnotation")]);
  2055.     case "NullLiteralTypeAnnotation":
  2056.       return "null";
  2057.     case "ThisTypeAnnotation":
  2058.       return "this";
  2059.     case "NumberTypeAnnotation":
  2060.       return "number";
  2061.     case "ObjectTypeCallProperty":
  2062.       if (n.static) {
  2063.         parts.push("static ");
  2064.       }
  2065.  
  2066.       parts.push(path.call(print, "value"));
  2067.  
  2068.       return concat(parts);
  2069.     case "ObjectTypeIndexer": {
  2070.       const variance = getFlowVariance(n);
  2071.       return concat([
  2072.         variance || "",
  2073.         "[",
  2074.         path.call(print, "id"),
  2075.         n.id ? ": " : "",
  2076.         path.call(print, "key"),
  2077.         "]: ",
  2078.         path.call(print, "value")
  2079.       ]);
  2080.     }
  2081.     case "ObjectTypeProperty": {
  2082.       const variance = getFlowVariance(n);
  2083.  
  2084.       return concat([
  2085.         n.static ? "static " : "",
  2086.         isGetterOrSetter(n) ? n.kind + " " : "",
  2087.         variance || "",
  2088.         path.call(print, "key"),
  2089.         n.optional ? "?" : "",
  2090.         isFunctionNotation(n) ? "" : ": ",
  2091.         path.call(print, "value")
  2092.       ]);
  2093.     }
  2094.     case "QualifiedTypeIdentifier":
  2095.       return concat([
  2096.         path.call(print, "qualification"),
  2097.         ".",
  2098.         path.call(print, "id")
  2099.       ]);
  2100.     case "StringLiteralTypeAnnotation":
  2101.       return nodeStr(n, options);
  2102.     case "NumberLiteralTypeAnnotation":
  2103.       assert.strictEqual(typeof n.value, "number");
  2104.  
  2105.       if (n.extra != null) {
  2106.         return printNumber(n.extra.raw);
  2107.       } else {
  2108.         return printNumber(n.raw);
  2109.       }
  2110.     case "StringTypeAnnotation":
  2111.       return "string";
  2112.     case "DeclareTypeAlias":
  2113.     case "TypeAlias": {
  2114.       if (
  2115.         n.type === "DeclareTypeAlias" ||
  2116.         isNodeStartingWithDeclare(n, options)
  2117.       ) {
  2118.         parts.push("declare ");
  2119.       }
  2120.  
  2121.       const canBreak = n.right.type === "StringLiteralTypeAnnotation";
  2122.  
  2123.       const printed = printAssignmentRight(
  2124.         n.right,
  2125.         path.call(print, "right"),
  2126.         canBreak,
  2127.         options
  2128.       );
  2129.  
  2130.       parts.push(
  2131.         "type ",
  2132.         path.call(print, "id"),
  2133.         path.call(print, "typeParameters"),
  2134.         " =",
  2135.         printed,
  2136.         semi
  2137.       );
  2138.  
  2139.       return group(concat(parts));
  2140.     }
  2141.     case "TypeCastExpression":
  2142.       return concat([
  2143.         "(",
  2144.         path.call(print, "expression"),
  2145.         ": ",
  2146.         path.call(print, "typeAnnotation"),
  2147.         ")"
  2148.       ]);
  2149.     case "TypeParameterDeclaration":
  2150.     case "TypeParameterInstantiation":
  2151.       return printTypeParameters(path, options, print, "params");
  2152.     case "TypeParameter": {
  2153.       const variance = getFlowVariance(n);
  2154.  
  2155.       if (variance) {
  2156.         parts.push(variance);
  2157.       }
  2158.  
  2159.       parts.push(path.call(print, "name"));
  2160.  
  2161.       if (n.bound) {
  2162.         parts.push(": ");
  2163.         parts.push(path.call(print, "bound"));
  2164.       }
  2165.  
  2166.       if (n.constraint) {
  2167.         parts.push(" extends ", path.call(print, "constraint"));
  2168.       }
  2169.  
  2170.       if (n["default"]) {
  2171.         parts.push(" = ", path.call(print, "default"));
  2172.       }
  2173.  
  2174.       return concat(parts);
  2175.     }
  2176.     case "TypeofTypeAnnotation":
  2177.       return concat(["typeof ", path.call(print, "argument")]);
  2178.     case "VoidTypeAnnotation":
  2179.       return "void";
  2180.     case "NullTypeAnnotation":
  2181.       return "null";
  2182.     case "InferredPredicate":
  2183.       return "%checks";
  2184.     // Unhandled types below. If encountered, nodes of these types should
  2185.     // be either left alone or desugared into AST types that are fully
  2186.     // supported by the pretty-printer.
  2187.     case "DeclaredPredicate":
  2188.       return concat(["%checks(", path.call(print, "value"), ")"]);
  2189.     case "TSAbstractKeyword":
  2190.       return "abstract";
  2191.     case "TSAnyKeyword":
  2192.       return "any";
  2193.     case "TSAsyncKeyword":
  2194.       return "async";
  2195.     case "TSBooleanKeyword":
  2196.       return "boolean";
  2197.     case "TSConstKeyword":
  2198.       return "const";
  2199.     case "TSDeclareKeyword":
  2200.       return "declare";
  2201.     case "TSExportKeyword":
  2202.       return "export";
  2203.     case "TSNeverKeyword":
  2204.       return "never";
  2205.     case "TSNumberKeyword":
  2206.       return "number";
  2207.     case "TSObjectKeyword":
  2208.       return "object";
  2209.     case "TSProtectedKeyword":
  2210.       return "protected";
  2211.     case "TSPrivateKeyword":
  2212.       return "private";
  2213.     case "TSPublicKeyword":
  2214.       return "public";
  2215.     case "TSReadonlyKeyword":
  2216.       return "readonly";
  2217.     case "TSSymbolKeyword":
  2218.       return "symbol";
  2219.     case "TSStaticKeyword":
  2220.       return "static";
  2221.     case "TSStringKeyword":
  2222.       return "string";
  2223.     case "TSUndefinedKeyword":
  2224.       return "undefined";
  2225.     case "TSVoidKeyword":
  2226.       return "void";
  2227.     case "TSAsExpression":
  2228.       return concat([
  2229.         path.call(print, "expression"),
  2230.         " as ",
  2231.         path.call(print, "typeAnnotation")
  2232.       ]);
  2233.     case "TSArrayType":
  2234.       return concat([path.call(print, "elementType"), "[]"]);
  2235.     case "TSPropertySignature": {
  2236.       if (n.accessibility) {
  2237.         parts.push(n.accessibility + " ");
  2238.       }
  2239.       if (n.export) {
  2240.         parts.push("export ");
  2241.       }
  2242.       if (n.static) {
  2243.         parts.push("static ");
  2244.       }
  2245.  
  2246.       if (n.readonly) {
  2247.         parts.push("readonly ");
  2248.       }
  2249.  
  2250.       if (n.computed) {
  2251.         parts.push("[");
  2252.       }
  2253.  
  2254.       parts.push(path.call(print, "key"));
  2255.  
  2256.       if (n.computed) {
  2257.         parts.push("]");
  2258.       }
  2259.  
  2260.       if (n.optional) {
  2261.         parts.push("?");
  2262.       }
  2263.  
  2264.       if (n.typeAnnotation) {
  2265.         parts.push(": ");
  2266.         parts.push(path.call(print, "typeAnnotation"));
  2267.       }
  2268.  
  2269.       // This isn't valid semantically, but it's in the AST so we can print it.
  2270.       if (n.initializer) {
  2271.         parts.push(" = ", path.call(print, "initializer"));
  2272.       }
  2273.  
  2274.       return concat(parts);
  2275.     }
  2276.     case "TSParameterProperty":
  2277.       if (n.accessibility) {
  2278.         parts.push(n.accessibility + " ");
  2279.       }
  2280.       if (n.export) {
  2281.         parts.push("export ");
  2282.       }
  2283.       if (n.static) {
  2284.         parts.push("static ");
  2285.       }
  2286.       if (n.readonly) {
  2287.         parts.push("readonly ");
  2288.       }
  2289.  
  2290.       parts.push(path.call(print, "parameter"));
  2291.  
  2292.       return concat(parts);
  2293.     case "TSTypeReference":
  2294.       return concat([
  2295.         path.call(print, "typeName"),
  2296.         printTypeParameters(path, options, print, "typeParameters")
  2297.       ]);
  2298.     case "TSTypeQuery":
  2299.       return concat(["typeof ", path.call(print, "exprName")]);
  2300.     case "TSParenthesizedType":
  2301.       return concat(["(", path.call(print, "typeAnnotation"), ")"]);
  2302.     case "TSIndexSignature": {
  2303.       const parent = path.getParentNode();
  2304.       let printedParams = [];
  2305.       if (n.params) {
  2306.         printedParams = path.map(print, "params");
  2307.       }
  2308.       if (n.parameters) {
  2309.         printedParams = path.map(print, "parameters");
  2310.       }
  2311.  
  2312.       return concat([
  2313.         n.accessibility ? concat([n.accessibility, " "]) : "",
  2314.         n.export ? "export " : "",
  2315.         n.static ? "static " : "",
  2316.         n.readonly ? "readonly " : "",
  2317.         "[",
  2318.         path.call(print, "index"),
  2319.         // This should only contain a single element, however TypeScript parses
  2320.         // it using parseDelimitedList that uses commas as delimiter.
  2321.         join(", ", printedParams),
  2322.         "]: ",
  2323.         path.call(print, "typeAnnotation"),
  2324.         parent.type === "ClassBody" ? semi : ""
  2325.       ]);
  2326.     }
  2327.     case "TSTypePredicate":
  2328.       return concat([
  2329.         path.call(print, "parameterName"),
  2330.         " is ",
  2331.         path.call(print, "typeAnnotation")
  2332.       ]);
  2333.     case "TSNonNullExpression":
  2334.       return concat([path.call(print, "expression"), "!"]);
  2335.     case "TSThisType":
  2336.       return "this";
  2337.     case "TSLastTypeNode":
  2338.       return path.call(print, "literal");
  2339.     case "TSIndexedAccessType":
  2340.       return concat([
  2341.         path.call(print, "objectType"),
  2342.         "[",
  2343.         path.call(print, "indexType"),
  2344.         "]"
  2345.       ]);
  2346.     case "TSConstructSignature":
  2347.     case "TSConstructorType":
  2348.     case "TSCallSignature": {
  2349.       if (n.type !== "TSCallSignature") {
  2350.         parts.push("new ");
  2351.       }
  2352.       const isType = n.type === "TSConstructorType";
  2353.  
  2354.       if (n.typeParameters) {
  2355.         parts.push(printTypeParameters(path, options, print, "typeParameters"));
  2356.       }
  2357.  
  2358.       const params = n.params
  2359.         ? path.map(print, "params")
  2360.         : path.map(print, "parameters");
  2361.       parts.push("(", join(", ", params), ")");
  2362.       if (n.typeAnnotation) {
  2363.         parts.push(isType ? " => " : ": ", path.call(print, "typeAnnotation"));
  2364.       }
  2365.       return concat(parts);
  2366.     }
  2367.     case "TSTypeOperator":
  2368.       return concat(["keyof ", path.call(print, "typeAnnotation")]);
  2369.     case "TSMappedType":
  2370.       return group(
  2371.         concat([
  2372.           "{",
  2373.           indent(
  2374.             concat([
  2375.               options.bracketSpacing ? line : softline,
  2376.               n.readonlyToken
  2377.                 ? concat([path.call(print, "readonlyToken"), " "])
  2378.                 : "",
  2379.               printTypeScriptModifiers(path, options, print),
  2380.               "[",
  2381.               path.call(print, "typeParameter"),
  2382.               "]",
  2383.               n.questionToken ? "?" : "",
  2384.               ": ",
  2385.               path.call(print, "typeAnnotation")
  2386.             ])
  2387.           ),
  2388.           comments.printDanglingComments(path, options, /* sameIndent */ true),
  2389.           options.bracketSpacing ? line : softline,
  2390.           "}"
  2391.         ])
  2392.       );
  2393.     case "TSTypeParameter":
  2394.       parts.push(path.call(print, "name"));
  2395.  
  2396.       if (n.constraint) {
  2397.         parts.push(" in ", path.call(print, "constraint"));
  2398.       }
  2399.  
  2400.       return concat(parts);
  2401.     case "TSMethodSignature":
  2402.       parts.push(
  2403.         n.accessibility ? concat([n.accessibility, " "]) : "",
  2404.         n.export ? "export " : "",
  2405.         n.static ? "static " : "",
  2406.         n.readonly ? "readonly " : "",
  2407.         n.computed ? "[" : "",
  2408.         path.call(print, "key"),
  2409.         n.computed ? "]" : "",
  2410.         n.optional ? "?" : "",
  2411.         printFunctionTypeParameters(path, options, print),
  2412.         printFunctionParams(path, print, options)
  2413.       );
  2414.  
  2415.       if (n.typeAnnotation) {
  2416.         parts.push(": ", path.call(print, "typeAnnotation"));
  2417.       }
  2418.       return concat(parts);
  2419.     case "TSNamespaceExportDeclaration":
  2420.       if (n.declaration) {
  2421.         // Temporary fix until https://github.com/eslint/typescript-eslint-parser/issues/263
  2422.         const isDefault = options.originalText
  2423.           .slice(util.locStart(n), util.locStart(n.declaration))
  2424.           .match(/\bdefault\b/);
  2425.         parts.push(
  2426.           "export ",
  2427.           isDefault ? "default " : "",
  2428.           path.call(print, "declaration")
  2429.         );
  2430.       } else {
  2431.         parts.push("export as namespace ", path.call(print, "name"));
  2432.  
  2433.         if (options.semi) {
  2434.           parts.push(";");
  2435.         }
  2436.       }
  2437.  
  2438.       return group(concat(parts));
  2439.     case "TSEnumDeclaration":
  2440.       if (n.modifiers) {
  2441.         parts.push(printTypeScriptModifiers(path, options, print));
  2442.       }
  2443.  
  2444.       parts.push("enum ", path.call(print, "name"), " ");
  2445.  
  2446.       if (n.members.length === 0) {
  2447.         parts.push(
  2448.           group(
  2449.             concat([
  2450.               "{",
  2451.               comments.printDanglingComments(path, options),
  2452.               softline,
  2453.               "}"
  2454.             ])
  2455.           )
  2456.         );
  2457.       } else {
  2458.         parts.push(
  2459.           group(
  2460.             concat([
  2461.               "{",
  2462.               indent(
  2463.                 concat([
  2464.                   hardline,
  2465.                   printArrayItems(path, options, "members", print),
  2466.                   shouldPrintComma(options, "es5") ? "," : ""
  2467.                 ])
  2468.               ),
  2469.               comments.printDanglingComments(
  2470.                 path,
  2471.                 options,
  2472.                 /* sameIndent */ true
  2473.               ),
  2474.               hardline,
  2475.               "}"
  2476.             ])
  2477.           )
  2478.         );
  2479.       }
  2480.  
  2481.       return concat(parts);
  2482.     case "TSEnumMember":
  2483.       parts.push(path.call(print, "name"));
  2484.       if (n.initializer) {
  2485.         parts.push(" = ", path.call(print, "initializer"));
  2486.       }
  2487.       return concat(parts);
  2488.     case "TSImportEqualsDeclaration":
  2489.       parts.push(
  2490.         printTypeScriptModifiers(path, options, print),
  2491.         "import ",
  2492.         path.call(print, "name"),
  2493.         " = ",
  2494.         path.call(print, "moduleReference")
  2495.       );
  2496.  
  2497.       if (options.semi) {
  2498.         parts.push(";");
  2499.       }
  2500.  
  2501.       return group(concat(parts));
  2502.     case "TSExternalModuleReference":
  2503.       return concat(["require(", path.call(print, "expression"), ")"]);
  2504.     case "TSModuleDeclaration": {
  2505.       const parent = path.getParentNode();
  2506.       const isExternalModule = isLiteral(n.name);
  2507.       const parentIsDeclaration = parent.type === "TSModuleDeclaration";
  2508.       const bodyIsDeclaration = n.body && n.body.type === "TSModuleDeclaration";
  2509.  
  2510.       if (parentIsDeclaration) {
  2511.         parts.push(".");
  2512.       } else {
  2513.         parts.push(printTypeScriptModifiers(path, options, print));
  2514.  
  2515.         // Global declaration looks like this:
  2516.         // declare global { ... }
  2517.         const isGlobalDeclaration =
  2518.           n.name.type === "Identifier" &&
  2519.           n.name.name === "global" &&
  2520.           n.modifiers &&
  2521.           n.modifiers.some(modifier => modifier.type === "TSDeclareKeyword");
  2522.  
  2523.         if (!isGlobalDeclaration) {
  2524.           parts.push(isExternalModule ? "module " : "namespace ");
  2525.         }
  2526.       }
  2527.  
  2528.       parts.push(path.call(print, "name"));
  2529.  
  2530.       if (bodyIsDeclaration) {
  2531.         parts.push(path.call(print, "body"));
  2532.       } else if (n.body) {
  2533.         parts.push(
  2534.           " {",
  2535.           indent(
  2536.             concat([
  2537.               line,
  2538.               path.call(
  2539.                 bodyPath =>
  2540.                   comments.printDanglingComments(bodyPath, options, true),
  2541.                 "body"
  2542.               ),
  2543.               group(path.call(print, "body"))
  2544.             ])
  2545.           ),
  2546.           line,
  2547.           "}"
  2548.         );
  2549.       } else {
  2550.         parts.push(semi);
  2551.       }
  2552.  
  2553.       return concat(parts);
  2554.     }
  2555.     case "TSModuleBlock":
  2556.       return path.call(bodyPath => {
  2557.         return printStatementSequence(bodyPath, options, print);
  2558.       }, "body");
  2559.     // postcss
  2560.     case "css-root": {
  2561.       return concat([printNodeSequence(path, options, print), hardline]);
  2562.     }
  2563.     case "css-comment": {
  2564.       if (n.raws.content) {
  2565.         return n.raws.content;
  2566.       }
  2567.       const text = options.originalText.slice(util.locStart(n), util.locEnd(n));
  2568.       const rawText = n.raws.text || n.text;
  2569.       // Workaround a bug where the location is off.
  2570.       // https://github.com/postcss/postcss-scss/issues/63
  2571.       if (text.indexOf(rawText) === -1) {
  2572.         if (n.raws.inline) {
  2573.           return concat(["// ", rawText]);
  2574.         }
  2575.         return concat(["/* ", rawText, " */"]);
  2576.       }
  2577.       return text;
  2578.     }
  2579.     case "css-rule": {
  2580.       return concat([
  2581.         path.call(print, "selector"),
  2582.         n.important ? " !important" : "",
  2583.         n.nodes
  2584.           ? concat([
  2585.               " {",
  2586.               n.nodes.length > 0
  2587.                 ? indent(
  2588.                     concat([hardline, printNodeSequence(path, options, print)])
  2589.                   )
  2590.                 : "",
  2591.               hardline,
  2592.               "}"
  2593.             ])
  2594.           : ";"
  2595.       ]);
  2596.     }
  2597.     case "css-decl": {
  2598.       return concat([
  2599.         n.raws.before.replace(/[\s;]/g, ""),
  2600.         n.prop,
  2601.         ": ",
  2602.         path.call(print, "value"),
  2603.         n.important ? " !important" : "",
  2604.         n.nodes
  2605.           ? concat([
  2606.               " {",
  2607.               indent(
  2608.                 concat([softline, printNodeSequence(path, options, print)])
  2609.               ),
  2610.               softline,
  2611.               "}"
  2612.             ])
  2613.           : ";"
  2614.       ]);
  2615.     }
  2616.     case "css-atrule": {
  2617.       const hasParams =
  2618.         n.params &&
  2619.         !(n.params.type === "media-query-list" && n.params.value === "");
  2620.       return concat([
  2621.         "@",
  2622.         n.name,
  2623.         hasParams ? concat([" ", path.call(print, "params")]) : "",
  2624.         n.nodes
  2625.           ? concat([
  2626.               " {",
  2627.               indent(
  2628.                 concat([
  2629.                   n.nodes.length > 0 ? softline : "",
  2630.                   printNodeSequence(path, options, print)
  2631.                 ])
  2632.               ),
  2633.               softline,
  2634.               "}"
  2635.             ])
  2636.           : ";"
  2637.       ]);
  2638.     }
  2639.     case "css-import": {
  2640.       return concat([
  2641.         "@",
  2642.         n.name,
  2643.         " ",
  2644.         n.directives ? concat([n.directives, " "]) : "",
  2645.         n.importPath,
  2646.         ";"
  2647.       ]);
  2648.     }
  2649.     // postcss-media-query-parser
  2650.     case "media-query-list": {
  2651.       const parts = [];
  2652.       path.each(childPath => {
  2653.         const node = childPath.getValue();
  2654.         if (node.type === "media-query" && node.value === "") {
  2655.           return;
  2656.         }
  2657.         parts.push(childPath.call(print));
  2658.       }, "nodes");
  2659.       return join(", ", parts);
  2660.     }
  2661.     case "media-query": {
  2662.       return join(" ", path.map(print, "nodes"));
  2663.     }
  2664.     case "media-type": {
  2665.       return n.value;
  2666.     }
  2667.     case "media-feature-expression": {
  2668.       if (!n.nodes) {
  2669.         return n.value;
  2670.       }
  2671.       return concat(["(", concat(path.map(print, "nodes")), ")"]);
  2672.     }
  2673.     case "media-feature": {
  2674.       return n.value.replace(/ +/g, " ");
  2675.     }
  2676.     case "media-colon": {
  2677.       return concat([n.value, " "]);
  2678.     }
  2679.     case "media-value": {
  2680.       return n.value;
  2681.     }
  2682.     case "media-keyword": {
  2683.       return n.value;
  2684.     }
  2685.     case "media-url": {
  2686.       return n.value;
  2687.     }
  2688.     case "media-unknown": {
  2689.       return n.value;
  2690.     }
  2691.     // postcss-selector-parser
  2692.     case "selector-root": {
  2693.       return group(join(concat([",", line]), path.map(print, "nodes")));
  2694.     }
  2695.     case "selector-comment": {
  2696.       return n.value;
  2697.     }
  2698.     case "selector-string": {
  2699.       return n.value;
  2700.     }
  2701.     case "selector-tag": {
  2702.       return n.value;
  2703.     }
  2704.     case "selector-id": {
  2705.       return concat(["#", n.value]);
  2706.     }
  2707.     case "selector-class": {
  2708.       return concat([".", n.value]);
  2709.     }
  2710.     case "selector-attribute": {
  2711.       return concat([
  2712.         "[",
  2713.         n.attribute,
  2714.         n.operator ? n.operator : "",
  2715.         n.value ? n.value : "",
  2716.         n.insensitive ? " i" : "",
  2717.         "]"
  2718.       ]);
  2719.     }
  2720.     case "selector-combinator": {
  2721.       if (n.value === "+" || n.value === ">" || n.value === "~") {
  2722.         const parent = path.getParentNode();
  2723.         const leading = parent.type === "selector-selector" &&
  2724.           parent.nodes[0] === n
  2725.           ? ""
  2726.           : line;
  2727.         return concat([leading, n.value, " "]);
  2728.       }
  2729.       return n.value;
  2730.     }
  2731.     case "selector-universal": {
  2732.       return n.value;
  2733.     }
  2734.     case "selector-selector": {
  2735.       return group(indent(concat(path.map(print, "nodes"))));
  2736.     }
  2737.     case "selector-pseudo": {
  2738.       return concat([
  2739.         n.value,
  2740.         n.nodes && n.nodes.length > 0
  2741.           ? concat(["(", join(", ", path.map(print, "nodes")), ")"])
  2742.           : ""
  2743.       ]);
  2744.     }
  2745.     case "selector-nesting": {
  2746.       return printValue(n.value);
  2747.     }
  2748.     // postcss-values-parser
  2749.     case "value-root": {
  2750.       return path.call(print, "group");
  2751.     }
  2752.     case "value-comma_group": {
  2753.       const printed = path.map(print, "groups");
  2754.       const parts = [];
  2755.       for (let i = 0; i < n.groups.length; ++i) {
  2756.         parts.push(printed[i]);
  2757.         if (
  2758.           i !== n.groups.length - 1 &&
  2759.           n.groups[i + 1].raws &&
  2760.           n.groups[i + 1].raws.before !== ""
  2761.         ) {
  2762.           if (
  2763.             n.groups[i + 1].type === "value-operator" &&
  2764.             ["+", "-", "/", "*", "%"].indexOf(n.groups[i + 1].value) !== -1
  2765.           ) {
  2766.             parts.push(" ");
  2767.           } else {
  2768.             parts.push(line);
  2769.           }
  2770.         }
  2771.       }
  2772.  
  2773.       return group(indent(concat(parts)));
  2774.     }
  2775.     case "value-paren_group": {
  2776.       const parent = path.getParentNode(