prettier 1.4.0 → 1.5.4

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.
@@ -1,8 +1,9 @@
1
1
  const { concat, group, hardline, indent, line } = require("../../prettier");
2
+ const { isEmptyBodyStmt } = require("../../utils");
2
3
 
3
4
  function printMethod(offset) {
4
5
  return function printMethodWithOffset(path, opts, print) {
5
- const [_name, params, body] = path.getValue().body.slice(offset);
6
+ const [_name, params, bodystmt] = path.getValue().body.slice(offset);
6
7
  const declaration = ["def "];
7
8
 
8
9
  // In this case, we're printing a method that's defined as a singleton, so
@@ -24,16 +25,8 @@ function printMethod(offset) {
24
25
  parens ? ")" : ""
25
26
  );
26
27
 
27
- // If the body is empty, we can replace with a ;
28
- const stmts = body.body[0].body;
29
-
30
- if (
31
- !body.body.slice(1).some((node) => node) &&
32
- stmts.length === 1 &&
33
- stmts[0].type === "void_stmt" &&
34
- !stmts[0].comments
35
- ) {
36
- return group(concat(declaration.concat(["; end"])));
28
+ if (isEmptyBodyStmt(bodystmt)) {
29
+ return group(concat(declaration.concat("; end")));
37
30
  }
38
31
 
39
32
  return group(
@@ -12,15 +12,13 @@ const {
12
12
  trim
13
13
  } = require("../../prettier");
14
14
 
15
+ const { isEmptyStmts } = require("../../utils");
16
+
15
17
  function printBodyStmt(path, opts, print) {
16
18
  const [stmts, rescue, elseClause, ensure] = path.getValue().body;
17
19
  const parts = [];
18
20
 
19
- if (
20
- stmts.body.length > 1 ||
21
- stmts.body[0].type != "void_stmt" ||
22
- stmts.body[0].comments
23
- ) {
21
+ if (!isEmptyStmts(stmts)) {
24
22
  parts.push(path.call(print, "body", 0));
25
23
  }
26
24
 
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
@@ -17,10 +17,44 @@ require 'delegate'
17
17
  require 'json'
18
18
  require 'ripper'
19
19
 
20
- module Prettier; end
20
+ module Prettier
21
+ end
21
22
 
22
23
  class Prettier::Parser < Ripper
23
- 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
24
58
 
25
59
  # This is an attr_accessor so Stmts objects can grab comments out of this
26
60
  # array and attach them to themselves.
@@ -39,9 +73,23 @@ class Prettier::Parser < Ripper
39
73
  @heredocs = []
40
74
 
41
75
  @scanner_events = []
42
- @line_counts = [0]
76
+ @line_counts = []
43
77
 
44
- @source.lines.each { |line| @line_counts << @line_counts.last + line.size }
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
83
+
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
45
93
  end
46
94
 
47
95
  def self.parse(source)
@@ -59,7 +107,7 @@ class Prettier::Parser < Ripper
59
107
  # this line, then we add the number of columns into this line that we've gone
60
108
  # through.
61
109
  def char_pos
62
- line_counts[lineno - 1] + column
110
+ @line_counts[lineno - 1][column]
63
111
  end
64
112
 
65
113
  # As we build up a list of scanner events, we'll periodically need to go
@@ -517,6 +565,12 @@ class Prettier::Parser < Ripper
517
565
  # binary is a parser event that represents a binary operation between two
518
566
  # values.
519
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
+
520
574
  {
521
575
  type: :binary,
522
576
  body: [left, oper, right],
@@ -1675,6 +1729,28 @@ class Prettier::Parser < Ripper
1675
1729
  )
1676
1730
  end
1677
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
+
1678
1754
  # The program node is the very top of the AST. Here we'll attach all of
1679
1755
  # the comments that we've gathered up over the course of parsing the
1680
1756
  # source string. We'll also attach on the __END__ content if there was
data/src/ruby/printer.js CHANGED
@@ -38,7 +38,8 @@ const noComments = [
38
38
  "args_add_star",
39
39
  "mlhs",
40
40
  "mlhs_add_post",
41
- "mlhs_add_star"
41
+ "mlhs_add_star",
42
+ "mlhs_paren"
42
43
  ];
43
44
 
44
45
  // Certain nodes are used more for organizational purposed than for actually
@@ -97,8 +98,12 @@ function getCommentChildNodes(node) {
97
98
 
98
99
  return parts;
99
100
  }
100
- default:
101
- return node.body;
101
+ default: {
102
+ if (Array.isArray(node.body)) {
103
+ return node.body.filter((child) => child && typeof child === "object");
104
+ }
105
+ return [];
106
+ }
102
107
  }
103
108
  }
104
109
 
data/src/utils.js CHANGED
@@ -1,10 +1,11 @@
1
1
  module.exports = {
2
2
  containsAssignment: require("./utils/containsAssignment"),
3
3
  getTrailingComma: require("./utils/getTrailingComma"),
4
+ isEmptyBodyStmt: require("./utils/isEmptyBodyStmt"),
4
5
  isEmptyStmts: require("./utils/isEmptyStmts"),
5
6
  hasAncestor: require("./utils/hasAncestor"),
6
7
  literal: require("./utils/literal"),
7
- literalLineNoBreak: require("./utils/literalLineNoBreak"),
8
+ literallineWithoutBreakParent: require("./utils/literallineWithoutBreakParent"),
8
9
  makeCall: require("./utils/makeCall"),
9
10
  noIndent: require("./utils/noIndent"),
10
11
  printEmptyCollection: require("./utils/printEmptyCollection"),
@@ -1,4 +1,11 @@
1
- const needsParens = ["args", "assign", "assoc_new", "massign", "opassign"];
1
+ const needsParens = [
2
+ "args",
3
+ "assign",
4
+ "assoc_new",
5
+ "call",
6
+ "massign",
7
+ "opassign"
8
+ ];
2
9
 
3
10
  // If you have a modifier statement (for instance an inline if statement or an
4
11
  // inline while loop) there are times when you need to wrap the entire statement
@@ -0,0 +1,7 @@
1
+ const isEmptyStmts = require("./isEmptyStmts");
2
+
3
+ function isEmptyBodyStmt(node) {
4
+ return isEmptyStmts(node.body[0]) && !node.body.slice(1).some(Boolean);
5
+ }
6
+
7
+ module.exports = isEmptyBodyStmt;
@@ -1,7 +1,11 @@
1
- const isEmptyStmts = (node) =>
2
- node &&
3
- node.type === "stmts" &&
4
- node.body.length === 1 &&
5
- node.body[0].type === "void_stmt";
1
+ function isEmptyStmts(node) {
2
+ return (
3
+ node &&
4
+ node.type === "stmts" &&
5
+ node.body.length === 1 &&
6
+ node.body[0].type === "void_stmt" &&
7
+ !node.body[0].comments
8
+ );
9
+ }
6
10
 
7
11
  module.exports = isEmptyStmts;
@@ -0,0 +1,7 @@
1
+ const literallineWithoutBreakParent = {
2
+ type: "line",
3
+ hard: true,
4
+ literal: true
5
+ };
6
+
7
+ module.exports = literallineWithoutBreakParent;
@@ -1,5 +1,11 @@
1
1
  const { concat, group, hardline, indent, join, line } = require("../prettier");
2
2
 
3
+ function containedWithin(node) {
4
+ return function containedWithinNode(comment) {
5
+ return comment.sc >= node.sc && comment.ec <= node.ec;
6
+ };
7
+ }
8
+
3
9
  // Empty collections are array or hash literals that do not contain any
4
10
  // contents. They can, however, have comments inside the body. You can solve
5
11
  // this by having a child node inside the array that gets the comments attached
@@ -7,11 +13,12 @@ const { concat, group, hardline, indent, join, line } = require("../prettier");
7
13
  // print out the non-leading comments here.
8
14
  function printEmptyCollection(path, opts, startToken, endToken) {
9
15
  const node = path.getValue();
16
+ const containedWithinNode = containedWithin(node);
10
17
 
11
18
  // If there are no comments or only leading comments, then we can just print
12
19
  // out the start and end token and be done, as there are no comments inside
13
20
  // the body of this node.
14
- if (!node.comments || !node.comments.some((comment) => !comment.leading)) {
21
+ if (!node.comments || !node.comments.some(containedWithinNode)) {
15
22
  return `${startToken}${endToken}`;
16
23
  }
17
24
 
@@ -21,7 +28,7 @@ function printEmptyCollection(path, opts, startToken, endToken) {
21
28
  const printComment = (commentPath) => {
22
29
  const comment = commentPath.getValue();
23
30
 
24
- if (!comment.leading) {
31
+ if (containedWithinNode(comment)) {
25
32
  comment.printed = true;
26
33
  comments.push(opts.printer.printComment(commentPath));
27
34
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prettier
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Deisz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-15 00:00:00.000000000 Z
11
+ date: 2021-03-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -97,9 +97,10 @@ files:
97
97
  - src/utils/getTrailingComma.js
98
98
  - src/utils/hasAncestor.js
99
99
  - src/utils/inlineEnsureParens.js
100
+ - src/utils/isEmptyBodyStmt.js
100
101
  - src/utils/isEmptyStmts.js
101
102
  - src/utils/literal.js
102
- - src/utils/literalLineNoBreak.js
103
+ - src/utils/literallineWithoutBreakParent.js
103
104
  - src/utils/makeCall.js
104
105
  - src/utils/noIndent.js
105
106
  - src/utils/printEmptyCollection.js
@@ -123,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
124
  - !ruby/object:Gem::Version
124
125
  version: '0'
125
126
  requirements: []
126
- rubygems_version: 3.1.4
127
+ rubygems_version: 3.2.3
127
128
  signing_key:
128
129
  specification_version: 4
129
130
  summary: prettier plugin for the Ruby programming language
@@ -1,7 +0,0 @@
1
- const literalLineNoBreak = {
2
- type: "line",
3
- hard: true,
4
- literal: true
5
- };
6
-
7
- module.exports = literalLineNoBreak;