prettier 1.5.0 → 1.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -2
  3. data/README.md +22 -12
  4. data/node_modules/prettier/index.js +53 -53
  5. data/node_modules/prettier/parser-angular.js +46 -0
  6. data/node_modules/prettier/parser-babel.js +1 -0
  7. data/node_modules/prettier/parser-espree.js +1 -0
  8. data/node_modules/prettier/parser-flow.js +1 -0
  9. data/node_modules/prettier/parser-glimmer.js +1 -0
  10. data/node_modules/prettier/parser-graphql.js +1 -0
  11. data/node_modules/prettier/parser-html.js +113 -0
  12. data/node_modules/prettier/parser-markdown.js +19 -0
  13. data/node_modules/prettier/parser-meriyah.js +1 -0
  14. data/node_modules/prettier/parser-postcss.js +1 -0
  15. data/node_modules/prettier/parser-typescript.js +1 -0
  16. data/node_modules/prettier/parser-yaml.js +15 -0
  17. data/package.json +4 -4
  18. data/rubocop.yml +3 -0
  19. data/src/haml/nodes/tag.js +45 -6
  20. data/src/haml/parser.js +2 -2
  21. data/src/haml/parser.rb +8 -3
  22. data/src/parser/netcat.js +0 -2
  23. data/src/parser/parseSync.js +151 -14
  24. data/src/parser/server.rb +7 -2
  25. data/src/plugin.js +6 -0
  26. data/src/rbs/parser.js +2 -2
  27. data/src/rbs/parser.rb +7 -3
  28. data/src/rbs/printer.js +14 -4
  29. data/src/ruby/embed.js +7 -5
  30. data/src/ruby/nodes/args.js +67 -19
  31. data/src/ruby/nodes/arrays.js +36 -33
  32. data/src/ruby/nodes/commands.js +1 -1
  33. data/src/ruby/nodes/heredocs.js +5 -3
  34. data/src/ruby/parser.js +2 -2
  35. data/src/ruby/parser.rb +81 -6
  36. data/src/ruby/printer.js +8 -3
  37. data/src/utils.js +1 -1
  38. data/src/utils/inlineEnsureParens.js +8 -1
  39. data/src/utils/literallineWithoutBreakParent.js +7 -0
  40. metadata +16 -7
  41. data/src/parser/getLang.js +0 -32
  42. data/src/parser/getNetcat.js +0 -50
  43. data/src/parser/requestParse.js +0 -74
  44. data/src/utils/literalLineNoBreak.js +0 -7
data/src/rbs/parser.rb CHANGED
@@ -86,9 +86,13 @@ end
86
86
  module Prettier
87
87
  class RBSParser
88
88
  def self.parse(text)
89
- { declarations: RBS::Parser.parse_signature(text) }
90
- rescue StandardError
91
- false
89
+ {
90
+ declarations: RBS::Parser.parse_signature(text),
91
+ location: {
92
+ start_pos: 0,
93
+ end_pos: text.length
94
+ }
95
+ }
92
96
  end
93
97
  end
94
98
  end
data/src/rbs/printer.js CHANGED
@@ -147,7 +147,7 @@ function printNode(path, opts, print) {
147
147
 
148
148
  // This is the big function that prints out any individual type, which can
149
149
  // look like all kinds of things, listed in the case statement below.
150
- function printType(path) {
150
+ function printType(path, { forceUnionParens = false } = {}) {
151
151
  const node = path.getValue();
152
152
 
153
153
  switch (node.class) {
@@ -173,8 +173,11 @@ function printNode(path, opts, print) {
173
173
  join(concat([line, "| "]), path.map(printType, "types"))
174
174
  );
175
175
 
176
- const parentType = path.getParentNode().class;
177
- return parentType === "intersection" ? concat(["(", doc, ")"]) : doc;
176
+ if (forceUnionParens || path.getParentNode().class === "intersection") {
177
+ return concat(["(", doc, ")"]);
178
+ }
179
+
180
+ return doc;
178
181
  }
179
182
  case "intersection":
180
183
  return group(join(concat([line, "& "]), path.map(printType, "types")));
@@ -515,7 +518,14 @@ function printNode(path, opts, print) {
515
518
  );
516
519
  }
517
520
 
518
- parts.push("-> ", path.call(printType, "type", "return_type"));
521
+ parts.push(
522
+ "-> ",
523
+ path.call(
524
+ (typePath) => printType(typePath, { forceUnionParens: true }),
525
+ "type",
526
+ "return_type"
527
+ )
528
+ );
519
529
 
520
530
  return group(concat(parts));
521
531
  }
data/src/ruby/embed.js CHANGED
@@ -8,7 +8,7 @@ const {
8
8
  stripTrailingHardline
9
9
  } = require("../prettier");
10
10
 
11
- const { literalLineNoBreak } = require("../utils");
11
+ const { literallineWithoutBreakParent } = require("../utils");
12
12
 
13
13
  const parsers = {
14
14
  css: "css",
@@ -30,7 +30,7 @@ function replaceNewlines(doc) {
30
30
  ? concat(
31
31
  currentDoc
32
32
  .split(/(\n)/g)
33
- .map((v, i) => (i % 2 === 0 ? v : literalLineNoBreak))
33
+ .map((v, i) => (i % 2 === 0 ? v : literallineWithoutBreakParent))
34
34
  )
35
35
  : currentDoc
36
36
  );
@@ -106,7 +106,7 @@ function embed(path, print, textToDoc, _opts) {
106
106
 
107
107
  // Pass that content into the embedded parser. Get back the doc node.
108
108
  const formatted = concat([
109
- literalLineNoBreak,
109
+ literallineWithoutBreakParent,
110
110
  replaceNewlines(stripTrailingHardline(textToDoc(content, { parser })))
111
111
  ]);
112
112
 
@@ -119,7 +119,7 @@ function embed(path, print, textToDoc, _opts) {
119
119
  group(
120
120
  concat([
121
121
  indent(markAsRoot(formatted)),
122
- literalLineNoBreak,
122
+ literallineWithoutBreakParent,
123
123
  ending.trim()
124
124
  ])
125
125
  )
@@ -132,7 +132,9 @@ function embed(path, print, textToDoc, _opts) {
132
132
  return markAsRoot(
133
133
  concat([
134
134
  path.call(print, "beging"),
135
- lineSuffix(group(concat([formatted, literalLineNoBreak, ending.trim()])))
135
+ lineSuffix(
136
+ group(concat([formatted, literallineWithoutBreakParent, ending.trim()]))
137
+ )
136
138
  ])
137
139
  );
138
140
  }
@@ -58,7 +58,7 @@ function printArgParen(path, opts, print) {
58
58
  concat([
59
59
  softline,
60
60
  join(concat([",", line]), path.call(print, "body", 0)),
61
- getTrailingComma(opts) && getArgParenTrailingComma(argsNode)
61
+ getTrailingComma(opts) ? getArgParenTrailingComma(argsNode) : ""
62
62
  ])
63
63
  ),
64
64
  softline,
@@ -106,25 +106,73 @@ function printArgs(path, { rubyToProc }, print) {
106
106
  return args;
107
107
  }
108
108
 
109
+ function printArgsAddBlock(path, opts, print) {
110
+ const node = path.getValue();
111
+ const parts = path.call(print, "body", 0);
112
+
113
+ if (node.body[1]) {
114
+ let blockDoc = path.call(print, "body", 1);
115
+
116
+ if (node.body[1].comments) {
117
+ // If we have a method call like:
118
+ //
119
+ // foo(
120
+ // # comment
121
+ // &block
122
+ // )
123
+ //
124
+ // then we need to make sure we don't accidentally prepend the operator
125
+ // before the comment.
126
+ blockDoc.parts[2] = concat(["&", blockDoc.parts[2]]);
127
+ } else {
128
+ // If we don't have any comments, we can just prepend the operator
129
+ blockDoc = concat(["&", blockDoc]);
130
+ }
131
+
132
+ parts.push(blockDoc);
133
+ }
134
+
135
+ return parts;
136
+ }
137
+
138
+ function printArgsAddStar(path, opts, print) {
139
+ const node = path.getValue();
140
+ const docs = path.map(print, "body");
141
+
142
+ if (node.body[1].comments) {
143
+ // If we have an array like:
144
+ //
145
+ // [
146
+ // # comment
147
+ // *values
148
+ // ]
149
+ //
150
+ // or if we have an array like:
151
+ //
152
+ // [
153
+ // *values # comment
154
+ // ]
155
+ //
156
+ // then we need to make sure we don't accidentally prepend the operator
157
+ // before the comment.
158
+ const index = node.body[1].comments.filter(({ leading }) => leading).length;
159
+ docs[1].parts[index] = concat(["*", docs[1].parts[index]]);
160
+ } else {
161
+ // If we don't have any comments, we can just prepend the operator
162
+ docs[1] = concat(["*", docs[1]]);
163
+ }
164
+
165
+ return docs[0].concat(docs[1]).concat(docs.slice(2));
166
+ }
167
+
168
+ function printBlockArg(path, opts, print) {
169
+ return concat(["&", path.call(print, "body", 0)]);
170
+ }
171
+
109
172
  module.exports = {
110
173
  arg_paren: printArgParen,
111
174
  args: printArgs,
112
- args_add_block: (path, opts, print) => {
113
- const parts = path.call(print, "body", 0);
114
-
115
- if (path.getValue().body[1]) {
116
- parts.push(concat(["&", path.call(print, "body", 1)]));
117
- }
118
-
119
- return parts;
120
- },
121
- args_add_star: (path, opts, print) => {
122
- const printed = path.map(print, "body");
123
- const parts = printed[0]
124
- .concat([concat(["*", printed[1]])])
125
- .concat(printed.slice(2));
126
-
127
- return parts;
128
- },
129
- blockarg: (path, opts, print) => concat(["&", path.call(print, "body", 0)])
175
+ args_add_block: printArgsAddBlock,
176
+ args_add_star: printArgsAddStar,
177
+ blockarg: printBlockArg
130
178
  };
@@ -63,33 +63,30 @@ function isSymbolArray(args) {
63
63
  // Prints out a word that is a part of a special array literal that accepts
64
64
  // interpolation. The body is an array of either plain strings or interpolated
65
65
  // expressions.
66
- function printSpecialArrayWord(path, opts, print) {
66
+ function printArrayLiteralWord(path, opts, print) {
67
67
  return concat(path.map(print, "body"));
68
68
  }
69
69
 
70
70
  // Prints out a special array literal. Accepts the parts of the array literal as
71
71
  // an argument, where the first element of the parts array is a string that
72
72
  // contains the special start.
73
- function printSpecialArrayParts(parts) {
73
+ function printArrayLiteral(start, parts) {
74
74
  return group(
75
75
  concat([
76
- parts[0],
76
+ start,
77
77
  "[",
78
- indent(concat([softline, join(line, parts.slice(1))])),
78
+ indent(concat([softline, join(line, parts)])),
79
79
  concat([softline, "]"])
80
80
  ])
81
81
  );
82
82
  }
83
83
 
84
- // Generates a print function with an embedded special start character for the
85
- // specific type of array literal that we're dealing with. The print function
86
- // returns an array as it expects to eventually be handed off to
87
- // printSpecialArrayParts.
88
- function printSpecialArray(start) {
89
- return function printSpecialArrayWithStart(path, opts, print) {
90
- return [start].concat(path.map(print, "body"));
91
- };
92
- }
84
+ const arrayLiteralStarts = {
85
+ qsymbols: "%i",
86
+ qwords: "%w",
87
+ symbols: "%I",
88
+ words: "%W"
89
+ };
93
90
 
94
91
  // An array node is any literal array in Ruby. This includes all of the special
95
92
  // array literals as well as regular arrays. If it is a special array literal
@@ -105,30 +102,40 @@ function printArray(path, opts, print) {
105
102
  return printEmptyCollection(path, opts, "[", "]");
106
103
  }
107
104
 
108
- // If we have an array that contains only simple string literals with no
109
- // spaces or interpolation, then we're going to print a %w array.
110
- if (opts.rubyArrayLiteral && isStringArray(args)) {
111
- const printString = (stringPath) => stringPath.call(print, "body", 0);
112
- const parts = path.map(printString, "body", 0, "body");
105
+ if (opts.rubyArrayLiteral) {
106
+ // If we have an array that contains only simple string literals with no
107
+ // spaces or interpolation, then we're going to print a %w array.
108
+ if (isStringArray(args)) {
109
+ const printString = (stringPath) => stringPath.call(print, "body", 0);
110
+ const parts = path.map(printString, "body", 0, "body");
113
111
 
114
- return printSpecialArrayParts(["%w"].concat(parts));
115
- }
112
+ return printArrayLiteral("%w", parts);
113
+ }
116
114
 
117
- // If we have an array that contains only simple symbol literals with no
118
- // interpolation, then we're going to print a %i array.
119
- if (opts.rubyArrayLiteral && isSymbolArray(args)) {
120
- const printSymbol = (symbolPath) => symbolPath.call(print, "body", 0);
121
- const parts = path.map(printSymbol, "body", 0, "body");
115
+ // If we have an array that contains only simple symbol literals with no
116
+ // interpolation, then we're going to print a %i array.
117
+ if (isSymbolArray(args)) {
118
+ const printSymbol = (symbolPath) => symbolPath.call(print, "body", 0);
119
+ const parts = path.map(printSymbol, "body", 0, "body");
122
120
 
123
- return printSpecialArrayParts(["%i"].concat(parts));
121
+ return printArrayLiteral("%i", parts);
122
+ }
124
123
  }
125
124
 
126
125
  // If we don't have a regular args node at this point then we have a special
127
126
  // array literal. In that case we're going to print out the body (which will
128
127
  // return to us an array with the first one being the start of the array) and
129
- // send that over to the printSpecialArrayParts function.
128
+ // send that over to the printArrayLiteral function.
130
129
  if (!["args", "args_add_star"].includes(args.type)) {
131
- return printSpecialArrayParts(path.call(print, "body", 0));
130
+ return path.call(
131
+ (arrayPath) =>
132
+ printArrayLiteral(
133
+ arrayLiteralStarts[arrayPath.getValue().type],
134
+ arrayPath.map(print, "body")
135
+ ),
136
+ "body",
137
+ 0
138
+ );
132
139
  }
133
140
 
134
141
  // Here we have a normal array of any type of object with no special literal
@@ -151,9 +158,5 @@ function printArray(path, opts, print) {
151
158
 
152
159
  module.exports = {
153
160
  array: printArray,
154
- qsymbols: printSpecialArray("%i"),
155
- qwords: printSpecialArray("%w"),
156
- symbols: printSpecialArray("%I"),
157
- word: printSpecialArrayWord,
158
- words: printSpecialArray("%W")
161
+ word: printArrayLiteralWord
159
162
  };
@@ -73,7 +73,7 @@ function printCommand(path, opts, print) {
73
73
  } else if (hasDef(path.getValue())) {
74
74
  breakArgs = joinedArgs;
75
75
  } else {
76
- breakArgs = align(command.length + 1, joinedArgs);
76
+ breakArgs = align(docLength(command) + 1, joinedArgs);
77
77
  }
78
78
 
79
79
  return group(
@@ -1,5 +1,5 @@
1
1
  const { concat, group, lineSuffix, join } = require("../../prettier");
2
- const { literalLineNoBreak } = require("../../utils");
2
+ const { literallineWithoutBreakParent } = require("../../utils");
3
3
 
4
4
  function printHeredoc(path, opts, print) {
5
5
  const { body, ending } = path.getValue();
@@ -11,7 +11,7 @@ function printHeredoc(path, opts, print) {
11
11
  }
12
12
 
13
13
  // In this case, the part of the string is just regular string content
14
- return join(literalLineNoBreak, part.body.split("\n"));
14
+ return join(literallineWithoutBreakParent, part.body.split("\n"));
15
15
  });
16
16
 
17
17
  // We use a literalline break because matching indentation is required
@@ -23,7 +23,9 @@ function printHeredoc(path, opts, print) {
23
23
  concat([
24
24
  path.call(print, "beging"),
25
25
  lineSuffix(
26
- group(concat([literalLineNoBreak].concat(parts).concat(ending)))
26
+ group(
27
+ concat([literallineWithoutBreakParent].concat(parts).concat(ending))
28
+ )
27
29
  )
28
30
  ])
29
31
  );
data/src/ruby/parser.js CHANGED
@@ -4,8 +4,8 @@ const parseSync = require("../parser/parseSync");
4
4
  // to prettier a JavaScript object that is the equivalent AST that represents
5
5
  // the code stored in that string. We accomplish this by spawning a new Ruby
6
6
  // process of parser.rb and reading JSON off STDOUT.
7
- function parse(text, _parsers, _opts) {
8
- return parseSync("ruby", text);
7
+ function parse(text, _parsers, opts) {
8
+ return parseSync("ruby", text, opts);
9
9
  }
10
10
 
11
11
  const pragmaPattern = /#\s*@(prettier|format)/;
data/src/ruby/parser.rb CHANGED
@@ -21,7 +21,40 @@ module Prettier
21
21
  end
22
22
 
23
23
  class Prettier::Parser < Ripper
24
- attr_reader :source, :lines, :scanner_events, :line_counts
24
+ # Represents a line in the source. If this class is being used, it means that
25
+ # every character in the string is 1 byte in length, so we can just return the
26
+ # start of the line + the index.
27
+ class SingleByteString
28
+ def initialize(start)
29
+ @start = start
30
+ end
31
+
32
+ def [](byteindex)
33
+ @start + byteindex
34
+ end
35
+ end
36
+
37
+ # Represents a line in the source. If this class is being used, it means that
38
+ # there are characters in the string that are multi-byte, so we will build up
39
+ # an array of indices, such that array[byteindex] will be equal to the index
40
+ # of the character within the string.
41
+ class MultiByteString
42
+ def initialize(start, line)
43
+ @indices = []
44
+
45
+ line
46
+ .each_char
47
+ .with_index(start) do |char, index|
48
+ char.bytesize.times { @indices << index }
49
+ end
50
+ end
51
+
52
+ def [](byteindex)
53
+ @indices[byteindex]
54
+ end
55
+ end
56
+
57
+ attr_reader :source, :lines, :scanner_events
25
58
 
26
59
  # This is an attr_accessor so Stmts objects can grab comments out of this
27
60
  # array and attach them to themselves.
@@ -40,9 +73,23 @@ class Prettier::Parser < Ripper
40
73
  @heredocs = []
41
74
 
42
75
  @scanner_events = []
43
- @line_counts = [0]
76
+ @line_counts = []
77
+
78
+ # Here we're going to build up a list of SingleByteString or MultiByteString
79
+ # objects. They're each going to represent a string in the source. They are
80
+ # used by the `char_pos` method to determine where we are in the source
81
+ # string.
82
+ last_index = 0
44
83
 
45
- @source.lines.each { |line| @line_counts << @line_counts.last + line.size }
84
+ @source.lines.each do |line|
85
+ if line.size == line.bytesize
86
+ @line_counts << SingleByteString.new(last_index)
87
+ else
88
+ @line_counts << MultiByteString.new(last_index, line)
89
+ end
90
+
91
+ last_index += line.size
92
+ end
46
93
  end
47
94
 
48
95
  def self.parse(source)
@@ -60,7 +107,7 @@ class Prettier::Parser < Ripper
60
107
  # this line, then we add the number of columns into this line that we've gone
61
108
  # through.
62
109
  def char_pos
63
- line_counts[lineno - 1] + column
110
+ @line_counts[lineno - 1][column]
64
111
  end
65
112
 
66
113
  # As we build up a list of scanner events, we'll periodically need to go
@@ -518,6 +565,12 @@ class Prettier::Parser < Ripper
518
565
  # binary is a parser event that represents a binary operation between two
519
566
  # values.
520
567
  def on_binary(left, oper, right)
568
+ # On most Ruby implementations, oper is a Symbol that represents that
569
+ # operation being performed. For instance in the example `1 < 2`, the `oper`
570
+ # object would be `:<`. However, on JRuby, it's an `@op` node, so here we're
571
+ # going to explicitly convert it into the same normalized form.
572
+ oper = scanner_events.delete(oper)[:body] unless oper.is_a?(Symbol)
573
+
521
574
  {
522
575
  type: :binary,
523
576
  body: [left, oper, right],
@@ -609,7 +662,7 @@ class Prettier::Parser < Ripper
609
662
  body: [block_var, stmts],
610
663
  sl: beging[:sl],
611
664
  sc: beging[:sc],
612
- el: ending[:el],
665
+ el: [ending[:el], stmts[:el]].max,
613
666
  ec: ending[:ec]
614
667
  }
615
668
  end
@@ -662,7 +715,7 @@ class Prettier::Parser < Ripper
662
715
  body: [receiver, oper, sending],
663
716
  sl: receiver[:sl],
664
717
  sc: receiver[:sc],
665
- el: ending[:el],
718
+ el: [ending[:el], receiver[:el]].max,
666
719
  ec: ending[:ec]
667
720
  }
668
721
  end
@@ -1676,6 +1729,28 @@ class Prettier::Parser < Ripper
1676
1729
  )
1677
1730
  end
1678
1731
 
1732
+ # A special parser error so that we can get nice syntax displays on the error
1733
+ # message when prettier prints out the results.
1734
+ class ParserError < StandardError
1735
+ attr_reader :lineno, :column
1736
+
1737
+ def initialize(error, lineno, column)
1738
+ super(error)
1739
+ @lineno = lineno
1740
+ @column = column
1741
+ end
1742
+ end
1743
+
1744
+ # If we encounter a parse error, just immediately bail out so that our runner
1745
+ # can catch it.
1746
+ def on_parse_error(error, *)
1747
+ raise ParserError.new(error, lineno, column)
1748
+ end
1749
+ alias on_alias_error on_parse_error
1750
+ alias on_assign_error on_parse_error
1751
+ alias on_class_name_error on_parse_error
1752
+ alias on_param_error on_parse_error
1753
+
1679
1754
  # The program node is the very top of the AST. Here we'll attach all of
1680
1755
  # the comments that we've gathered up over the course of parsing the
1681
1756
  # source string. We'll also attach on the __END__ content if there was