prettier 2.0.0.pre.rc1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1015fa9f7c5b4f580afa9c6b24042c8799762e5d13835dbb492abfe33f676b8
4
- data.tar.gz: 53045f82f75561082c6120d836d3abdffb07cccb31e5272442ef2608014f8f6d
3
+ metadata.gz: a8393d82622bcce83298aa8e2833b37bccf9742b0a67e81cd3b730e57e6795b8
4
+ data.tar.gz: a66af4efc73854f143e0faa288fdde112bf87ba45364af3efd862a179734453c
5
5
  SHA512:
6
- metadata.gz: 4f4541af3e4e4047f03c4c34890506b25126d34e052b92023d40e7bb68b5184cfce9c91ba5794478b21b61952e1823d4f7e08d51b52d468a9de61f270f9d61a0
7
- data.tar.gz: 983d6da92e456dae0f081a2ee4b77f4a47d540415f991c51d91006a2847ac38937574e76f82bd376fb9e47401deeb5bd77414c10b3ab80a9d4adaa7a7e66499e
6
+ metadata.gz: f780174b5b038bfd9583c637caefff23e442f4aef626e9e33769811c15afd7c267bb78f20c4eb223ab4b50f3c0b6664123c6ce00d997ff0a571b0d57228f5070
7
+ data.tar.gz: bdfbd3f42b4db020059b511b3176ee7b5393a5a008136dd06a584c26df69afbcfe7d937e6151e22029858d71bad68e8c68eb07241e67771debd802cf733c282d
data/CHANGELOG.md CHANGED
@@ -6,7 +6,43 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [2.0.0-rc1]
9
+ ## [2.0.0] - 2021-10-28
10
+
11
+ ### Changed
12
+
13
+ - [#1018](https://github.com/prettier/plugin-ruby/issues/1018) - rindek, kddnewton - Ensure brackets are used when matching an array pattern with a single element.
14
+ - [#906](https://github.com/prettier/plugin-ruby/issues/906) - Hansenq, kddnewton - Turn off the `Style/MultilineBlockChain` rubocop rule in our shipped configuration because multiple chained method calls with blocks can potentially conflict with rubocop's desired output.
15
+
16
+ ## [2.0.0-rc4] - 2021-10-18
17
+
18
+ ### Added
19
+
20
+ - [#993](https://github.com/prettier/plugin-ruby/pull/993) - kddnewton - Nicer error message if you don't have the necessary JavaScript files to run prettier.
21
+ - [#996](https://github.com/prettier/plugin-ruby/pull/996) - nbudin - Allow `@prettier/plugin-ruby` to run in yarn's plug'n'play mode.
22
+
23
+ ### Changed
24
+
25
+ - [#1000](https://github.com/prettier/plugin-ruby/pull/1000) - nbudin, kddnewton - Fix for rescuing single top-level exceptions in `rescue` clauses.
26
+
27
+ ## [2.0.0-rc3] - 2021-10-01
28
+
29
+ ### Changed
30
+
31
+ - [#987](https://github.com/prettier/plugin-ruby/pull/9870) - valscion - Ignore stderr when checking for node <-> ruby connection clients, restoring the behavior of v1.x
32
+ - [#989](https://github.com/prettier/plugin-ruby/issues/989) - hubertjakubiak, kddnewton - Make sure comments after the keyword/lbrace are not moved inside the body of the statements of do and brace blocks.
33
+
34
+ ## [2.0.0-rc2] - 2021-09-30
35
+
36
+ ### Added
37
+
38
+ - [#979](https://github.com/prettier/plugin-ruby/issues/979) - ronocod, kddnewton - Alignment of `to_not` is explicitly allowed to not indent to better support rspec.
39
+ - [#894](https://github.com/prettier/plugin-ruby/issues/894) - mister-what, kddnewton - Add a warning that this plugin will not function with the plug'n'play filesystem provided by yarn berry.
40
+
41
+ ### Changed
42
+
43
+ - [#943](https://github.com/prettier/plugin-ruby/issues/943) - valscion, kddnewton - Trailing call operators that are followed by comments should stay on the first line.
44
+
45
+ ## [2.0.0-rc1] - 2021-09-30
10
46
 
11
47
  ### Added
12
48
 
@@ -1151,7 +1187,11 @@ would previously result in `array[]`, but now prints properly.
1151
1187
 
1152
1188
  - Initial release 🎉
1153
1189
 
1154
- [unreleased]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc1...HEAD
1190
+ [unreleased]: https://github.com/prettier/plugin-ruby/compare/v2.0.0...HEAD
1191
+ [2.0.0]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc4...v2.0.0
1192
+ [2.0.0-rc4]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc3...v2.0.0-rc4
1193
+ [2.0.0-rc3]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc2...v2.0.0-rc3
1194
+ [2.0.0-rc2]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc1...v2.0.0-rc2
1155
1195
  [2.0.0-rc1]: https://github.com/prettier/plugin-ruby/compare/v1.6.1...v2.0.0-rc1
1156
1196
  [1.6.1]: https://github.com/prettier/plugin-ruby/compare/v1.6.0...v1.6.1
1157
1197
  [1.6.0]: https://github.com/prettier/plugin-ruby/compare/v1.5.5...v1.6.0
@@ -58,8 +58,53 @@ exports.getInfoFilepath = getInfoFilepath;
58
58
  // will read that information in order to enable us to connect to it in the
59
59
  // spawnSync function.
60
60
  function spawnServer() {
61
+ const tempDir = (0, fs_1.mkdtempSync)(path_1.default.join(os_1.default.tmpdir(), "prettier-plugin-ruby-"));
61
62
  const filepath = getInfoFilepath();
62
- const server = (0, child_process_1.spawn)("ruby", [path_1.default.join(__dirname, "./server.rb"), filepath], {
63
+ let serverRbPath = path_1.default.join(__dirname, "./server.rb");
64
+ let getInfoJsPath = path_1.default.join(__dirname, "./getInfo.js");
65
+ let cleanupTempFiles;
66
+ if (runningInPnPZip()) {
67
+ // If we're running in a Yarn PnP environment inside a ZIP file, it's not possible to run
68
+ // the Ruby server or the getInfo.js script directly. Instead, we need to copy them and all
69
+ // the files they depend on to a temporary directory.
70
+ const sourceFiles = [
71
+ "parser/server.rb",
72
+ "parser/getInfo.js",
73
+ "parser/netcat.js",
74
+ "ruby/parser.rb",
75
+ "rbs/parser.rb",
76
+ "haml/parser.rb"
77
+ ];
78
+ serverRbPath = path_1.default.join(tempDir, "parser", "server.rb");
79
+ getInfoJsPath = path_1.default.join(tempDir, "parser", "getInfo.js");
80
+ sourceFiles.forEach((rubyFile) => {
81
+ const destDir = path_1.default.join(tempDir, path_1.default.dirname(rubyFile));
82
+ if (!(0, fs_1.existsSync)(destDir)) {
83
+ (0, fs_1.mkdirSync)(destDir);
84
+ }
85
+ (0, fs_1.copyFileSync)(path_1.default.join(__dirname, "..", rubyFile), path_1.default.join(tempDir, rubyFile));
86
+ });
87
+ cleanupTempFiles = () => {
88
+ [
89
+ getInfoJsPath,
90
+ ...sourceFiles.map((rubyFile) => path_1.default.join(tempDir, rubyFile))
91
+ ].forEach((tmpFilePath) => {
92
+ if ((0, fs_1.existsSync)(tmpFilePath)) {
93
+ (0, fs_1.unlinkSync)(tmpFilePath);
94
+ }
95
+ });
96
+ sourceFiles.forEach((rubyFile) => {
97
+ const tempSubdir = path_1.default.join(tempDir, path_1.default.dirname(rubyFile));
98
+ if ((0, fs_1.existsSync)(tempSubdir)) {
99
+ (0, fs_1.rmdirSync)(tempSubdir);
100
+ }
101
+ });
102
+ if ((0, fs_1.existsSync)(tempDir)) {
103
+ (0, fs_1.rmdirSync)(tempDir);
104
+ }
105
+ };
106
+ }
107
+ const server = (0, child_process_1.spawn)("ruby", [serverRbPath, filepath], {
63
108
  env: Object.assign({}, process_1.default.env, { LANG: getLang() }),
64
109
  detached: true,
65
110
  stdio: "inherit"
@@ -69,6 +114,9 @@ function spawnServer() {
69
114
  if ((0, fs_1.existsSync)(filepath)) {
70
115
  (0, fs_1.unlinkSync)(filepath);
71
116
  }
117
+ if (cleanupTempFiles != null) {
118
+ cleanupTempFiles();
119
+ }
72
120
  try {
73
121
  if (server.pid) {
74
122
  process_1.default.kill(-server.pid);
@@ -80,10 +128,7 @@ function spawnServer() {
80
128
  }
81
129
  }
82
130
  });
83
- const info = (0, child_process_1.spawnSync)("node", [
84
- path_1.default.join(__dirname, "./getInfo.js"),
85
- filepath
86
- ]);
131
+ const info = (0, child_process_1.spawnSync)("node", [getInfoJsPath, filepath]);
87
132
  if (info.status !== 0) {
88
133
  throw new Error(`
89
134
  We failed to spawn our parser server. Please report this error on GitHub
@@ -95,6 +140,12 @@ function spawnServer() {
95
140
  const [cmd, ...args] = info.stdout.toString().split(" ");
96
141
  return { cmd, args };
97
142
  }
143
+ // If we're in a yarn Plug'n'Play environment, then the relative paths being
144
+ // used by the parser server and the various scripts used to communicate
145
+ // therein are not going to work with its virtual file system.
146
+ function runningInPnPZip() {
147
+ return process_1.default.versions.pnp && __dirname.includes(".zip");
148
+ }
98
149
  // Formats and sends a request to the parser server. We use netcat (or something
99
150
  // like it) here since Prettier requires the results of `parse` to be
100
151
  // synchronous and Node.js does not offer a mechanism for synchronous socket
@@ -112,8 +112,9 @@ candidates.map! do |candidate|
112
112
  Thread.new do
113
113
  Thread.current.report_on_exception = false
114
114
 
115
- stdout, status =
116
- Open3.capture2("#{candidate} #{information}", stdin_data: 'ping')
115
+ # We do not care about stderr here, so throw it away
116
+ stdout, _stderr, status =
117
+ Open3.capture3("#{candidate} #{information}", stdin_data: 'ping')
117
118
 
118
119
  candidate if JSON.parse(stdout) == 'pong' && status.exitstatus == 0
119
120
  rescue StandardError
@@ -17,6 +17,23 @@ const printBlockVar = (path, opts, print) => {
17
17
  return parts;
18
18
  };
19
19
  exports.printBlockVar = printBlockVar;
20
+ // You have to go through the main print function if you could potentially have
21
+ // comments attached. So we're doing this weird reflection on the printed docs
22
+ // to retroactively change the printed keyword depending on if we're using
23
+ // braces or not. Ideally we wouldn't do this, we would instead do this
24
+ // reflection in the child printer, but this keeps the logic to just this file
25
+ // and contains it, so keeping it here for now.
26
+ function printBlockBeging(path, print, useBraces) {
27
+ let docs = print(path);
28
+ const doc = useBraces ? "{" : "do";
29
+ if (Array.isArray(docs)) {
30
+ docs[1] = doc;
31
+ }
32
+ else {
33
+ docs = doc;
34
+ }
35
+ return docs;
36
+ }
20
37
  function printBlock(braces) {
21
38
  return function printBlockWithBraces(path, opts, print) {
22
39
  const [variables, statements] = path.getValue().body;
@@ -34,7 +51,8 @@ function printBlock(braces) {
34
51
  // switch to using braces instead.
35
52
  const useBraces = braces && (0, utils_1.hasAncestor)(path, ["command", "command_call"]);
36
53
  const doBlock = [
37
- useBraces ? " {" : " do",
54
+ " ",
55
+ path.call((begingPath) => printBlockBeging(begingPath, print, useBraces), "beging"),
38
56
  variables ? [" ", path.call(print, "body", 0)] : "",
39
57
  doBlockBody,
40
58
  [softline, useBraces ? "}" : "end"]
@@ -54,7 +72,8 @@ function printBlock(braces) {
54
72
  }
55
73
  const hasBody = stmts.some(({ type }) => type !== "void_stmt");
56
74
  const braceBlock = [
57
- " {",
75
+ " ",
76
+ path.call((begingPath) => printBlockBeging(begingPath, print, true), "beging"),
58
77
  hasBody || variables ? " " : "",
59
78
  variables ? path.call(print, "body", 0) : "",
60
79
  path.call(print, "body", 1),
@@ -9,6 +9,10 @@ const utils_1 = require("../../utils");
9
9
  const toProc_1 = __importDefault(require("../toProc"));
10
10
  const { group, hardline, ifBreak, indent, join, softline } = prettier_1.default;
11
11
  const chained = ["call", "method_add_arg", "method_add_block"];
12
+ function hasLeadingComments(node) {
13
+ var _a;
14
+ return (_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ leading }) => leading);
15
+ }
12
16
  const printCall = (path, opts, print) => {
13
17
  const node = path.getValue();
14
18
  const [receiverNode, , messageNode] = node.body;
@@ -18,26 +22,40 @@ const printCall = (path, opts, print) => {
18
22
  // In this case, "call" is returned for the 3rd child node. We don't alter
19
23
  // call syntax so if `call` is implicit, we don't print it out.
20
24
  const messageDoc = messageNode === "call" ? "" : path.call(print, "body", 2);
25
+ // Create some arrays that are going to represent each side of our call.
26
+ let leftSideDoc = [receiverDoc];
27
+ let rightSideDoc = [operatorDoc, messageDoc];
28
+ // If there are leading comments on the right side of the call, then it means
29
+ // we have a structure where there's a receiver and an operator together, then
30
+ // a comment, then the message, as in:
31
+ //
32
+ // foo.
33
+ // # comment
34
+ // baz
35
+ //
36
+ // In the case we need to group the receiver and the operator together or
37
+ // we'll end up with a syntax error.
38
+ const operatorIsTrailing = messageNode !== "call" && hasLeadingComments(messageNode);
39
+ if (operatorIsTrailing) {
40
+ leftSideDoc = [receiverDoc, operatorDoc];
41
+ rightSideDoc = [messageDoc];
42
+ }
21
43
  // For certain left sides of the call nodes, we want to attach directly to
22
44
  // the } or end.
23
45
  if (utils_1.noIndent.includes(receiverNode.type)) {
24
- return [receiverDoc, operatorDoc, messageDoc];
46
+ return [leftSideDoc, rightSideDoc];
25
47
  }
26
- // The right side of the call node, as in everything including the operator
27
- // and beyond.
28
- let rightSideDoc = [
29
- receiverNode.comments ? hardline : softline,
30
- operatorDoc,
31
- messageDoc
32
- ];
33
- // This is very specialized behavior wherein we group .where.not calls
34
- // together because it looks better. For more information, see
35
- // https://github.com/prettier/plugin-ruby/issues/862.
36
48
  if (receiverNode.type === "call" &&
37
49
  receiverNode.body[2] !== "call" &&
38
50
  receiverNode.body[2].body === "where" &&
39
51
  messageDoc === "not") {
40
- rightSideDoc = [operatorDoc, messageDoc];
52
+ // This is very specialized behavior wherein we group .where.not calls
53
+ // together because it looks better. For more information, see
54
+ // https://github.com/prettier/plugin-ruby/issues/862.
55
+ }
56
+ else {
57
+ // Otherwise, we're going to put a line node into the right side doc.
58
+ rightSideDoc.unshift(receiverNode.comments ? hardline : softline);
41
59
  }
42
60
  // Get a reference to the parent node so we can check if we're inside a chain
43
61
  const parentNode = path.getParentNode();
@@ -46,8 +64,30 @@ const printCall = (path, opts, print) => {
46
64
  if (chained.includes(parentNode.type) && !node.comments) {
47
65
  parentNode.chain = (node.chain || 0) + 1;
48
66
  parentNode.callChain = (node.callChain || 0) + 1;
49
- parentNode.breakDoc = (node.breakDoc || [receiverDoc]).concat(rightSideDoc);
50
67
  parentNode.firstReceiverType = node.firstReceiverType || receiverNode.type;
68
+ // Here we're going to determine what doc nodes to send up to the parent
69
+ // node to represent when we're in the multi-line form.
70
+ let breakDocLHS;
71
+ if (node.breakDoc && operatorIsTrailing) {
72
+ // Here we already have a child node that has passed up its
73
+ // representation. In this case node.breakDoc represents the receiver
74
+ // without any lines inserted. With regard to this node, it means it's
75
+ // everything up until the operator. So we're just going to append the
76
+ // operator.
77
+ breakDocLHS = node.breakDoc.concat(operatorDoc);
78
+ }
79
+ else if (node.breakDoc) {
80
+ // Here we don't need a trailing operator, so we're just going to use the
81
+ // existing node.breakDoc. The operator will be a part of the rightSideDoc
82
+ // variable.
83
+ breakDocLHS = node.breakDoc;
84
+ }
85
+ else {
86
+ // Here we're at the bottom of the chain, so there's no representation yet
87
+ // for the receiver. So we're just going to pass up the left side.
88
+ breakDocLHS = leftSideDoc;
89
+ }
90
+ parentNode.breakDoc = breakDocLHS.concat(rightSideDoc);
51
91
  }
52
92
  // If we're at the top of a chain, then we're going to print out a nice
53
93
  // multi-line layout if this doesn't break into multiple lines.
@@ -55,11 +95,11 @@ const printCall = (path, opts, print) => {
55
95
  (node.chain || 0) >= 3 &&
56
96
  node.breakDoc) {
57
97
  return ifBreak(group(indent(node.breakDoc.concat(rightSideDoc))), [
58
- receiverDoc,
98
+ leftSideDoc,
59
99
  group(rightSideDoc)
60
100
  ]);
61
101
  }
62
- return group([receiverDoc, group(indent(rightSideDoc))]);
102
+ return group([leftSideDoc, group(indent(rightSideDoc))]);
63
103
  };
64
104
  exports.printCall = printCall;
65
105
  const printMethodAddArg = (path, opts, print) => {
@@ -62,8 +62,8 @@ function hasDef(node) {
62
62
  //
63
63
  // In this case the arguments are aligned to the left side as opposed to being
64
64
  // aligned with the `receive` call.
65
- function skipArgsAlign(path) {
66
- return ["to", "not_to"].includes(path.getValue().body[2].body);
65
+ function skipArgsAlign(node) {
66
+ return ["to", "not_to", "to_not"].includes(node.body[2].body);
67
67
  }
68
68
  // If there is a ternary argument to a command and it's going to get broken
69
69
  // into multiple lines, then we're going to have to use parentheses around the
@@ -110,7 +110,7 @@ const printCommandCall = (path, opts, print) => {
110
110
  breakDoc = parts.concat("(", indent([softline, argDocs]), softline, ")");
111
111
  parts.push(" ");
112
112
  }
113
- else if (skipArgsAlign(path)) {
113
+ else if (skipArgsAlign(node)) {
114
114
  parts.push(" ");
115
115
  breakDoc = parts.concat(argDocs);
116
116
  }
@@ -19,24 +19,36 @@ const printPatternArg = (path, opts, print) => {
19
19
  };
20
20
  const printAryPtn = (path, opts, print) => {
21
21
  const [constant, preargs, splatarg, postargs] = path.getValue().body;
22
- let args = [];
22
+ let argDocs = [];
23
23
  if (preargs) {
24
- args = args.concat(path.map((argPath) => printPatternArg(argPath, opts, print), "body", 1));
24
+ argDocs = argDocs.concat(path.map((argPath) => printPatternArg(argPath, opts, print), "body", 1));
25
25
  }
26
26
  if (splatarg) {
27
- args.push(["*", path.call(print, "body", 2)]);
27
+ argDocs.push(["*", path.call(print, "body", 2)]);
28
28
  }
29
29
  if (postargs) {
30
- args = args.concat(path.map(print, "body", 3));
30
+ argDocs = argDocs.concat(path.map(print, "body", 3));
31
31
  }
32
- args = group(join([",", line], args));
33
- if (constant || patterns.includes(path.getParentNode().type)) {
34
- args = ["[", args, "]"];
32
+ let argDoc = group(join([",", line], argDocs));
33
+ // There are a couple of cases where we _must_ use brackets. They include:
34
+ //
35
+ // * When the number of arguments inside the array pattern is one 1, then we
36
+ // have to include them, otherwise it matches the whole array. Consider the
37
+ // difference between `in [elem]` and `in elem`.
38
+ // * If we have a wrapping constant, then we definitely need the brackets.
39
+ // Consider the difference between `in Const[elem]` and `in Const elem`
40
+ // * If we're nested inside a parent pattern, then we have to have brackets.
41
+ // Consider the difference between `in key: first, second` and
42
+ // `in key: [first, second]`.
43
+ if (argDocs.length === 1 ||
44
+ constant ||
45
+ patterns.includes(path.getParentNode().type)) {
46
+ argDoc = ["[", argDoc, "]"];
35
47
  }
36
48
  if (constant) {
37
- return [path.call(print, "body", 0), args];
49
+ return [path.call(print, "body", 0), argDoc];
38
50
  }
39
- return args;
51
+ return argDoc;
40
52
  };
41
53
  exports.printAryPtn = printAryPtn;
42
54
  const printFndPtn = (path, opts, print) => {
@@ -86,9 +98,10 @@ const printHshPtn = (path, opts, print) => {
86
98
  };
87
99
  exports.printHshPtn = printHshPtn;
88
100
  const printIn = (path, opts, print) => {
101
+ const keyword = "in ";
89
102
  const parts = [
90
- "in ",
91
- align("in ".length, path.call((valuePath) => printPatternArg(valuePath, opts, print), "body", 0)),
103
+ keyword,
104
+ align(keyword.length, path.call((valuePath) => printPatternArg(valuePath, opts, print), "body", 0)),
92
105
  indent([hardline, path.call(print, "body", 1)])
93
106
  ];
94
107
  if (path.getValue().body[2]) {
@@ -52,10 +52,13 @@ const printRescueEx = (path, opts, print) => {
52
52
  const [exception, variable] = path.getValue().body;
53
53
  const parts = [];
54
54
  if (exception) {
55
+ // If there's just one exception being rescued, then it's just going to be a
56
+ // single doc node.
55
57
  let exceptionDoc = path.call(print, "body", 0);
56
- if (Array.isArray(exceptionDoc)) {
57
- const joiner = [",", line];
58
- exceptionDoc = group(join(joiner, exceptionDoc));
58
+ // If there are multiple exceptions being rescued, then we're going to have
59
+ // multiple doc nodes returned as an array that we need to join together.
60
+ if (["mrhs_add_star", "mrhs_new_from_args"].includes(exception.type)) {
61
+ exceptionDoc = group(join([",", line], exceptionDoc));
59
62
  }
60
63
  parts.push(" ", exceptionDoc);
61
64
  }
data/dist/ruby/parser.rb CHANGED
@@ -136,12 +136,6 @@ class Prettier::Parser < Ripper
136
136
  # keyword.
137
137
  @__end__ = nil
138
138
 
139
- # Magic comments are a certain kind of comment that can impact the way the
140
- # file is parsed (encoding/string frozen default/etc.). These scanner events
141
- # are immediately followed by a comment scanner event, so we only need the
142
- # one variable to set/unset it immediately.
143
- @magic_comment = nil
144
-
145
139
  # Heredocs can actually be nested together if you're using interpolation, so
146
140
  # this is a stack of heredoc nodes that are currently being created. When we
147
141
  # get to the scanner event that finishes off a heredoc node, we pop the top
@@ -799,11 +793,15 @@ class Prettier::Parser < Ripper
799
793
  beging = find_scanner_event(:@lbrace)
800
794
  ending = find_scanner_event(:@rbrace)
801
795
 
802
- stmts.bind((block_var || beging)[:ec], ending[:sc])
796
+ stmts.bind(
797
+ find_next_statement_start((block_var || beging)[:ec]),
798
+ ending[:sc]
799
+ )
803
800
 
804
801
  {
805
802
  type: :brace_block,
806
803
  body: [block_var, stmts],
804
+ beging: beging,
807
805
  sl: beging[:sl],
808
806
  sc: beging[:sc],
809
807
  el: [ending[:el], stmts[:el]].max,
@@ -970,22 +968,6 @@ class Prettier::Parser < Ripper
970
968
  start_line = lineno
971
969
  start_char = char_pos
972
970
 
973
- # If we already had special handling of a magic comment, then we can just
974
- # skip and return the value of that node.
975
- if @magic_comment
976
- comment = @magic_comment
977
- @magic_comment = nil
978
-
979
- # At the moment, merging in the value of the string being passed into
980
- # here. In the next major version I'd like to remove this and just use the
981
- # value of the magic comment. At the moment though that would change
982
- # comments like -*- encoding: UTF-8 -*- into encoding: UTF-8 so need to
983
-
984
- # wait for a major version to do that.
985
- @comments << comment.merge(value: body, ec: start_char + value.length - 1)
986
- return comment
987
- end
988
-
989
971
  @comments << {
990
972
  type: :@comment,
991
973
  value: body,
@@ -1208,11 +1190,15 @@ class Prettier::Parser < Ripper
1208
1190
  beging = find_scanner_event(:@kw, 'do')
1209
1191
  ending = find_scanner_event(:@kw, 'end')
1210
1192
 
1211
- bodystmt.bind((block_var || beging)[:ec], ending[:sc])
1193
+ bodystmt.bind(
1194
+ find_next_statement_start((block_var || beging)[:ec]),
1195
+ ending[:sc]
1196
+ )
1212
1197
 
1213
1198
  {
1214
1199
  type: :do_block,
1215
1200
  body: [block_var, bodystmt],
1201
+ beging: beging,
1216
1202
  sl: beging[:sl],
1217
1203
  sc: beging[:sc],
1218
1204
  el: ending[:el],
@@ -2012,20 +1998,12 @@ class Prettier::Parser < Ripper
2012
1998
  # magic_comment is a scanner event that represents the use of a pragma at the
2013
1999
  # beginning of the file. Usually it will inside something like
2014
2000
  # frozen_string_literal (the key) with a value of true (the value). Both
2015
- # children come is a string literals.
2016
- def on_magic_comment(key, value)
2017
- start_line = lineno
2018
- start_char = char_pos
2019
-
2020
- @magic_comment = {
2021
- type: :@comment,
2022
- value: " #{key}: #{value}",
2023
- sl: start_line,
2024
- el: start_line,
2025
- sc: start_char,
2026
- ec: start_char + @line_counts[start_line][-1]
2027
- }
2028
- end
2001
+ # children come is a string literals. We're going to leave these alone as they
2002
+ # come in all kinds of shapes and sizes.
2003
+ #
2004
+ # def on_magic_comment(key, value)
2005
+ # @magic_comment = { value: " #{key}: #{value}" }
2006
+ # end
2029
2007
 
2030
2008
  # massign is a parser event that is a parent node of any kind of multiple
2031
2009
  # assignment. This includes splitting out variables on the left like:
data/dist/ruby/printer.js CHANGED
@@ -67,6 +67,10 @@ const printer = {
67
67
  }
68
68
  return parts;
69
69
  }
70
+ case "brace_block":
71
+ return [node.body[0], node.body[1], node.beging];
72
+ case "do_block":
73
+ return [node.body[0], node.body[1], node.beging];
70
74
  case "paren":
71
75
  return [node.lparen, node.body[0]];
72
76
  default: {
data/exe/rbprettier CHANGED
@@ -4,5 +4,4 @@
4
4
  $:.unshift(File.expand_path(File.join('..', 'lib'), __dir__))
5
5
  require 'prettier'
6
6
 
7
- Prettier.run(ARGV)
8
- exit($?.exitstatus) if $?.exited?
7
+ exit(Prettier.run(ARGV))
data/lib/prettier.rb CHANGED
@@ -1,18 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json' unless defined?(JSON)
4
+ require 'open3'
4
5
 
5
6
  module Prettier
6
7
  PLUGIN = -File.expand_path('..', __dir__)
7
8
  BINARY = -File.join(PLUGIN, 'node_modules', 'prettier', 'bin-prettier.js')
8
9
  VERSION = -JSON.parse(File.read(File.join(PLUGIN, 'package.json')))['version']
9
10
 
10
- class << self
11
- def run(args)
12
- quoted = args.map { |arg| arg.start_with?('-') ? arg : "\"#{arg}\"" }
13
- command = "node #{BINARY} --plugin \"#{PLUGIN}\" #{quoted.join(' ')}"
11
+ def self.run(args)
12
+ quoted = args.map { |arg| arg.start_with?('-') ? arg : "\"#{arg}\"" }
13
+ command = "node #{BINARY} --plugin \"#{PLUGIN}\" #{quoted.join(' ')}"
14
14
 
15
- system({ 'RBPRETTIER' => '1' }, command)
15
+ stdout, stderr, status = Open3.capture3({ 'RBPRETTIER' => '1' }, command)
16
+ STDOUT.puts(stdout)
17
+
18
+ # If we completed successfully, then just exit out.
19
+ exitstatus = status.exitstatus
20
+ return exitstatus if exitstatus == 0
21
+
22
+ if stderr.match?(%r{Cannot find module '/.+?/bin-prettier.js'})
23
+ # If we're missing bin-prettier.js, then it's possible the user installed
24
+ # the gem through git, which wouldn't have installed the requisite
25
+ # JavaScript files.
26
+ STDERR.puts(<<~MSG)
27
+ Could not find the JavaScript files necessary to run prettier.
28
+
29
+ If you installed this dependency through git instead of from rubygems,
30
+ it does not install the necessary files by default. To fix this you can
31
+ either install them yourself by cd-ing into the directory where this gem
32
+ is located (#{File.expand_path('..', __dir__)}) and running:
33
+
34
+ `yarn && yarn prepublishOnly`
35
+ or
36
+ `npm install && npm run prepublishOnly`
37
+ or
38
+ you can change the source in your Gemfile to point directly to rubygems.
39
+ MSG
40
+ else
41
+ # Otherwise, just print out the same error that prettier emitted, as it's
42
+ # unknown to us.
43
+ STDERR.puts(stderr)
16
44
  end
45
+
46
+ # Make sure we still exit with the same status code the prettier emitted.
47
+ exitstatus
17
48
  end
18
49
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "2.0.0-rc1",
3
+ "version": "2.0.0",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
5
  "main": "dist/plugin.js",
6
6
  "scripts": {
@@ -26,9 +26,9 @@
26
26
  "@types/jest": "^27.0.1",
27
27
  "@types/node": "^16.9.1",
28
28
  "@types/prettier": "^2.3.2",
29
- "@typescript-eslint/eslint-plugin": "^4.31.2",
30
- "@typescript-eslint/parser": "^4.31.2",
31
- "eslint": "^7.22.0",
29
+ "@typescript-eslint/eslint-plugin": "^5.2.0",
30
+ "@typescript-eslint/parser": "^5.2.0",
31
+ "eslint": "^8.1.0",
32
32
  "eslint-config-prettier": "^8.0.0",
33
33
  "husky": "^7.0.0",
34
34
  "jest": "^27.0.1",
data/rubocop.yml CHANGED
@@ -13,12 +13,16 @@ Layout:
13
13
  Layout/LineLength:
14
14
  Enabled: true
15
15
 
16
- # Disabling all of the following options because they could conflict with a
17
- # prettier configuration setting.
18
-
19
16
  Style/MultilineIfModifier: # rubyModifier
20
17
  Enabled: false
21
18
 
19
+ # When method chains with multiple blocks are chained together, rubocop will let
20
+ # them pass if they're using braces but not if they're using do and end
21
+ # keywords. Because we will break individual blocks down to using keywords if
22
+ # they are multiline, this conflicts with rubocop.
23
+ Style/MultilineBlockChain:
24
+ Enabled: false
25
+
22
26
  Style/SymbolArray: # rubyArrayLiteral
23
27
  Enabled: false
24
28
 
@@ -34,5 +38,7 @@ Style/TrailingCommaInArrayLiteral: # trailingComma
34
38
  Style/TrailingCommaInHashLiteral: # trailingComma
35
39
  Enabled: false
36
40
 
41
+ # lambdas that are constructed with the lambda method call cannot be safely
42
+ # turned into lambda literals without removing a method call.
37
43
  Style/Lambda:
38
44
  Enabled: false
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: 2.0.0.pre.rc1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Newton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-30 00:00:00.000000000 Z
11
+ date: 2021-10-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -129,9 +129,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
129
  version: '0'
130
130
  required_rubygems_version: !ruby/object:Gem::Requirement
131
131
  requirements:
132
- - - ">"
132
+ - - ">="
133
133
  - !ruby/object:Gem::Version
134
- version: 1.3.1
134
+ version: '0'
135
135
  requirements: []
136
136
  rubygems_version: 3.2.3
137
137
  signing_key: