BVB Source Codes

prettier Show doc-printer.js Source code

Return Download prettier: download doc-printer.js Source code - Download prettier Source code - Type:.js
  1. "use strict";
  2.  
  3. const docBuilders = require("./doc-builders");
  4. const concat = docBuilders.concat;
  5. const fill = docBuilders.fill;
  6. const cursor = docBuilders.cursor;
  7.  
  8. const MODE_BREAK = 1;
  9. const MODE_FLAT = 2;
  10.  
  11. function rootIndent() {
  12.   return {
  13.     indent: 0,
  14.     align: {
  15.       spaces: 0,
  16.       tabs: 0
  17.     }
  18.   };
  19. }
  20.  
  21. function makeIndent(ind) {
  22.   return {
  23.     indent: ind.indent + 1,
  24.     align: ind.align
  25.   };
  26. }
  27.  
  28. function makeAlign(ind, n) {
  29.   if (n === -Infinity) {
  30.     return {
  31.       indent: 0,
  32.       align: {
  33.         spaces: 0,
  34.         tabs: 0
  35.       }
  36.     };
  37.   }
  38.  
  39.   return {
  40.     indent: ind.indent,
  41.     align: {
  42.       spaces: ind.align.spaces + n,
  43.       tabs: ind.align.tabs + (n ? 1 : 0)
  44.     }
  45.   };
  46. }
  47.  
  48. function fits(next, restCommands, width, mustBeFlat) {
  49.   let restIdx = restCommands.length;
  50.   const cmds = [next];
  51.   while (width >= 0) {
  52.     if (cmds.length === 0) {
  53.       if (restIdx === 0) {
  54.         return true;
  55.       } else {
  56.         cmds.push(restCommands[restIdx - 1]);
  57.  
  58.         restIdx--;
  59.  
  60.         continue;
  61.       }
  62.     }
  63.  
  64.     const x = cmds.pop();
  65.     const ind = x[0];
  66.     const mode = x[1];
  67.     const doc = x[2];
  68.  
  69.     if (typeof doc === "string") {
  70.       width -= doc.length;
  71.     } else {
  72.       switch (doc.type) {
  73.         case "concat":
  74.           for (let i = doc.parts.length - 1; i >= 0; i--) {
  75.             cmds.push([ind, mode, doc.parts[i]]);
  76.           }
  77.  
  78.           break;
  79.         case "indent":
  80.           cmds.push([makeIndent(ind), mode, doc.contents]);
  81.  
  82.           break;
  83.         case "align":
  84.           cmds.push([makeAlign(ind, doc.n), mode, doc.contents]);
  85.  
  86.           break;
  87.         case "group":
  88.           if (mustBeFlat && doc.break) {
  89.             return false;
  90.           }
  91.           cmds.push([ind, doc.break ? MODE_BREAK : mode, doc.contents]);
  92.  
  93.           break;
  94.         case "fill":
  95.           for (let i = doc.parts.length - 1; i >= 0; i--) {
  96.             cmds.push([ind, mode, doc.parts[i]]);
  97.           }
  98.  
  99.           break;
  100.         case "if-break":
  101.           if (mode === MODE_BREAK) {
  102.             if (doc.breakContents) {
  103.               cmds.push([ind, mode, doc.breakContents]);
  104.             }
  105.           }
  106.           if (mode === MODE_FLAT) {
  107.             if (doc.flatContents) {
  108.               cmds.push([ind, mode, doc.flatContents]);
  109.             }
  110.           }
  111.  
  112.           break;
  113.         case "line":
  114.           switch (mode) {
  115.             // fallthrough
  116.             case MODE_FLAT:
  117.               if (!doc.hard) {
  118.                 if (!doc.soft) {
  119.                   width -= 1;
  120.                 }
  121.  
  122.                 break;
  123.               }
  124.               return true;
  125.  
  126.             case MODE_BREAK:
  127.               return true;
  128.           }
  129.           break;
  130.       }
  131.     }
  132.   }
  133.   return false;
  134. }
  135.  
  136. function printDocToString(doc, options) {
  137.   const width = options.printWidth;
  138.   const newLine = options.newLine || "\n";
  139.   let pos = 0;
  140.   // cmds is basically a stack. We've turned a recursive call into a
  141.   // while loop which is much faster. The while loop below adds new
  142.   // cmds to the array instead of recursively calling `print`.
  143.   const cmds = [[rootIndent(), MODE_BREAK, doc]];
  144.   const out = [];
  145.   let shouldRemeasure = false;
  146.   let lineSuffix = [];
  147.  
  148.   while (cmds.length !== 0) {
  149.     const x = cmds.pop();
  150.     const ind = x[0];
  151.     const mode = x[1];
  152.     const doc = x[2];
  153.  
  154.     if (typeof doc === "string") {
  155.       out.push(doc);
  156.  
  157.       pos += doc.length;
  158.     } else {
  159.       switch (doc.type) {
  160.         case "cursor":
  161.           out.push(cursor.placeholder);
  162.  
  163.           break;
  164.         case "concat":
  165.           for (let i = doc.parts.length - 1; i >= 0; i--) {
  166.             cmds.push([ind, mode, doc.parts[i]]);
  167.           }
  168.  
  169.           break;
  170.         case "indent":
  171.           cmds.push([makeIndent(ind), mode, doc.contents]);
  172.  
  173.           break;
  174.         case "align":
  175.           cmds.push([makeAlign(ind, doc.n), mode, doc.contents]);
  176.  
  177.           break;
  178.         case "group":
  179.           switch (mode) {
  180.             case MODE_FLAT:
  181.               if (!shouldRemeasure) {
  182.                 cmds.push([
  183.                   ind,
  184.                   doc.break ? MODE_BREAK : MODE_FLAT,
  185.                   doc.contents
  186.                 ]);
  187.  
  188.                 break;
  189.               }
  190.             // fallthrough
  191.  
  192.             case MODE_BREAK: {
  193.               shouldRemeasure = false;
  194.  
  195.               const next = [ind, MODE_FLAT, doc.contents];
  196.               const rem = width - pos;
  197.  
  198.               if (!doc.break && fits(next, cmds, rem)) {
  199.                 cmds.push(next);
  200.               } else {
  201.                 // Expanded states are a rare case where a document
  202.                 // can manually provide multiple representations of
  203.                 // itself. It provides an array of documents
  204.                 // going from the least expanded (most flattened)
  205.                 // representation first to the most expanded. If a
  206.                 // group has these, we need to manually go through
  207.                 // these states and find the first one that fits.
  208.                 if (doc.expandedStates) {
  209.                   const mostExpanded =
  210.                     doc.expandedStates[doc.expandedStates.length - 1];
  211.  
  212.                   if (doc.break) {
  213.                     cmds.push([ind, MODE_BREAK, mostExpanded]);
  214.  
  215.                     break;
  216.                   } else {
  217.                     for (let i = 1; i < doc.expandedStates.length + 1; i++) {
  218.                       if (i >= doc.expandedStates.length) {
  219.                         cmds.push([ind, MODE_BREAK, mostExpanded]);
  220.  
  221.                         break;
  222.                       } else {
  223.                         const state = doc.expandedStates[i];
  224.                         const cmd = [ind, MODE_FLAT, state];
  225.  
  226.                         if (fits(cmd, cmds, rem)) {
  227.                           cmds.push(cmd);
  228.  
  229.                           break;
  230.                         }
  231.                       }
  232.                     }
  233.                   }
  234.                 } else {
  235.                   cmds.push([ind, MODE_BREAK, doc.contents]);
  236.                 }
  237.               }
  238.  
  239.               break;
  240.             }
  241.           }
  242.           break;
  243.         // Fills each line with as much code as possible before moving to a new
  244.         // line with the same indentation.
  245.         //
  246.         // Expects doc.parts to be an array of alternating content and
  247.         // whitespace. The whitespace contains the linebreaks.
  248.         //
  249.         // For example:
  250.         //   ["I", line, "love", line, "monkeys"]
  251.         // or
  252.         //   [{ type: group, ... }, softline, { type: group, ... }]
  253.         //
  254.         // It uses this parts structure to handle three main layout cases:
  255.         // * The first two content items fit on the same line without
  256.         //   breaking
  257.         //   -> output the first content item and the whitespace "flat".
  258.         // * Only the first content item fits on the line without breaking
  259.         //   -> output the first content item "flat" and the whitespace with
  260.         //   "break".
  261.         // * Neither content item fits on the line without breaking
  262.         //   -> output the first content item and the whitespace with "break".
  263.         case "fill": {
  264.           const rem = width - pos;
  265.  
  266.           const parts = doc.parts;
  267.           if (parts.length === 0) {
  268.             break;
  269.           }
  270.  
  271.           const content = parts[0];
  272.           const contentFlatCmd = [ind, MODE_FLAT, content];
  273.           const contentBreakCmd = [ind, MODE_BREAK, content];
  274.           const contentFits = fits(contentFlatCmd, [], width - rem, true);
  275.  
  276.           if (parts.length === 1) {
  277.             if (contentFits) {
  278.               cmds.push(contentFlatCmd);
  279.             } else {
  280.               cmds.push(contentBreakCmd);
  281.             }
  282.             break;
  283.           }
  284.  
  285.           const whitespace = parts[1];
  286.           const whitespaceFlatCmd = [ind, MODE_FLAT, whitespace];
  287.           const whitespaceBreakCmd = [ind, MODE_BREAK, whitespace];
  288.  
  289.           if (parts.length === 2) {
  290.             if (contentFits) {
  291.               cmds.push(whitespaceFlatCmd);
  292.               cmds.push(contentFlatCmd);
  293.             } else {
  294.               cmds.push(whitespaceBreakCmd);
  295.               cmds.push(contentBreakCmd);
  296.             }
  297.             break;
  298.           }
  299.  
  300.           const remaining = parts.slice(2);
  301.           const remainingCmd = [ind, mode, fill(remaining)];
  302.  
  303.           const secondContent = parts[2];
  304.           const firstAndSecondContentFlatCmd = [
  305.             ind,
  306.             MODE_FLAT,
  307.             concat([content, whitespace, secondContent])
  308.           ];
  309.           const firstAndSecondContentFits = fits(
  310.             firstAndSecondContentFlatCmd,
  311.             [],
  312.             rem,
  313.             true
  314.           );
  315.  
  316.           if (firstAndSecondContentFits) {
  317.             cmds.push(remainingCmd);
  318.             cmds.push(whitespaceFlatCmd);
  319.             cmds.push(contentFlatCmd);
  320.           } else if (contentFits) {
  321.             cmds.push(remainingCmd);
  322.             cmds.push(whitespaceBreakCmd);
  323.             cmds.push(contentFlatCmd);
  324.           } else {
  325.             cmds.push(remainingCmd);
  326.             cmds.push(whitespaceBreakCmd);
  327.             cmds.push(contentBreakCmd);
  328.           }
  329.           break;
  330.         }
  331.         case "if-break":
  332.           if (mode === MODE_BREAK) {
  333.             if (doc.breakContents) {
  334.               cmds.push([ind, mode, doc.breakContents]);
  335.             }
  336.           }
  337.           if (mode === MODE_FLAT) {
  338.             if (doc.flatContents) {
  339.               cmds.push([ind, mode, doc.flatContents]);
  340.             }
  341.           }
  342.  
  343.           break;
  344.         case "line-suffix":
  345.           lineSuffix.push([ind, mode, doc.contents]);
  346.           break;
  347.         case "line-suffix-boundary":
  348.           if (lineSuffix.length > 0) {
  349.             cmds.push([ind, mode, { type: "line", hard: true }]);
  350.           }
  351.           break;
  352.         case "line":
  353.           switch (mode) {
  354.             case MODE_FLAT:
  355.               if (!doc.hard) {
  356.                 if (!doc.soft) {
  357.                   out.push(" ");
  358.  
  359.                   pos += 1;
  360.                 }
  361.  
  362.                 break;
  363.               } else {
  364.                 // This line was forced into the output even if we
  365.                 // were in flattened mode, so we need to tell the next
  366.                 // group that no matter what, it needs to remeasure
  367.                 // because the previous measurement didn't accurately
  368.                 // capture the entire expression (this is necessary
  369.                 // for nested groups)
  370.                 shouldRemeasure = true;
  371.               }
  372.             // fallthrough
  373.  
  374.             case MODE_BREAK:
  375.               if (lineSuffix.length) {
  376.                 cmds.push([ind, mode, doc]);
  377.                 [].push.apply(cmds, lineSuffix.reverse());
  378.                 lineSuffix = [];
  379.                 break;
  380.               }
  381.  
  382.               if (doc.literal) {
  383.                 out.push(newLine);
  384.                 pos = 0;
  385.               } else {
  386.                 if (out.length > 0) {
  387.                   // Trim whitespace at the end of line
  388.                   while (
  389.                     out.length > 0 &&
  390.                     out[out.length - 1].match(/^[^\S\n]*$/)
  391.                   ) {
  392.                     out.pop();
  393.                   }
  394.  
  395.                   if (out.length) {
  396.                     out[out.length - 1] = out[out.length - 1].replace(
  397.                       /[^\S\n]*$/,
  398.                       ""
  399.                     );
  400.                   }
  401.                 }
  402.  
  403.                 const length = ind.indent * options.tabWidth + ind.align.spaces;
  404.                 const indentString = options.useTabs
  405.                   ? "\t".repeat(ind.indent + ind.align.tabs)
  406.                   : " ".repeat(length);
  407.                 out.push(newLine + indentString);
  408.                 pos = length;
  409.               }
  410.               break;
  411.           }
  412.           break;
  413.         default:
  414.       }
  415.     }
  416.   }
  417.  
  418.   const cursorPlaceholderIndex = out.indexOf(cursor.placeholder);
  419.   if (cursorPlaceholderIndex !== -1) {
  420.     const beforeCursor = out.slice(0, cursorPlaceholderIndex).join("");
  421.     const afterCursor = out.slice(cursorPlaceholderIndex + 1).join("");
  422.  
  423.     return {
  424.       formatted: beforeCursor + afterCursor,
  425.       cursor: beforeCursor.length
  426.     };
  427.   }
  428.  
  429.   return { formatted: out.join("") };
  430. }
  431.  
  432. module.exports = { printDocToString };
  433.  
downloaddoc-printer.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