prettier 1.5.0 → 1.5.5

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.
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