prettier 1.2.4 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +351 -361
- data/README.md +11 -96
- data/node_modules/prettier/index.js +54 -54
- data/package.json +1 -2
- data/src/haml/embed.js +87 -0
- data/src/haml/nodes/comment.js +27 -0
- data/src/haml/nodes/doctype.js +34 -0
- data/src/haml/nodes/filter.js +16 -0
- data/src/haml/nodes/hamlComment.js +21 -0
- data/src/haml/nodes/plain.js +6 -0
- data/src/haml/nodes/root.js +8 -0
- data/src/haml/nodes/script.js +33 -0
- data/src/haml/nodes/silentScript.js +59 -0
- data/src/haml/nodes/tag.js +193 -0
- data/src/haml/parser.js +22 -0
- data/src/haml/parser.rb +138 -0
- data/src/haml/printer.js +28 -0
- data/src/parser/getLang.js +32 -0
- data/src/parser/getNetcat.js +50 -0
- data/src/parser/netcat.js +15 -0
- data/src/parser/parseSync.js +33 -0
- data/src/parser/requestParse.js +74 -0
- data/src/parser/server.rb +61 -0
- data/src/plugin.js +26 -4
- data/src/rbs/parser.js +39 -0
- data/src/rbs/parser.rb +94 -0
- data/src/rbs/printer.js +605 -0
- data/src/ruby/embed.js +54 -8
- data/src/ruby/nodes/args.js +20 -6
- data/src/ruby/nodes/arrays.js +36 -33
- data/src/ruby/nodes/calls.js +12 -43
- data/src/ruby/nodes/class.js +17 -27
- data/src/ruby/nodes/commands.js +8 -3
- data/src/ruby/nodes/conditionals.js +1 -1
- data/src/ruby/nodes/hashes.js +28 -14
- data/src/ruby/nodes/loops.js +4 -10
- data/src/ruby/nodes/methods.js +4 -11
- data/src/ruby/nodes/rescue.js +32 -25
- data/src/ruby/nodes/statements.js +6 -5
- data/src/ruby/nodes/strings.js +7 -6
- data/src/ruby/parser.js +2 -50
- data/src/ruby/parser.rb +113 -43
- data/src/ruby/printer.js +8 -5
- data/src/utils.js +1 -0
- data/src/utils/inlineEnsureParens.js +8 -1
- data/src/utils/isEmptyBodyStmt.js +7 -0
- data/src/utils/isEmptyStmts.js +9 -5
- data/src/utils/noIndent.js +1 -0
- data/src/utils/printEmptyCollection.js +9 -2
- metadata +25 -2
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            const { concat, group, hardline, indent, join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#html-comments-
         | 
| 4 | 
            +
            function comment(path, _opts, print) {
         | 
| 5 | 
            +
              const { children, value } = path.getValue();
         | 
| 6 | 
            +
              const parts = ["/"];
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              if (value.revealed) {
         | 
| 9 | 
            +
                parts.push("!");
         | 
| 10 | 
            +
              }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              if (value.conditional) {
         | 
| 13 | 
            +
                parts.push(value.conditional);
         | 
| 14 | 
            +
              } else if (value.text) {
         | 
| 15 | 
            +
                parts.push(" ", value.text);
         | 
| 16 | 
            +
              }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              if (children.length > 0) {
         | 
| 19 | 
            +
                parts.push(
         | 
| 20 | 
            +
                  indent(concat([hardline, join(hardline, path.map(print, "children"))]))
         | 
| 21 | 
            +
                );
         | 
| 22 | 
            +
              }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              return group(concat(parts));
         | 
| 25 | 
            +
            }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            module.exports = comment;
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            const { join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            const types = {
         | 
| 4 | 
            +
              basic: "Basic",
         | 
| 5 | 
            +
              frameset: "Frameset",
         | 
| 6 | 
            +
              mobile: "Mobile",
         | 
| 7 | 
            +
              rdfa: "RDFa",
         | 
| 8 | 
            +
              strict: "Strict",
         | 
| 9 | 
            +
              xml: "XML"
         | 
| 10 | 
            +
            };
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            const versions = ["1.1", "5"];
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#doctype-
         | 
| 15 | 
            +
            function doctype(path, _opts, _print) {
         | 
| 16 | 
            +
              const { value } = path.getValue();
         | 
| 17 | 
            +
              const parts = ["!!!"];
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              if (value.type in types) {
         | 
| 20 | 
            +
                parts.push(types[value.type]);
         | 
| 21 | 
            +
              } else if (versions.includes(value.version)) {
         | 
| 22 | 
            +
                parts.push(value.version);
         | 
| 23 | 
            +
              } else {
         | 
| 24 | 
            +
                parts.push(value.type);
         | 
| 25 | 
            +
              }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              if (value.encoding) {
         | 
| 28 | 
            +
                parts.push(value.encoding);
         | 
| 29 | 
            +
              }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              return join(" ", parts);
         | 
| 32 | 
            +
            }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            module.exports = doctype;
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            const { concat, group, hardline, indent, join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#filters
         | 
| 4 | 
            +
            function filter(path, _opts, _print) {
         | 
| 5 | 
            +
              const { value } = path.getValue();
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              return group(
         | 
| 8 | 
            +
                concat([
         | 
| 9 | 
            +
                  ":",
         | 
| 10 | 
            +
                  value.name,
         | 
| 11 | 
            +
                  indent(concat([hardline, join(hardline, value.text.trim().split("\n"))]))
         | 
| 12 | 
            +
                ])
         | 
| 13 | 
            +
              );
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            module.exports = filter;
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            const { concat, hardline, indent, join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#haml-comments--
         | 
| 4 | 
            +
            function hamlComment(path, opts, _print) {
         | 
| 5 | 
            +
              const node = path.getValue();
         | 
| 6 | 
            +
              const parts = ["-#"];
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              if (node.value.text) {
         | 
| 9 | 
            +
                if (opts.originalText.split("\n")[node.line - 1].trim() === "-#") {
         | 
| 10 | 
            +
                  const lines = node.value.text.trim().split("\n");
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  parts.push(indent(concat([hardline, join(hardline, lines)])));
         | 
| 13 | 
            +
                } else {
         | 
| 14 | 
            +
                  parts.push(" ", node.value.text.trim());
         | 
| 15 | 
            +
                }
         | 
| 16 | 
            +
              }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              return concat(parts);
         | 
| 19 | 
            +
            }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            module.exports = hamlComment;
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            const { concat, group, hardline, indent, join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#inserting_ruby
         | 
| 4 | 
            +
            function script(path, opts, print) {
         | 
| 5 | 
            +
              const { children, value } = path.getValue();
         | 
| 6 | 
            +
              const parts = [];
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              if (value.escape_html) {
         | 
| 9 | 
            +
                parts.unshift("&");
         | 
| 10 | 
            +
              }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              if (value.preserve) {
         | 
| 13 | 
            +
                parts.push("~");
         | 
| 14 | 
            +
              } else if (!value.interpolate) {
         | 
| 15 | 
            +
                parts.push("=");
         | 
| 16 | 
            +
              }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              if (value.escape_html && !value.preserve && value.interpolate) {
         | 
| 19 | 
            +
                parts.push(" ", value.text.trim().slice(1, -1));
         | 
| 20 | 
            +
              } else {
         | 
| 21 | 
            +
                parts.push(" ", value.text.trim());
         | 
| 22 | 
            +
              }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              if (children.length > 0) {
         | 
| 25 | 
            +
                parts.push(
         | 
| 26 | 
            +
                  indent(concat([hardline, join(hardline, path.map(print, "children"))]))
         | 
| 27 | 
            +
                );
         | 
| 28 | 
            +
              }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              return group(concat(parts));
         | 
| 31 | 
            +
            }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            module.exports = script;
         | 
| @@ -0,0 +1,59 @@ | |
| 1 | 
            +
            const { concat, group, hardline, indent, join } = require("../../prettier");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            function findKeywordIndices(children, keywords) {
         | 
| 4 | 
            +
              const indices = [];
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              children.forEach((child, index) => {
         | 
| 7 | 
            +
                if (child.type !== "silent_script") {
         | 
| 8 | 
            +
                  return;
         | 
| 9 | 
            +
                }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                if (keywords.includes(child.value.keyword)) {
         | 
| 12 | 
            +
                  indices.push(index);
         | 
| 13 | 
            +
                }
         | 
| 14 | 
            +
              });
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              return indices;
         | 
| 17 | 
            +
            }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
         | 
| 20 | 
            +
            function silentScript(path, _opts, print) {
         | 
| 21 | 
            +
              const { children, value } = path.getValue();
         | 
| 22 | 
            +
              const parts = [`- ${value.text.trim()}`];
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              if (children.length > 0) {
         | 
| 25 | 
            +
                const scripts = path.map(print, "children");
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                if (value.keyword === "case") {
         | 
| 28 | 
            +
                  const keywordIndices = findKeywordIndices(children, ["when", "else"]);
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  parts.push(
         | 
| 31 | 
            +
                    concat(
         | 
| 32 | 
            +
                      scripts.map((script, index) => {
         | 
| 33 | 
            +
                        const concated = concat([hardline, script]);
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                        return keywordIndices.includes(index) ? concated : indent(concated);
         | 
| 36 | 
            +
                      })
         | 
| 37 | 
            +
                    )
         | 
| 38 | 
            +
                  );
         | 
| 39 | 
            +
                } else if (["if", "unless"].includes(value.keyword)) {
         | 
| 40 | 
            +
                  const keywordIndices = findKeywordIndices(children, ["elsif", "else"]);
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  parts.push(
         | 
| 43 | 
            +
                    concat(
         | 
| 44 | 
            +
                      scripts.map((script, index) => {
         | 
| 45 | 
            +
                        const concated = concat([hardline, script]);
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                        return keywordIndices.includes(index) ? concated : indent(concated);
         | 
| 48 | 
            +
                      })
         | 
| 49 | 
            +
                    )
         | 
| 50 | 
            +
                  );
         | 
| 51 | 
            +
                } else {
         | 
| 52 | 
            +
                  parts.push(indent(concat([hardline, join(hardline, scripts)])));
         | 
| 53 | 
            +
                }
         | 
| 54 | 
            +
              }
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              return group(concat(parts));
         | 
| 57 | 
            +
            }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            module.exports = silentScript;
         | 
| @@ -0,0 +1,193 @@ | |
| 1 | 
            +
            const {
         | 
| 2 | 
            +
              align,
         | 
| 3 | 
            +
              concat,
         | 
| 4 | 
            +
              fill,
         | 
| 5 | 
            +
              group,
         | 
| 6 | 
            +
              hardline,
         | 
| 7 | 
            +
              ifBreak,
         | 
| 8 | 
            +
              indent,
         | 
| 9 | 
            +
              join,
         | 
| 10 | 
            +
              line,
         | 
| 11 | 
            +
              softline
         | 
| 12 | 
            +
            } = require("../../prettier");
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            function getDynamicAttributes(header, attributes) {
         | 
| 15 | 
            +
              const pairs = attributes
         | 
| 16 | 
            +
                .slice(1, -2)
         | 
| 17 | 
            +
                .split(",")
         | 
| 18 | 
            +
                .map((pair) => pair.slice(1).split('" => '));
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              const parts = [concat([pairs[0][0], "=", pairs[0][1]])];
         | 
| 21 | 
            +
              pairs.slice(1).forEach((pair) => {
         | 
| 22 | 
            +
                parts.push(line, concat([pair[0], "=", pair[1]]));
         | 
| 23 | 
            +
              });
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              return group(concat(["(", align(header + 1, fill(parts)), ")"]));
         | 
| 26 | 
            +
            }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            function getHashValue(value, opts) {
         | 
| 29 | 
            +
              if (typeof value !== "string") {
         | 
| 30 | 
            +
                return value.toString();
         | 
| 31 | 
            +
              }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              // This is a very special syntax created by the parser to let us know that
         | 
| 34 | 
            +
              // this should be printed literally instead of as a string.
         | 
| 35 | 
            +
              if (value.startsWith("&")) {
         | 
| 36 | 
            +
                return value.slice(1);
         | 
| 37 | 
            +
              }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              const quote = opts.rubySingleQuote ? "'" : '"';
         | 
| 40 | 
            +
              return `${quote}${value}${quote}`;
         | 
| 41 | 
            +
            }
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            function getHashKey(key, opts) {
         | 
| 44 | 
            +
              let quoted = key;
         | 
| 45 | 
            +
              const joiner = opts.rubyHashLabel ? ":" : " =>";
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              if (key.includes(":") || key.includes("-")) {
         | 
| 48 | 
            +
                const quote = opts.rubySingleQuote ? "'" : '"';
         | 
| 49 | 
            +
                quoted = `${quote}${key}${quote}`;
         | 
| 50 | 
            +
              }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              return `${opts.rubyHashLabel ? "" : ":"}${quoted}${joiner}`;
         | 
| 53 | 
            +
            }
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            function getKeyValuePair(key, value, opts) {
         | 
| 56 | 
            +
              return `${getHashKey(key, opts)} ${getHashValue(value, opts)}`;
         | 
| 57 | 
            +
            }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            function getStaticAttributes(header, attributes, opts) {
         | 
| 60 | 
            +
              const keys = Object.keys(attributes).filter(
         | 
| 61 | 
            +
                (name) => !["class", "id"].includes(name)
         | 
| 62 | 
            +
              );
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              const parts = [getKeyValuePair(keys[0], attributes[keys[0]], opts)];
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              keys.slice(1).forEach((key) => {
         | 
| 67 | 
            +
                parts.push(",", line, getKeyValuePair(key, attributes[key], opts));
         | 
| 68 | 
            +
              });
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              return group(concat(["{", align(header + 1, fill(parts)), "}"]));
         | 
| 71 | 
            +
            }
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            function getAttributesObject(object, opts, level = 0) {
         | 
| 74 | 
            +
              if (typeof object !== "object") {
         | 
| 75 | 
            +
                return getHashValue(object, opts);
         | 
| 76 | 
            +
              }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              const boundary = level === 0 ? softline : line;
         | 
| 79 | 
            +
              const parts = Object.keys(object).map((key) =>
         | 
| 80 | 
            +
                concat([
         | 
| 81 | 
            +
                  getHashKey(key, opts),
         | 
| 82 | 
            +
                  " ",
         | 
| 83 | 
            +
                  getAttributesObject(object[key], opts, level + 1)
         | 
| 84 | 
            +
                ])
         | 
| 85 | 
            +
              );
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              return group(
         | 
| 88 | 
            +
                concat([
         | 
| 89 | 
            +
                  "{",
         | 
| 90 | 
            +
                  indent(group(concat([boundary, join(concat([",", line]), parts)]))),
         | 
| 91 | 
            +
                  boundary,
         | 
| 92 | 
            +
                  "}"
         | 
| 93 | 
            +
                ])
         | 
| 94 | 
            +
              );
         | 
| 95 | 
            +
            }
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            function getHeader(value, opts) {
         | 
| 98 | 
            +
              const { attributes } = value;
         | 
| 99 | 
            +
              const parts = [];
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              if (value.name !== "div") {
         | 
| 102 | 
            +
                parts.push(`%${value.name}`);
         | 
| 103 | 
            +
              }
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              if (attributes.class) {
         | 
| 106 | 
            +
                parts.push(`.${attributes.class.replace(/ /g, ".")}`);
         | 
| 107 | 
            +
              }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
              if (attributes.id) {
         | 
| 110 | 
            +
                parts.push(`#${attributes.id}`);
         | 
| 111 | 
            +
              }
         | 
| 112 | 
            +
             | 
| 113 | 
            +
              if (value.dynamic_attributes.new) {
         | 
| 114 | 
            +
                parts.push(
         | 
| 115 | 
            +
                  getDynamicAttributes(parts.join("").length, value.dynamic_attributes.new)
         | 
| 116 | 
            +
                );
         | 
| 117 | 
            +
              }
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              if (
         | 
| 120 | 
            +
                Object.keys(attributes).some((name) => name !== "class" && name !== "id")
         | 
| 121 | 
            +
              ) {
         | 
| 122 | 
            +
                parts.push(getStaticAttributes(parts.join("").length, attributes, opts));
         | 
| 123 | 
            +
              }
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              if (value.dynamic_attributes.old) {
         | 
| 126 | 
            +
                if (parts.length === 0) {
         | 
| 127 | 
            +
                  parts.push("%div");
         | 
| 128 | 
            +
                }
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                if (typeof value.dynamic_attributes.old === "string") {
         | 
| 131 | 
            +
                  parts.push(value.dynamic_attributes.old);
         | 
| 132 | 
            +
                } else {
         | 
| 133 | 
            +
                  parts.push(getAttributesObject(value.dynamic_attributes.old, opts));
         | 
| 134 | 
            +
                }
         | 
| 135 | 
            +
              }
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              if (value.object_ref) {
         | 
| 138 | 
            +
                if (parts.length === 0) {
         | 
| 139 | 
            +
                  parts.push("%div");
         | 
| 140 | 
            +
                }
         | 
| 141 | 
            +
                parts.push(value.object_ref);
         | 
| 142 | 
            +
              }
         | 
| 143 | 
            +
             | 
| 144 | 
            +
              if (value.nuke_outer_whitespace) {
         | 
| 145 | 
            +
                parts.push(">");
         | 
| 146 | 
            +
              }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              if (value.nuke_inner_whitespace) {
         | 
| 149 | 
            +
                parts.push("<");
         | 
| 150 | 
            +
              }
         | 
| 151 | 
            +
             | 
| 152 | 
            +
              if (value.self_closing) {
         | 
| 153 | 
            +
                parts.push("/");
         | 
| 154 | 
            +
              }
         | 
| 155 | 
            +
             | 
| 156 | 
            +
              if (value.value) {
         | 
| 157 | 
            +
                const prefix = value.parse ? "= " : ifBreak("", " ");
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                return group(
         | 
| 160 | 
            +
                  concat([
         | 
| 161 | 
            +
                    group(concat(parts)),
         | 
| 162 | 
            +
                    indent(concat([softline, prefix, value.value]))
         | 
| 163 | 
            +
                  ])
         | 
| 164 | 
            +
                );
         | 
| 165 | 
            +
              }
         | 
| 166 | 
            +
             | 
| 167 | 
            +
              // In case none of the other if statements have matched and we're printing a
         | 
| 168 | 
            +
              // div, we need to explicitly add it back into the array.
         | 
| 169 | 
            +
              if (parts.length === 0 && value.name === "div") {
         | 
| 170 | 
            +
                parts.push("%div");
         | 
| 171 | 
            +
              }
         | 
| 172 | 
            +
             | 
| 173 | 
            +
              return group(concat(parts));
         | 
| 174 | 
            +
            }
         | 
| 175 | 
            +
             | 
| 176 | 
            +
            // https://haml.info/docs/yardoc/file.REFERENCE.html#element-name-
         | 
| 177 | 
            +
            function tag(path, opts, print) {
         | 
| 178 | 
            +
              const { children, value } = path.getValue();
         | 
| 179 | 
            +
              const header = getHeader(value, opts);
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              if (children.length === 0) {
         | 
| 182 | 
            +
                return header;
         | 
| 183 | 
            +
              }
         | 
| 184 | 
            +
             | 
| 185 | 
            +
              return group(
         | 
| 186 | 
            +
                concat([
         | 
| 187 | 
            +
                  header,
         | 
| 188 | 
            +
                  indent(concat([hardline, join(hardline, path.map(print, "children"))]))
         | 
| 189 | 
            +
                ])
         | 
| 190 | 
            +
              );
         | 
| 191 | 
            +
            }
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            module.exports = tag;
         | 
    
        data/src/haml/parser.js
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            const parseSync = require("../parser/parseSync");
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            const parse = (text, _parsers, _opts) => {
         | 
| 4 | 
            +
              return parseSync("haml", text);
         | 
| 5 | 
            +
            };
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            const pragmaPattern = /^\s*-#\s*@(prettier|format)/;
         | 
| 8 | 
            +
            const hasPragma = (text) => pragmaPattern.test(text);
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            // These functions are just placeholders until we can actually perform this
         | 
| 11 | 
            +
            // properly. The functions are necessary otherwise the format with cursor
         | 
| 12 | 
            +
            // functions break.
         | 
| 13 | 
            +
            const locStart = (_node) => 0;
         | 
| 14 | 
            +
            const locEnd = (_node) => 0;
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            module.exports = {
         | 
| 17 | 
            +
              parse,
         | 
| 18 | 
            +
              astFormat: "haml",
         | 
| 19 | 
            +
              hasPragma,
         | 
| 20 | 
            +
              locStart,
         | 
| 21 | 
            +
              locEnd
         | 
| 22 | 
            +
            };
         | 
    
        data/src/haml/parser.rb
    ADDED
    
    | @@ -0,0 +1,138 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'ripper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            begin
         | 
| 6 | 
            +
              require 'haml'
         | 
| 7 | 
            +
            rescue LoadError
         | 
| 8 | 
            +
              # If we can't load the haml gem, then we're going to provide a shim parser
         | 
| 9 | 
            +
              # that will warn and bail out.
         | 
| 10 | 
            +
              class Prettier::HAMLParser
         | 
| 11 | 
            +
                def self.parse(text)
         | 
| 12 | 
            +
                  warn(
         | 
| 13 | 
            +
                    'The `haml` gem could not be loaded. Please ensure you have it ' \
         | 
| 14 | 
            +
                      'installed and that it is available in the gem path.'
         | 
| 15 | 
            +
                  )
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  false
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              return
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            class Haml::Parser::ParseNode
         | 
| 25 | 
            +
              class DeepAttributeParser
         | 
| 26 | 
            +
                def parse(string)
         | 
| 27 | 
            +
                  Haml::AttributeParser.available? ? parse_value(string) : string
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def literal(string, level)
         | 
| 33 | 
            +
                  level == 0 ? string : "&#{string}"
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def parse_value(string, level = 0)
         | 
| 37 | 
            +
                  response = Ripper.sexp(string)
         | 
| 38 | 
            +
                  return literal(string, level) unless response
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  case response[1][0][0]
         | 
| 41 | 
            +
                  when :hash
         | 
| 42 | 
            +
                    hash = Haml::AttributeParser.parse(string)
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    if hash
         | 
| 45 | 
            +
                      # Explicitly not using Enumerable#to_h here to support Ruby 2.5
         | 
| 46 | 
            +
                      hash.each_with_object({}) do |(key, value), response|
         | 
| 47 | 
            +
                        response[key] = parse_value(value, level + 1)
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
                    else
         | 
| 50 | 
            +
                      literal(string, level)
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  when :string_literal
         | 
| 53 | 
            +
                    string[1...-1]
         | 
| 54 | 
            +
                  else
         | 
| 55 | 
            +
                    literal(string, level)
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              ESCAPE = /Haml::Helpers.html_escape\(\((.+)\)\)/.freeze
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              # If a node comes in as the plain type but starts with one of the special
         | 
| 63 | 
            +
              # characters that haml parses, then we need to escape it with a \ when
         | 
| 64 | 
            +
              # printing. So here we make a regexp pattern to check if the node needs to be
         | 
| 65 | 
            +
              # escaped.
         | 
| 66 | 
            +
              special_chars =
         | 
| 67 | 
            +
                Haml::Parser::SPECIAL_CHARACTERS.map { |char| Regexp.escape(char) }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              SPECIAL_START = /\A(?:#{special_chars.join('|')})/
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def as_json
         | 
| 72 | 
            +
                case type
         | 
| 73 | 
            +
                when :comment, :doctype, :silent_script
         | 
| 74 | 
            +
                  to_h.tap do |json|
         | 
| 75 | 
            +
                    json.delete(:parent)
         | 
| 76 | 
            +
                    json[:children] = children.map(&:as_json)
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                when :filter, :haml_comment
         | 
| 79 | 
            +
                  to_h.tap { |json| json.delete(:parent) }
         | 
| 80 | 
            +
                when :plain
         | 
| 81 | 
            +
                  to_h.tap do |json|
         | 
| 82 | 
            +
                    json.delete(:parent)
         | 
| 83 | 
            +
                    json[:children] = children.map(&:as_json)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    text = json[:value][:text]
         | 
| 86 | 
            +
                    json[:value][:text] = "\\#{text}" if text.match?(SPECIAL_START)
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                when :root
         | 
| 89 | 
            +
                  to_h.tap { |json| json[:children] = children.map(&:as_json) }
         | 
| 90 | 
            +
                when :script
         | 
| 91 | 
            +
                  to_h.tap do |json|
         | 
| 92 | 
            +
                    json.delete(:parent)
         | 
| 93 | 
            +
                    json[:children] = children.map(&:as_json)
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    if json[:value][:text].match?(ESCAPE)
         | 
| 96 | 
            +
                      json[:value][:text].gsub!(ESCAPE) { $1 }
         | 
| 97 | 
            +
                      json[:value].merge!(escape_html: 'escape_html', interpolate: true)
         | 
| 98 | 
            +
                    end
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                when :tag
         | 
| 101 | 
            +
                  to_h.tap do |json|
         | 
| 102 | 
            +
                    json.delete(:parent)
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    # For some reason this is actually using a symbol to represent a null
         | 
| 105 | 
            +
                    # object ref instead of nil itself, so just replacing it here for
         | 
| 106 | 
            +
                    # simplicity in the printer
         | 
| 107 | 
            +
                    json[:value][:object_ref] = nil if json[:value][:object_ref] == :nil
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                    # Get a reference to the dynamic attributes hash
         | 
| 110 | 
            +
                    dynamic_attributes = value[:dynamic_attributes].to_h
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    # If we have any in the old style, then we're going to pass it through
         | 
| 113 | 
            +
                    # the deep attribute parser filter.
         | 
| 114 | 
            +
                    if dynamic_attributes[:old]
         | 
| 115 | 
            +
                      dynamic_attributes[:old] =
         | 
| 116 | 
            +
                        DeepAttributeParser.new.parse(dynamic_attributes[:old])
         | 
| 117 | 
            +
                    end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                    json.merge!(
         | 
| 120 | 
            +
                      children: children.map(&:as_json),
         | 
| 121 | 
            +
                      value: value.merge(dynamic_attributes: dynamic_attributes)
         | 
| 122 | 
            +
                    )
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                else
         | 
| 125 | 
            +
                  raise ArgumentError, "Unsupported type: #{type}"
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
            end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            module Prettier
         | 
| 131 | 
            +
              class HAMLParser
         | 
| 132 | 
            +
                def self.parse(source)
         | 
| 133 | 
            +
                  Haml::Parser.new({}).call(source).as_json
         | 
| 134 | 
            +
                rescue StandardError
         | 
| 135 | 
            +
                  false
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         |