BVB Source Codes

prettier Show comments.js Source code

Return Download prettier: download comments.js Source code - Download prettier Source code - Type:.js
  1. "use strict";
  2.  
  3. const assert = require("assert");
  4. const docBuilders = require("./doc-builders");
  5. const concat = docBuilders.concat;
  6. const hardline = docBuilders.hardline;
  7. const breakParent = docBuilders.breakParent;
  8. const indent = docBuilders.indent;
  9. const lineSuffix = docBuilders.lineSuffix;
  10. const join = docBuilders.join;
  11. const cursor = docBuilders.cursor;
  12. const util = require("./util");
  13. const childNodesCacheKey = Symbol("child-nodes");
  14. const locStart = util.locStart;
  15. const locEnd = util.locEnd;
  16. const getNextNonSpaceNonCommentCharacter =
  17.   util.getNextNonSpaceNonCommentCharacter;
  18.  
  19. function getSortedChildNodes(node, text, resultArray) {
  20.   if (!node) {
  21.     return;
  22.   }
  23.  
  24.   if (resultArray) {
  25.     if (
  26.       node &&
  27.       node.type &&
  28.       node.type !== "CommentBlock" &&
  29.       node.type !== "CommentLine" &&
  30.       node.type !== "Line" &&
  31.       node.type !== "Block" &&
  32.       node.type !== "EmptyStatement" &&
  33.       node.type !== "TemplateElement"
  34.     ) {
  35.       // This reverse insertion sort almost always takes constant
  36.       // time because we almost always (maybe always?) append the
  37.       // nodes in order anyway.
  38.       let i;
  39.       for (i = resultArray.length - 1; i >= 0; --i) {
  40.         if (
  41.           locStart(resultArray[i]) <= locStart(node) &&
  42.           locEnd(resultArray[i]) <= locEnd(node)
  43.         ) {
  44.           break;
  45.         }
  46.       }
  47.       resultArray.splice(i + 1, 0, node);
  48.       return;
  49.     }
  50.   } else if (node[childNodesCacheKey]) {
  51.     return node[childNodesCacheKey];
  52.   }
  53.  
  54.   let names;
  55.   if (node && typeof node === "object") {
  56.     names = Object.keys(node).filter(
  57.       n =>
  58.         n !== "enclosingNode" && n !== "precedingNode" && n !== "followingNode"
  59.     );
  60.   } else {
  61.     return;
  62.   }
  63.  
  64.   if (!resultArray) {
  65.     Object.defineProperty(node, childNodesCacheKey, {
  66.       value: (resultArray = []),
  67.       enumerable: false
  68.     });
  69.   }
  70.  
  71.   for (
  72.     let i = 0,
  73.       nameCount = names.length;
  74.     i < nameCount;
  75.     ++i
  76.   ) {
  77.     getSortedChildNodes(node[names[i]], text, resultArray);
  78.   }
  79.  
  80.   return resultArray;
  81. }
  82.  
  83. // As efficiently as possible, decorate the comment object with
  84. // .precedingNode, .enclosingNode, and/or .followingNode properties, at
  85. // least one of which is guaranteed to be defined.
  86. function decorateComment(node, comment, text) {
  87.   const childNodes = getSortedChildNodes(node, text);
  88.   let precedingNode, followingNode;
  89.   // Time to dust off the old binary search robes and wizard hat.
  90.   let left = 0,
  91.     right = childNodes.length;
  92.   while (left < right) {
  93.     const middle = (left + right) >> 1;
  94.     const child = childNodes[middle];
  95.  
  96.     if (
  97.       locStart(child) - locStart(comment) <= 0 &&
  98.       locEnd(comment) - locEnd(child) <= 0
  99.     ) {
  100.       // The comment is completely contained by this child node.
  101.       comment.enclosingNode = child;
  102.  
  103.       decorateComment(child, comment, text);
  104.       return; // Abandon the binary search at this level.
  105.     }
  106.  
  107.     if (locEnd(child) - locStart(comment) <= 0) {
  108.       // This child node falls completely before the comment.
  109.       // Because we will never consider this node or any nodes
  110.       // before it again, this node must be the closest preceding
  111.       // node we have encountered so far.
  112.       precedingNode = child;
  113.       left = middle + 1;
  114.       continue;
  115.     }
  116.  
  117.     if (locEnd(comment) - locStart(child) <= 0) {
  118.       // This child node falls completely after the comment.
  119.       // Because we will never consider this node or any nodes after
  120.       // it again, this node must be the closest following node we
  121.       // have encountered so far.
  122.       followingNode = child;
  123.       right = middle;
  124.       continue;
  125.     }
  126.  
  127.     throw new Error("Comment location overlaps with node location");
  128.   }
  129.  
  130.   // We don't want comments inside of different expressions inside of the same
  131.   // template literal to move to another expression.
  132.   if (
  133.     comment.enclosingNode &&
  134.     comment.enclosingNode.type === "TemplateLiteral"
  135.   ) {
  136.     const quasis = comment.enclosingNode.quasis;
  137.     const commentIndex = findExpressionIndexForComment(quasis, comment);
  138.  
  139.     if (
  140.       precedingNode &&
  141.       findExpressionIndexForComment(quasis, precedingNode) !== commentIndex
  142.     ) {
  143.       precedingNode = null;
  144.     }
  145.     if (
  146.       followingNode &&
  147.       findExpressionIndexForComment(quasis, followingNode) !== commentIndex
  148.     ) {
  149.       followingNode = null;
  150.     }
  151.   }
  152.  
  153.   if (precedingNode) {
  154.     comment.precedingNode = precedingNode;
  155.   }
  156.  
  157.   if (followingNode) {
  158.     comment.followingNode = followingNode;
  159.   }
  160. }
  161.  
  162. function attach(comments, ast, text) {
  163.   if (!Array.isArray(comments)) {
  164.     return;
  165.   }
  166.  
  167.   const tiesToBreak = [];
  168.  
  169.   comments.forEach((comment, i) => {
  170.     decorateComment(ast, comment, text);
  171.  
  172.     const precedingNode = comment.precedingNode;
  173.     const enclosingNode = comment.enclosingNode;
  174.     const followingNode = comment.followingNode;
  175.  
  176.     const isLastComment = comments.length - 1 === i;
  177.  
  178.     if (util.hasNewline(text, locStart(comment), { backwards: true })) {
  179.       // If a comment exists on its own line, prefer a leading comment.
  180.       // We also need to check if it's the first line of the file.
  181.       if (
  182.         handleLastFunctionArgComments(
  183.           text,
  184.           precedingNode,
  185.           enclosingNode,
  186.           followingNode,
  187.           comment
  188.         ) ||
  189.         handleMemberExpressionComments(enclosingNode, followingNode, comment) ||
  190.         handleIfStatementComments(
  191.           text,
  192.           precedingNode,
  193.           enclosingNode,
  194.           followingNode,
  195.           comment
  196.         ) ||
  197.         handleTryStatementComments(enclosingNode, followingNode, comment) ||
  198.         handleClassComments(enclosingNode, comment) ||
  199.         handleImportSpecifierComments(enclosingNode, comment) ||
  200.         handleObjectPropertyComments(enclosingNode, comment) ||
  201.         handleForComments(enclosingNode, precedingNode, comment) ||
  202.         handleUnionTypeComments(
  203.           precedingNode,
  204.           enclosingNode,
  205.           followingNode,
  206.           comment
  207.         ) ||
  208.         handleOnlyComments(enclosingNode, ast, comment, isLastComment) ||
  209.         handleImportDeclarationComments(
  210.           text,
  211.           enclosingNode,
  212.           precedingNode,
  213.           comment
  214.         ) ||
  215.         handleAssignmentPatternComments(enclosingNode, comment)
  216.       ) {
  217.         // We're good
  218.       } else if (followingNode) {
  219.         // Always a leading comment.
  220.         addLeadingComment(followingNode, comment);
  221.       } else if (precedingNode) {
  222.         addTrailingComment(precedingNode, comment);
  223.       } else if (enclosingNode) {
  224.         addDanglingComment(enclosingNode, comment);
  225.       } else {
  226.         // There are no nodes, let's attach it to the root of the ast
  227.         addDanglingComment(ast, comment);
  228.       }
  229.     } else if (util.hasNewline(text, locEnd(comment))) {
  230.       if (
  231.         handleLastFunctionArgComments(
  232.           text,
  233.           precedingNode,
  234.           enclosingNode,
  235.           followingNode,
  236.           comment
  237.         ) ||
  238.         handleConditionalExpressionComments(
  239.           enclosingNode,
  240.           precedingNode,
  241.           followingNode,
  242.           comment,
  243.           text
  244.         ) ||
  245.         handleImportSpecifierComments(enclosingNode, comment) ||
  246.         handleIfStatementComments(
  247.           text,
  248.           precedingNode,
  249.           enclosingNode,
  250.           followingNode,
  251.           comment
  252.         ) ||
  253.         handleClassComments(enclosingNode, comment) ||
  254.         handleLabeledStatementComments(enclosingNode, comment) ||
  255.         handleCallExpressionComments(precedingNode, enclosingNode, comment) ||
  256.         handlePropertyComments(enclosingNode, comment) ||
  257.         handleExportNamedDeclarationComments(enclosingNode, comment) ||
  258.         handleOnlyComments(enclosingNode, ast, comment, isLastComment) ||
  259.         handleClassMethodComments(enclosingNode, comment) ||
  260.         handleTypeAliasComments(enclosingNode, followingNode, comment) ||
  261.         handleVariableDeclaratorComments(enclosingNode, followingNode, comment)
  262.       ) {
  263.         // We're good
  264.       } else if (precedingNode) {
  265.         // There is content before this comment on the same line, but
  266.         // none after it, so prefer a trailing comment of the previous node.
  267.         addTrailingComment(precedingNode, comment);
  268.       } else if (followingNode) {
  269.         addLeadingComment(followingNode, comment);
  270.       } else if (enclosingNode) {
  271.         addDanglingComment(enclosingNode, comment);
  272.       } else {
  273.         // There are no nodes, let's attach it to the root of the ast
  274.         addDanglingComment(ast, comment);
  275.       }
  276.     } else {
  277.       if (
  278.         handleIfStatementComments(
  279.           text,
  280.           precedingNode,
  281.           enclosingNode,
  282.           followingNode,
  283.           comment
  284.         ) ||
  285.         handleObjectPropertyAssignment(enclosingNode, precedingNode, comment) ||
  286.         handleCommentInEmptyParens(text, enclosingNode, comment) ||
  287.         handleOnlyComments(enclosingNode, ast, comment, isLastComment)
  288.       ) {
  289.         // We're good
  290.       } else if (precedingNode && followingNode) {
  291.         // Otherwise, text exists both before and after the comment on
  292.         // the same line. If there is both a preceding and following
  293.         // node, use a tie-breaking algorithm to determine if it should
  294.         // be attached to the next or previous node. In the last case,
  295.         // simply attach the right node;
  296.         const tieCount = tiesToBreak.length;
  297.         if (tieCount > 0) {
  298.           const lastTie = tiesToBreak[tieCount - 1];
  299.           if (lastTie.followingNode !== comment.followingNode) {
  300.             breakTies(tiesToBreak, text);
  301.           }
  302.         }
  303.         tiesToBreak.push(comment);
  304.       } else if (precedingNode) {
  305.         addTrailingComment(precedingNode, comment);
  306.       } else if (followingNode) {
  307.         addLeadingComment(followingNode, comment);
  308.       } else if (enclosingNode) {
  309.         addDanglingComment(enclosingNode, comment);
  310.       } else {
  311.         // There are no nodes, let's attach it to the root of the ast
  312.         addDanglingComment(ast, comment);
  313.       }
  314.     }
  315.   });
  316.  
  317.   breakTies(tiesToBreak, text);
  318.  
  319.   comments.forEach(comment => {
  320.     // These node references were useful for breaking ties, but we
  321.     // don't need them anymore, and they create cycles in the AST that
  322.     // may lead to infinite recursion if we don't delete them here.
  323.     delete comment.precedingNode;
  324.     delete comment.enclosingNode;
  325.     delete comment.followingNode;
  326.   });
  327. }
  328.  
  329. function breakTies(tiesToBreak, text) {
  330.   const tieCount = tiesToBreak.length;
  331.   if (tieCount === 0) {
  332.     return;
  333.   }
  334.  
  335.   const precedingNode = tiesToBreak[0].precedingNode;
  336.   const followingNode = tiesToBreak[0].followingNode;
  337.   let gapEndPos = locStart(followingNode);
  338.  
  339.   // Iterate backwards through tiesToBreak, examining the gaps
  340.   // between the tied comments. In order to qualify as leading, a
  341.   // comment must be separated from followingNode by an unbroken series of
  342.   // whitespace-only gaps (or other comments).
  343.   let indexOfFirstLeadingComment;
  344.   for (
  345.     indexOfFirstLeadingComment = tieCount;
  346.     indexOfFirstLeadingComment > 0;
  347.     --indexOfFirstLeadingComment
  348.   ) {
  349.     const comment = tiesToBreak[indexOfFirstLeadingComment - 1];
  350.     assert.strictEqual(comment.precedingNode, precedingNode);
  351.     assert.strictEqual(comment.followingNode, followingNode);
  352.  
  353.     const gap = text.slice(locEnd(comment), gapEndPos);
  354.     if (/\S/.test(gap)) {
  355.       // The gap string contained something other than whitespace.
  356.       break;
  357.     }
  358.  
  359.     gapEndPos = locStart(comment);
  360.   }
  361.  
  362.   tiesToBreak.forEach((comment, i) => {
  363.     if (i < indexOfFirstLeadingComment) {
  364.       addTrailingComment(precedingNode, comment);
  365.     } else {
  366.       addLeadingComment(followingNode, comment);
  367.     }
  368.   });
  369.  
  370.   tiesToBreak.length = 0;
  371. }
  372.  
  373. function addCommentHelper(node, comment) {
  374.   const comments = node.comments || (node.comments = []);
  375.   comments.push(comment);
  376.   comment.printed = false;
  377. }
  378.  
  379. function addLeadingComment(node, comment) {
  380.   comment.leading = true;
  381.   comment.trailing = false;
  382.   addCommentHelper(node, comment);
  383. }
  384.  
  385. function addDanglingComment(node, comment) {
  386.   comment.leading = false;
  387.   comment.trailing = false;
  388.   addCommentHelper(node, comment);
  389. }
  390.  
  391. function addTrailingComment(node, comment) {
  392.   comment.leading = false;
  393.   comment.trailing = true;
  394.   addCommentHelper(node, comment);
  395. }
  396.  
  397. function addBlockStatementFirstComment(node, comment) {
  398.   const body = node.body.filter(n => n.type !== "EmptyStatement");
  399.   if (body.length === 0) {
  400.     addDanglingComment(node, comment);
  401.   } else {
  402.     addLeadingComment(body[0], comment);
  403.   }
  404. }
  405.  
  406. function addBlockOrNotComment(node, comment) {
  407.   if (node.type === "BlockStatement") {
  408.     addBlockStatementFirstComment(node, comment);
  409.   } else {
  410.     addLeadingComment(node, comment);
  411.   }
  412. }
  413.  
  414. // There are often comments before the else clause of if statements like
  415. //
  416. //   if (1) { ... }
  417. //   // comment
  418. //   else { ... }
  419. //
  420. // They are being attached as leading comments of the BlockExpression which
  421. // is not well printed. What we want is to instead move the comment inside
  422. // of the block and make it leadingComment of the first element of the block
  423. // or dangling comment of the block if there is nothing inside
  424. //
  425. //   if (1) { ... }
  426. //   else {
  427. //     // comment
  428. //     ...
  429. //   }
  430. function handleIfStatementComments(
  431.   text,
  432.   precedingNode,
  433.   enclosingNode,
  434.   followingNode,
  435.   comment
  436. ) {
  437.   if (
  438.     !enclosingNode ||
  439.     enclosingNode.type !== "IfStatement" ||
  440.     !followingNode
  441.   ) {
  442.     return false;
  443.   }
  444.  
  445.   // We unfortunately have no way using the AST or location of nodes to know
  446.   // if the comment is positioned before or after the condition parenthesis:
  447.   //   if (a /* comment */) {}
  448.   //   if (a) /* comment */ {}
  449.   // The only workaround I found is to look at the next character to see if
  450.   // it is a ).
  451.   if (getNextNonSpaceNonCommentCharacter(text, comment) === ")") {
  452.     addTrailingComment(precedingNode, comment);
  453.     return true;
  454.   }
  455.  
  456.   if (followingNode.type === "BlockStatement") {
  457.     addBlockStatementFirstComment(followingNode, comment);
  458.     return true;
  459.   }
  460.  
  461.   if (followingNode.type === "IfStatement") {
  462.     addBlockOrNotComment(followingNode.consequent, comment);
  463.     return true;
  464.   }
  465.  
  466.   return false;
  467. }
  468.  
  469. // Same as IfStatement but for TryStatement
  470. function handleTryStatementComments(enclosingNode, followingNode, comment) {
  471.   if (
  472.     !enclosingNode ||
  473.     enclosingNode.type !== "TryStatement" ||
  474.     !followingNode
  475.   ) {
  476.     return false;
  477.   }
  478.  
  479.   if (followingNode.type === "BlockStatement") {
  480.     addBlockStatementFirstComment(followingNode, comment);
  481.     return true;
  482.   }
  483.  
  484.   if (followingNode.type === "TryStatement") {
  485.     addBlockOrNotComment(followingNode.finalizer, comment);
  486.     return true;
  487.   }
  488.  
  489.   if (followingNode.type === "CatchClause") {
  490.     addBlockOrNotComment(followingNode.body, comment);
  491.     return true;
  492.   }
  493.  
  494.   return false;
  495. }
  496.  
  497. function handleMemberExpressionComments(enclosingNode, followingNode, comment) {
  498.   if (
  499.     enclosingNode &&
  500.     enclosingNode.type === "MemberExpression" &&
  501.     followingNode &&
  502.     followingNode.type === "Identifier"
  503.   ) {
  504.     addLeadingComment(enclosingNode, comment);
  505.     return true;
  506.   }
  507.  
  508.   return false;
  509. }
  510.  
  511. function handleConditionalExpressionComments(
  512.   enclosingNode,
  513.   precedingNode,
  514.   followingNode,
  515.   comment,
  516.   text
  517. ) {
  518.   const isSameLineAsPrecedingNode =
  519.     precedingNode &&
  520.     !util.hasNewlineInRange(text, locEnd(precedingNode), locStart(comment));
  521.  
  522.   if (
  523.     (!precedingNode || !isSameLineAsPrecedingNode) &&
  524.     enclosingNode &&
  525.     enclosingNode.type === "ConditionalExpression" &&
  526.     followingNode
  527.   ) {
  528.     addLeadingComment(followingNode, comment);
  529.     return true;
  530.   }
  531.   return false;
  532. }
  533.  
  534. function handleObjectPropertyAssignment(enclosingNode, precedingNode, comment) {
  535.   if (
  536.     enclosingNode &&
  537.     (enclosingNode.type === "ObjectProperty" ||
  538.       enclosingNode.type === "Property") &&
  539.     enclosingNode.shorthand &&
  540.     enclosingNode.key === precedingNode &&
  541.     enclosingNode.value.type === "AssignmentPattern"
  542.   ) {
  543.     addTrailingComment(enclosingNode.value.left, comment);
  544.     return true;
  545.   }
  546.   return false;
  547. }
  548.  
  549. function handleCommentInEmptyParens(text, enclosingNode, comment) {
  550.   if (getNextNonSpaceNonCommentCharacter(text, comment) !== ")") {
  551.     return false;
  552.   }
  553.  
  554.   // Only add dangling comments to fix the case when no params are present,
  555.   // i.e. a function without any argument.
  556.   if (
  557.     enclosingNode &&
  558.     (((enclosingNode.type === "FunctionDeclaration" ||
  559.       enclosingNode.type === "FunctionExpression" ||
  560.       enclosingNode.type === "ArrowFunctionExpression" ||
  561.       enclosingNode.type === "ClassMethod" ||
  562.       enclosingNode.type === "ObjectMethod") &&
  563.       enclosingNode.params.length === 0) ||
  564.       (enclosingNode.type === "CallExpression" &&
  565.         enclosingNode.arguments.length === 0))
  566.   ) {
  567.     addDanglingComment(enclosingNode, comment);
  568.     return true;
  569.   }
  570.   if (
  571.     enclosingNode &&
  572.     (enclosingNode.type === "MethodDefinition" &&
  573.       enclosingNode.value.params.length === 0)
  574.   ) {
  575.     addDanglingComment(enclosingNode.value, comment);
  576.     return true;
  577.   }
  578.   return false;
  579. }
  580.  
  581. function handleLastFunctionArgComments(
  582.   text,
  583.   precedingNode,
  584.   enclosingNode,
  585.   followingNode,
  586.   comment
  587. ) {
  588.   // Type definitions functions
  589.   if (
  590.     precedingNode &&
  591.     precedingNode.type === "FunctionTypeParam" &&
  592.     enclosingNode &&
  593.     enclosingNode.type === "FunctionTypeAnnotation" &&
  594.     followingNode &&
  595.     followingNode.type !== "FunctionTypeParam"
  596.   ) {
  597.     addTrailingComment(precedingNode, comment);
  598.     return true;
  599.   }
  600.  
  601.   // Real functions
  602.   if (
  603.     precedingNode &&
  604.     (precedingNode.type === "Identifier" ||
  605.       precedingNode.type === "AssignmentPattern") &&
  606.     enclosingNode &&
  607.     (enclosingNode.type === "ArrowFunctionExpression" ||
  608.       enclosingNode.type === "FunctionExpression" ||
  609.       enclosingNode.type === "FunctionDeclaration" ||
  610.       enclosingNode.type === "ObjectMethod" ||
  611.       enclosingNode.type === "ClassMethod") &&
  612.     getNextNonSpaceNonCommentCharacter(text, comment) === ")"
  613.   ) {
  614.     addTrailingComment(precedingNode, comment);
  615.     return true;
  616.   }
  617.   return false;
  618. }
  619.  
  620. function handleClassComments(enclosingNode, comment) {
  621.   if (
  622.     enclosingNode &&
  623.     (enclosingNode.type === "ClassDeclaration" ||
  624.       enclosingNode.type === "ClassExpression")
  625.   ) {
  626.     addLeadingComment(enclosingNode, comment);
  627.     return true;
  628.   }
  629.   return false;
  630. }
  631.  
  632. function handleImportSpecifierComments(enclosingNode, comment) {
  633.   if (enclosingNode && enclosingNode.type === "ImportSpecifier") {
  634.     addLeadingComment(enclosingNode, comment);
  635.     return true;
  636.   }
  637.   return false;
  638. }
  639.  
  640. function handleObjectPropertyComments(enclosingNode, comment) {
  641.   if (enclosingNode && enclosingNode.type === "ObjectProperty") {
  642.     addLeadingComment(enclosingNode, comment);
  643.     return true;
  644.   }
  645.   return false;
  646. }
  647.  
  648. function handleLabeledStatementComments(enclosingNode, comment) {
  649.   if (enclosingNode && enclosingNode.type === "LabeledStatement") {
  650.     addLeadingComment(enclosingNode, comment);
  651.     return true;
  652.   }
  653.   return false;
  654. }
  655.  
  656. function handleCallExpressionComments(precedingNode, enclosingNode, comment) {
  657.   if (
  658.     enclosingNode &&
  659.     enclosingNode.type === "CallExpression" &&
  660.     precedingNode &&
  661.     enclosingNode.callee === precedingNode &&
  662.     enclosingNode.arguments.length > 0
  663.   ) {
  664.     addLeadingComment(enclosingNode.arguments[0], comment);
  665.     return true;
  666.   }
  667.   return false;
  668. }
  669.  
  670. function handleUnionTypeComments(
  671.   precedingNode,
  672.   enclosingNode,
  673.   followingNode,
  674.   comment
  675. ) {
  676.   if (
  677.     enclosingNode &&
  678.     (enclosingNode.type === "UnionTypeAnnotation" ||
  679.       enclosingNode.type === "TSUnionType")
  680.   ) {
  681.     addTrailingComment(precedingNode, comment);
  682.     return true;
  683.   }
  684.   return false;
  685. }
  686.  
  687. function handlePropertyComments(enclosingNode, comment) {
  688.   if (
  689.     enclosingNode &&
  690.     (enclosingNode.type === "Property" ||
  691.       enclosingNode.type === "ObjectProperty")
  692.   ) {
  693.     addLeadingComment(enclosingNode, comment);
  694.     return true;
  695.   }
  696.   return false;
  697. }
  698.  
  699. function handleExportNamedDeclarationComments(enclosingNode, comment) {
  700.   if (enclosingNode && enclosingNode.type === "ExportNamedDeclaration") {
  701.     addLeadingComment(enclosingNode, comment);
  702.     return true;
  703.   }
  704.   return false;
  705. }
  706.  
  707. function handleOnlyComments(enclosingNode, ast, comment, isLastComment) {
  708.   // With Flow the enclosingNode is undefined so use the AST instead.
  709.   if (ast && ast.body && ast.body.length === 0) {
  710.     if (isLastComment) {
  711.       addDanglingComment(ast, comment);
  712.     } else {
  713.       addLeadingComment(ast, comment);
  714.     }
  715.     return true;
  716.   } else if (
  717.     enclosingNode &&
  718.     enclosingNode.type === "Program" &&
  719.     enclosingNode.body.length === 0 &&
  720.     enclosingNode.directives &&
  721.     enclosingNode.directives.length === 0
  722.   ) {
  723.     if (isLastComment) {
  724.       addDanglingComment(enclosingNode, comment);
  725.     } else {
  726.       addLeadingComment(enclosingNode, comment);
  727.     }
  728.     return true;
  729.   }
  730.   return false;
  731. }
  732.  
  733. function handleForComments(enclosingNode, precedingNode, comment) {
  734.   if (
  735.     enclosingNode &&
  736.     (enclosingNode.type === "ForInStatement" ||
  737.       enclosingNode.type === "ForOfStatement")
  738.   ) {
  739.     addLeadingComment(enclosingNode, comment);
  740.     return true;
  741.   }
  742.   return false;
  743. }
  744.  
  745. function handleImportDeclarationComments(
  746.   text,
  747.   enclosingNode,
  748.   precedingNode,
  749.   comment
  750. ) {
  751.   if (
  752.     precedingNode &&
  753.     enclosingNode &&
  754.     enclosingNode.type === "ImportDeclaration" &&
  755.     util.hasNewline(text, util.locEnd(comment))
  756.   ) {
  757.     addTrailingComment(precedingNode, comment);
  758.     return true;
  759.   }
  760.   return false;
  761. }
  762.  
  763. function handleAssignmentPatternComments(enclosingNode, comment) {
  764.   if (enclosingNode && enclosingNode.type === "AssignmentPattern") {
  765.     addLeadingComment(enclosingNode, comment);
  766.     return true;
  767.   }
  768.   return false;
  769. }
  770.  
  771. function handleClassMethodComments(enclosingNode, comment) {
  772.   if (enclosingNode && enclosingNode.type === "ClassMethod") {
  773.     addTrailingComment(enclosingNode, comment);
  774.     return true;
  775.   }
  776.   return false;
  777. }
  778.  
  779. function handleTypeAliasComments(enclosingNode, followingNode, comment) {
  780.   if (enclosingNode && enclosingNode.type === "TypeAlias") {
  781.     addLeadingComment(enclosingNode, comment);
  782.     return true;
  783.   }
  784.   return false;
  785. }
  786.  
  787. function handleVariableDeclaratorComments(
  788.   enclosingNode,
  789.   followingNode,
  790.   comment
  791. ) {
  792.   if (
  793.     enclosingNode &&
  794.     enclosingNode.type === "VariableDeclarator" &&
  795.     followingNode &&
  796.     (followingNode.type === "ObjectExpression" ||
  797.       followingNode.type === "ArrayExpression")
  798.   ) {
  799.     addLeadingComment(followingNode, comment);
  800.     return true;
  801.   }
  802.   return false;
  803. }
  804.  
  805. function printComment(commentPath, options) {
  806.   const comment = commentPath.getValue();
  807.   comment.printed = true;
  808.  
  809.   switch (comment.type) {
  810.     case "CommentBlock":
  811.     case "Block":
  812.       return "/*" + comment.value + "*/";
  813.     case "CommentLine":
  814.     case "Line":
  815.       // Print shebangs with the proper comment characters
  816.       if (options.originalText.slice(util.locStart(comment)).startsWith("#!")) {
  817.         return "#!" + comment.value;
  818.       }
  819.       return "//" + comment.value;
  820.     default:
  821.       throw new Error("Not a comment: " + JSON.stringify(comment));
  822.   }
  823. }
  824.  
  825. function findExpressionIndexForComment(quasis, comment) {
  826.   const startPos = locStart(comment) - 1;
  827.  
  828.   for (let i = 1; i < quasis.length; ++i) {
  829.     if (startPos < getQuasiRange(quasis[i]).start) {
  830.       return i - 1;
  831.     }
  832.   }
  833.  
  834.   // We haven't found it, it probably means that some of the locations are off.
  835.   // Let's just return the first one.
  836.   return 0;
  837. }
  838.  
  839. function getQuasiRange(expr) {
  840.   if (expr.start !== undefined) {
  841.     // Babylon
  842.     return { start: expr.start, end: expr.end };
  843.   }
  844.   // Flow
  845.   return { start: expr.range[0], end: expr.range[1] };
  846. }
  847.  
  848. function printLeadingComment(commentPath, print, options) {
  849.   const comment = commentPath.getValue();
  850.   const contents = printComment(commentPath, options);
  851.   if (!contents) {
  852.     return "";
  853.   }
  854.   const isBlock = util.isBlockComment(comment);
  855.  
  856.   // Leading block comments should see if they need to stay on the
  857.   // same line or not.
  858.   if (isBlock) {
  859.     return concat([
  860.       contents,
  861.       util.hasNewline(options.originalText, locEnd(comment)) ? hardline : " "
  862.     ]);
  863.   }
  864.  
  865.   return concat([contents, hardline]);
  866. }
  867.  
  868. function printTrailingComment(commentPath, print, options) {
  869.   const comment = commentPath.getValue();
  870.   const contents = printComment(commentPath, options);
  871.   if (!contents) {
  872.     return "";
  873.   }
  874.   const isBlock = util.isBlockComment(comment);
  875.  
  876.   if (
  877.     util.hasNewline(options.originalText, locStart(comment), {
  878.       backwards: true
  879.     })
  880.   ) {
  881.     // This allows comments at the end of nested structures:
  882.     // {
  883.     //   x: 1,
  884.     //   y: 2
  885.     //   // A comment
  886.     // }
  887.     // Those kinds of comments are almost always leading comments, but
  888.     // here it doesn't go "outside" the block and turns it into a
  889.     // trailing comment for `2`. We can simulate the above by checking
  890.     // if this a comment on its own line; normal trailing comments are
  891.     // always at the end of another expression.
  892.  
  893.     const isLineBeforeEmpty = util.isPreviousLineEmpty(
  894.       options.originalText,
  895.       comment
  896.     );
  897.  
  898.     return lineSuffix(
  899.       concat([hardline, isLineBeforeEmpty ? hardline : "", contents])
  900.     );
  901.   } else if (isBlock) {
  902.     // Trailing block comments never need a newline
  903.     return concat([" ", contents]);
  904.   }
  905.  
  906.   return concat([lineSuffix(" " + contents), !isBlock ? breakParent : ""]);
  907. }
  908.  
  909. function printDanglingComments(path, options, sameIndent) {
  910.   const parts = [];
  911.   const node = path.getValue();
  912.  
  913.   if (!node || !node.comments) {
  914.     return "";
  915.   }
  916.  
  917.   path.each(commentPath => {
  918.     const comment = commentPath.getValue();
  919.     if (comment && !comment.leading && !comment.trailing) {
  920.       parts.push(printComment(commentPath, options));
  921.     }
  922.   }, "comments");
  923.  
  924.   if (parts.length === 0) {
  925.     return "";
  926.   }
  927.  
  928.   if (sameIndent) {
  929.     return join(hardline, parts);
  930.   }
  931.   return indent(concat([hardline, join(hardline, parts)]));
  932. }
  933.  
  934. function prependCursorPlaceholder(path, options, printed) {
  935.   if (path.getNode() === options.cursorNode) {
  936.     return concat([cursor, printed]);
  937.   }
  938.   return printed;
  939. }
  940.  
  941. function printComments(path, print, options, needsSemi) {
  942.   const value = path.getValue();
  943.   const printed = print(path);
  944.   const comments = value && value.comments;
  945.  
  946.   if (!comments || comments.length === 0) {
  947.     return prependCursorPlaceholder(path, options, printed);
  948.   }
  949.  
  950.   const leadingParts = [];
  951.   const trailingParts = [needsSemi ? ";" : "", printed];
  952.  
  953.   path.each(commentPath => {
  954.     const comment = commentPath.getValue();
  955.     const leading = comment.leading;
  956.     const trailing = comment.trailing;
  957.  
  958.     if (leading) {
  959.       const contents = printLeadingComment(commentPath, print, options);
  960.       if (!contents) {
  961.         return;
  962.       }
  963.       leadingParts.push(contents);
  964.  
  965.       const text = options.originalText;
  966.       if (util.hasNewline(text, util.skipNewline(text, util.locEnd(comment)))) {
  967.         leadingParts.push(hardline);
  968.       }
  969.     } else if (trailing) {
  970.       trailingParts.push(printTrailingComment(commentPath, print, options));
  971.     }
  972.   }, "comments");
  973.  
  974.   return prependCursorPlaceholder(
  975.     path,
  976.     options,
  977.     concat(leadingParts.concat(trailingParts))
  978.   );
  979. }
  980.  
  981. module.exports = {
  982.   attach,
  983.   printComments,
  984.   printDanglingComments,
  985.   getSortedChildNodes
  986. };
  987.  
downloadcomments.js Source code - Download prettier Source code
Related Source Codes/Software:
storybook - 2017-06-07
ionicons - The premium icon font for Ionic ... 2017-06-07
AsyncDisplayKit - Smooth asynchronous user interfaces for iOS apps. ... 2017-06-07
lottie-android - Render After Effects animations natively on Androi... 2017-06-07
parse-server - Parse-compatible API server module for Node/Expres... 2017-06-07
inferno - An extremely fast, React-like JavaScript library f... 2017-06-08
guetzli - Perceptual JPEG encoder 2017-06-08
cs-video-courses - List of Computer Science courses with video lectur... 2017-06-08
interviews - Everything you need to know to get the job. 2017-06-08
prepack - Prepack is a partial evaluator for JavaScript. Pre... 2017-06-08
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top