prettier 1.2.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +349 -358
  3. data/README.md +21 -93
  4. data/node_modules/prettier/index.js +54 -54
  5. data/package.json +1 -2
  6. data/rubocop.yml +26 -0
  7. data/src/haml/embed.js +87 -0
  8. data/src/haml/nodes/comment.js +27 -0
  9. data/src/haml/nodes/doctype.js +34 -0
  10. data/src/haml/nodes/filter.js +16 -0
  11. data/src/haml/nodes/hamlComment.js +21 -0
  12. data/src/haml/nodes/plain.js +6 -0
  13. data/src/haml/nodes/root.js +8 -0
  14. data/src/haml/nodes/script.js +33 -0
  15. data/src/haml/nodes/silentScript.js +59 -0
  16. data/src/haml/nodes/tag.js +193 -0
  17. data/src/haml/parser.js +22 -0
  18. data/src/haml/parser.rb +138 -0
  19. data/src/haml/printer.js +28 -0
  20. data/src/parser/getLang.js +32 -0
  21. data/src/parser/getNetcat.js +50 -0
  22. data/src/parser/netcat.js +15 -0
  23. data/src/parser/parseSync.js +33 -0
  24. data/src/parser/requestParse.js +74 -0
  25. data/src/parser/server.rb +61 -0
  26. data/src/plugin.js +26 -4
  27. data/src/prettier.js +1 -0
  28. data/src/rbs/parser.js +39 -0
  29. data/src/rbs/parser.rb +94 -0
  30. data/src/rbs/printer.js +605 -0
  31. data/src/ruby/embed.js +58 -8
  32. data/src/ruby/nodes/args.js +20 -6
  33. data/src/ruby/nodes/blocks.js +64 -59
  34. data/src/ruby/nodes/calls.js +12 -43
  35. data/src/ruby/nodes/class.js +17 -27
  36. data/src/ruby/nodes/commands.js +7 -2
  37. data/src/ruby/nodes/conditionals.js +1 -1
  38. data/src/ruby/nodes/hashes.js +28 -14
  39. data/src/ruby/nodes/hooks.js +9 -19
  40. data/src/ruby/nodes/loops.js +4 -10
  41. data/src/ruby/nodes/methods.js +8 -17
  42. data/src/ruby/nodes/params.js +22 -14
  43. data/src/ruby/nodes/patterns.js +9 -5
  44. data/src/ruby/nodes/rescue.js +32 -25
  45. data/src/ruby/nodes/return.js +0 -4
  46. data/src/ruby/nodes/statements.js +11 -13
  47. data/src/ruby/nodes/strings.js +27 -35
  48. data/src/ruby/parser.js +2 -49
  49. data/src/ruby/parser.rb +256 -232
  50. data/src/ruby/printer.js +0 -2
  51. data/src/ruby/toProc.js +4 -8
  52. data/src/utils.js +1 -0
  53. data/src/utils/isEmptyBodyStmt.js +7 -0
  54. data/src/utils/isEmptyStmts.js +9 -5
  55. data/src/utils/makeCall.js +3 -0
  56. data/src/utils/noIndent.js +1 -0
  57. data/src/utils/printEmptyCollection.js +9 -2
  58. metadata +26 -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,6 @@
1
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#plain-text
2
+ function plain(path, _opts, _print) {
3
+ return path.getValue().value.text;
4
+ }
5
+
6
+ module.exports = plain;
@@ -0,0 +1,8 @@
1
+ const { concat, hardline, join } = require("../../prettier");
2
+
3
+ // The root node in the AST
4
+ function root(path, _opts, print) {
5
+ return concat([join(hardline, path.map(print, "children")), hardline]);
6
+ }
7
+
8
+ module.exports = root;
@@ -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;
@@ -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
+ };
@@ -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