Advertisement
Guest User

Untitled

a guest
Jan 19th, 2017
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.30 KB | None | 0 0
  1. "use strict";
  2.  
  3. const MODE_BREAK = 1;
  4. const MODE_FLAT = 2;
  5.  
  6. function fits(next, restCommands, width) {
  7. let restIdx = restCommands.length;
  8. const cmds = [ next ];
  9. while (width >= 0) {
  10. if (cmds.length === 0) {
  11. if (restIdx === 0) {
  12. return true;
  13. } else {
  14. cmds.push(restCommands[restIdx - 1]);
  15.  
  16. restIdx--;
  17.  
  18. continue;
  19. }
  20. }
  21.  
  22. const x = cmds.pop();
  23. const ind = x[0];
  24. const mode = x[1];
  25. const doc = x[2];
  26.  
  27. if (typeof doc === "string") {
  28. width -= doc.length;
  29. } else {
  30. switch (doc.type) {
  31. case "concat":
  32. for (var i = doc.parts.length - 1; i >= 0; i--) {
  33. cmds.push([ ind, mode, doc.parts[i] ]);
  34. }
  35.  
  36. break;
  37. case "indent":
  38. cmds.push([ ind + doc.n, mode, doc.contents ]);
  39.  
  40. break;
  41. case "group":
  42. cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]);
  43.  
  44. break;
  45. case "if-break":
  46. if (mode === MODE_BREAK) {
  47. if (doc.breakContents) {
  48. cmds.push([ ind, mode, doc.breakContents ]);
  49. }
  50. }
  51. if (mode === MODE_FLAT) {
  52. if (doc.flatContents) {
  53. cmds.push([ ind, mode, doc.flatContents ]);
  54. }
  55. }
  56.  
  57. break;
  58. case "line":
  59. switch (mode) {
  60. // fallthrough
  61. case MODE_FLAT:
  62. if (!doc.hard) {
  63. if (!doc.soft) {
  64. width -= 1;
  65. }
  66.  
  67. break;
  68. }
  69.  
  70. case MODE_BREAK:
  71. return true;
  72. }
  73. break;
  74. }
  75. }
  76. }
  77. return false;
  78. }
  79.  
  80. function printDocToString(w, doc) {
  81. let pos = 0;
  82. // cmds is basically a stack. We've turned a recursive call into a
  83. // while loop which is much faster. The while loop below adds new
  84. // cmds to the array instead of recursively calling `print`.
  85. let cmds = [ [ 0, MODE_BREAK, doc ] ];
  86. let out = [];
  87. let shouldRemeasure = false;
  88. while (cmds.length !== 0) {
  89. const x = cmds.pop();
  90. const ind = x[0];
  91. const mode = x[1];
  92. const doc = x[2];
  93.  
  94. if (typeof doc === "string") {
  95. out.push(doc);
  96.  
  97. pos += doc.length;
  98. } else {
  99. switch (doc.type) {
  100. case "concat":
  101. for (var i = doc.parts.length - 1; i >= 0; i--) {
  102. cmds.push([ ind, mode, doc.parts[i] ]);
  103. }
  104.  
  105. break;
  106. case "indent":
  107. cmds.push([ ind + doc.n, mode, doc.contents ]);
  108.  
  109. break;
  110. case "group":
  111. switch (mode) {
  112. // fallthrough
  113. case MODE_FLAT:
  114. if (!shouldRemeasure) {
  115. cmds.push([
  116. ind,
  117. doc.break ? MODE_BREAK : MODE_FLAT,
  118. doc.contents
  119. ]);
  120.  
  121. break;
  122. }
  123.  
  124. case MODE_BREAK:
  125. shouldRemeasure = false;
  126.  
  127. const next = [ ind, MODE_FLAT, doc.contents ];
  128. let rem = w - pos;
  129.  
  130. if (!doc.break && fits(next, cmds, rem)) {
  131. cmds.push(next);
  132. } else {
  133. // Expanded states are a rare case where a document
  134. // can manually provide multiple representations of
  135. // itself. It provides an array of documents
  136. // going from the least expanded (most flattened)
  137. // representation first to the most expanded. If a
  138. // group has these, we need to manually go through
  139. // these states and find the first one that fits.
  140. if (doc.expandedStates) {
  141. const mostExpanded = doc.expandedStates[doc.expandedStates.length -
  142. 1];
  143.  
  144. if (doc.break) {
  145. cmds.push([ ind, MODE_BREAK, mostExpanded ]);
  146.  
  147. break;
  148. } else {
  149. for (var i = 1; i < doc.expandedStates.length + 1; i++) {
  150. if (i >= doc.expandedStates.length) {
  151. cmds.push([ ind, MODE_BREAK, mostExpanded ]);
  152.  
  153. break;
  154. } else {
  155. const state = doc.expandedStates[i];
  156. const cmd = [ ind, MODE_FLAT, state ];
  157.  
  158. if (fits(cmd, cmds, rem)) {
  159. cmds.push(cmd);
  160.  
  161. break;
  162. }
  163. }
  164. }
  165. }
  166. } else {
  167. cmds.push([ ind, MODE_BREAK, doc.contents ]);
  168. }
  169. }
  170.  
  171. break;
  172. }
  173. break;
  174. case "if-break":
  175. if (mode === MODE_BREAK) {
  176. if (doc.breakContents) {
  177. cmds.push([ ind, mode, doc.breakContents ]);
  178. }
  179. }
  180. if (mode === MODE_FLAT) {
  181. if (doc.flatContents) {
  182. cmds.push([ ind, mode, doc.flatContents ]);
  183. }
  184. }
  185.  
  186. break;
  187. case "line":
  188. switch (mode) {
  189. // fallthrough
  190. case MODE_FLAT:
  191. if (!doc.hard) {
  192. if (!doc.soft) {
  193. out.push(" ");
  194.  
  195. pos += 1;
  196. }
  197.  
  198. break;
  199. } else {
  200. // This line was forced into the output even if we
  201. // were in flattened mode, so we need to tell the next
  202. // group that no matter what, it needs to remeasure
  203. // because the previous measurement didn't accurately
  204. // capture the entire expression (this is necessary
  205. // for nested groups)
  206. shouldRemeasure = true;
  207. }
  208.  
  209. case MODE_BREAK:
  210. if (doc.literal) {
  211. out.push("\n");
  212.  
  213. pos = 0;
  214. } else {
  215. if (out.length > 0) {
  216. // Trim whitespace at the end of line
  217. out[out.length - 1] = out[out.length - 1].replace(
  218. /[^\S\n]*$/,
  219. ""
  220. );
  221. }
  222.  
  223. out.push("\n" + " ".repeat(ind));
  224.  
  225. pos = ind;
  226. }
  227.  
  228. break;
  229. }
  230. break;
  231. default:
  232. }
  233. }
  234. }
  235. return out.join("");
  236. }
  237.  
  238. module.exports = {
  239. printDocToString,
  240. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement