Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- const MODE_BREAK = 1;
- const MODE_FLAT = 2;
- function fits(next, restCommands, width) {
- let restIdx = restCommands.length;
- const cmds = [ next ];
- while (width >= 0) {
- if (cmds.length === 0) {
- if (restIdx === 0) {
- return true;
- } else {
- cmds.push(restCommands[restIdx - 1]);
- restIdx--;
- continue;
- }
- }
- const x = cmds.pop();
- const ind = x[0];
- const mode = x[1];
- const doc = x[2];
- if (typeof doc === "string") {
- width -= doc.length;
- } else {
- switch (doc.type) {
- case "concat":
- for (var i = doc.parts.length - 1; i >= 0; i--) {
- cmds.push([ ind, mode, doc.parts[i] ]);
- }
- break;
- case "indent":
- cmds.push([ ind + doc.n, mode, doc.contents ]);
- break;
- case "group":
- cmds.push([ ind, doc.break ? MODE_BREAK : mode, doc.contents ]);
- break;
- case "if-break":
- if (mode === MODE_BREAK) {
- if (doc.breakContents) {
- cmds.push([ ind, mode, doc.breakContents ]);
- }
- }
- if (mode === MODE_FLAT) {
- if (doc.flatContents) {
- cmds.push([ ind, mode, doc.flatContents ]);
- }
- }
- break;
- case "line":
- switch (mode) {
- // fallthrough
- case MODE_FLAT:
- if (!doc.hard) {
- if (!doc.soft) {
- width -= 1;
- }
- break;
- }
- case MODE_BREAK:
- return true;
- }
- break;
- }
- }
- }
- return false;
- }
- function printDocToString(w, doc) {
- let pos = 0;
- // cmds is basically a stack. We've turned a recursive call into a
- // while loop which is much faster. The while loop below adds new
- // cmds to the array instead of recursively calling `print`.
- let cmds = [ [ 0, MODE_BREAK, doc ] ];
- let out = [];
- let shouldRemeasure = false;
- while (cmds.length !== 0) {
- const x = cmds.pop();
- const ind = x[0];
- const mode = x[1];
- const doc = x[2];
- if (typeof doc === "string") {
- out.push(doc);
- pos += doc.length;
- } else {
- switch (doc.type) {
- case "concat":
- for (var i = doc.parts.length - 1; i >= 0; i--) {
- cmds.push([ ind, mode, doc.parts[i] ]);
- }
- break;
- case "indent":
- cmds.push([ ind + doc.n, mode, doc.contents ]);
- break;
- case "group":
- switch (mode) {
- // fallthrough
- case MODE_FLAT:
- if (!shouldRemeasure) {
- cmds.push([
- ind,
- doc.break ? MODE_BREAK : MODE_FLAT,
- doc.contents
- ]);
- break;
- }
- case MODE_BREAK:
- shouldRemeasure = false;
- const next = [ ind, MODE_FLAT, doc.contents ];
- let rem = w - pos;
- if (!doc.break && fits(next, cmds, rem)) {
- cmds.push(next);
- } else {
- // Expanded states are a rare case where a document
- // can manually provide multiple representations of
- // itself. It provides an array of documents
- // going from the least expanded (most flattened)
- // representation first to the most expanded. If a
- // group has these, we need to manually go through
- // these states and find the first one that fits.
- if (doc.expandedStates) {
- const mostExpanded = doc.expandedStates[doc.expandedStates.length -
- 1];
- if (doc.break) {
- cmds.push([ ind, MODE_BREAK, mostExpanded ]);
- break;
- } else {
- for (var i = 1; i < doc.expandedStates.length + 1; i++) {
- if (i >= doc.expandedStates.length) {
- cmds.push([ ind, MODE_BREAK, mostExpanded ]);
- break;
- } else {
- const state = doc.expandedStates[i];
- const cmd = [ ind, MODE_FLAT, state ];
- if (fits(cmd, cmds, rem)) {
- cmds.push(cmd);
- break;
- }
- }
- }
- }
- } else {
- cmds.push([ ind, MODE_BREAK, doc.contents ]);
- }
- }
- break;
- }
- break;
- case "if-break":
- if (mode === MODE_BREAK) {
- if (doc.breakContents) {
- cmds.push([ ind, mode, doc.breakContents ]);
- }
- }
- if (mode === MODE_FLAT) {
- if (doc.flatContents) {
- cmds.push([ ind, mode, doc.flatContents ]);
- }
- }
- break;
- case "line":
- switch (mode) {
- // fallthrough
- case MODE_FLAT:
- if (!doc.hard) {
- if (!doc.soft) {
- out.push(" ");
- pos += 1;
- }
- break;
- } else {
- // This line was forced into the output even if we
- // were in flattened mode, so we need to tell the next
- // group that no matter what, it needs to remeasure
- // because the previous measurement didn't accurately
- // capture the entire expression (this is necessary
- // for nested groups)
- shouldRemeasure = true;
- }
- case MODE_BREAK:
- if (doc.literal) {
- out.push("\n");
- pos = 0;
- } else {
- if (out.length > 0) {
- // Trim whitespace at the end of line
- out[out.length - 1] = out[out.length - 1].replace(
- /[^\S\n]*$/,
- ""
- );
- }
- out.push("\n" + " ".repeat(ind));
- pos = ind;
- }
- break;
- }
- break;
- default:
- }
- }
- }
- return out.join("");
- }
- module.exports = {
- printDocToString,
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement