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.
data/README.md CHANGED
@@ -128,17 +128,19 @@ The `prettier` executable is now installed and ready for use:
128
128
 
129
129
  Below are the options (from [`src/plugin.js`](src/plugin.js)) that `@prettier/plugin-ruby` currently supports:
130
130
 
131
- | API Option | CLI Option | Default | Description |
132
- | ------------------ | ---------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------------------ |
133
- | `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
134
- | `requirePragma` | `--require-pragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
135
- | `rubyArrayLiteral` | `--ruby-array-literal` | `true` | When possible, favor the use of string and symbol array literals. |
136
- | `rubyHashLabel` | `--ruby-hash-label` | `true` | When possible, uses the shortened hash key syntax, as opposed to hash rockets. |
137
- | `rubyModifier` | `--ruby-modifier` | `true` | When it fits on one line, allows while and until statements to use the modifier form. |
138
- | `rubySingleQuote` | `--ruby-single-quote` | `true` | When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals. |
139
- | `rubyToProc` | `--ruby-to-proc` | `false` | When possible, convert blocks to the more concise `Symbol#to_proc` syntax. |
140
- | `tabWidth` | `--tab-width` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
141
- | `trailingComma` | `--trailing-comma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#trailing-comma)). `"es5"` is equivalent to `true`. |
131
+ | API Option | CLI Option | Default | Description |
132
+ | ------------------- | ----------------------- | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
133
+ | `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
134
+ | `requirePragma` | `--require-pragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
135
+ | `rubyArrayLiteral` | `--ruby-array-literal` | `true` | When possible, favor the use of string and symbol array literals. |
136
+ | `rubyHashLabel` | `--ruby-hash-label` | `true` | When possible, uses the shortened hash key syntax, as opposed to hash rockets. |
137
+ | `rubyModifier` | `--ruby-modifier` | `true` | When it fits on one line, allows while and until statements to use the modifier form. |
138
+ | `rubyNetcatCommand` | `--ruby-netcat-command` | | The prefix of the command to execute to communicate between the node.js process and the Ruby process. (For example, `"nc -U"` or `"telnet -u"`) Normally you should not set this option. |
139
+
140
+ | `rubySingleQuote` | `--ruby-single-quote` | `true` | When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals. |
141
+ | `rubyToProc` | `--ruby-to-proc` | `false` | When possible, convert blocks to the more concise `Symbol#to_proc` syntax. |
142
+ | `tabWidth` | `--tab-width` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
143
+ | `trailingComma` | `--trailing-comma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#trailing-comma)). `"es5"` is equivalent to `true`. |
142
144
 
143
145
  Any of these can be added to your existing [prettier configuration
144
146
  file](https://prettier.io/docs/en/configuration.html). For example:
@@ -163,11 +165,20 @@ with some of RuboCop's functionality.
163
165
  Prettier provides a RuboCop configuration file to disable the rules which clash.
164
166
  To enable, add the following config at the top of your project's `.rubocop.yml`:
165
167
 
168
+ #### Ruby gem
169
+
166
170
  ```yaml
167
171
  inherit_gem:
168
172
  prettier: rubocop.yml
169
173
  ```
170
174
 
175
+ #### `npm` package
176
+
177
+ ```yaml
178
+ inherit_from:
179
+ - node_modules/@prettier/plugin-ruby/rubocop.yml
180
+ ```
181
+
171
182
  ## Contributing
172
183
 
173
184
  Check out our [contributing guide](CONTRIBUTING.md). Bug reports and pull requests are welcome on GitHub at https://github.com/prettier/plugin-ruby.
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "1.4.0",
3
+ "version": "1.5.4",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
5
  "main": "src/plugin.js",
6
6
  "scripts": {
@@ -22,9 +22,9 @@
22
22
  "prettier": ">=1.10"
23
23
  },
24
24
  "devDependencies": {
25
- "eslint": "^7.8.1",
26
- "eslint-config-prettier": "^7.0.0",
27
- "husky": "^4.3.5",
25
+ "eslint": "^7.22.0",
26
+ "eslint-config-prettier": "^8.0.0",
27
+ "husky": "^5.0.9",
28
28
  "jest": "^26.0.0",
29
29
  "pretty-quick": "^3.1.0"
30
30
  },
data/rubocop.yml CHANGED
@@ -24,3 +24,6 @@ Style/TrailingCommaInArrayLiteral: # trailingComma
24
24
 
25
25
  Style/TrailingCommaInHashLiteral: # trailingComma
26
26
  Enabled: false
27
+
28
+ Style/Lambda:
29
+ Enabled: false
data/src/haml/parser.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const parseSync = require("../parser/parseSync");
2
2
 
3
- const parse = (text, _parsers, _opts) => {
4
- return parseSync("haml", text);
3
+ const parse = (text, _parsers, opts) => {
4
+ return parseSync("haml", text, opts);
5
5
  };
6
6
 
7
7
  const pragmaPattern = /^\s*-#\s*@(prettier|format)/;
data/src/haml/parser.rb CHANGED
@@ -131,8 +131,6 @@ module Prettier
131
131
  class HAMLParser
132
132
  def self.parse(source)
133
133
  Haml::Parser.new({}).call(source).as_json
134
- rescue StandardError
135
- false
136
134
  end
137
135
  end
138
136
  end
@@ -16,35 +16,42 @@ function hasCommand(name) {
16
16
 
17
17
  // Finds an netcat-like adapter to use for sending data to a socket. We order
18
18
  // these by likelihood of being found so we can avoid some shell-outs.
19
- function getCommandAndArg() {
19
+ function getCommandAndArgs() {
20
20
  if (hasCommand("nc")) {
21
- return ["nc", "-U"];
21
+ return ["nc", ["-U"]];
22
22
  }
23
23
 
24
24
  if (hasCommand("telnet")) {
25
- return ["telnet", "-u"];
25
+ return ["telnet", ["-u"]];
26
26
  }
27
27
 
28
28
  if (hasCommand("ncat")) {
29
- return ["ncat", "-U"];
29
+ return ["ncat", ["-U"]];
30
30
  }
31
31
 
32
32
  if (hasCommand("socat")) {
33
- return ["socat", "-"];
33
+ return ["socat", ["-"]];
34
34
  }
35
35
 
36
- return ["node", require.resolve("./netcat.js")];
36
+ return ["node", [require.resolve("./netcat.js")]];
37
37
  }
38
38
 
39
39
  let command;
40
- let arg;
40
+ let args;
41
41
 
42
- function getNetcat() {
42
+ function getNetcat(opts) {
43
43
  if (!command) {
44
- [command, arg] = getCommandAndArg();
44
+ if (opts.rubyNetcatCommand) {
45
+ const splits = opts.rubyNetcatCommand.split(" ");
46
+
47
+ command = splits[0];
48
+ args = splits.slice(1);
49
+ } else {
50
+ [command, args] = getCommandAndArgs();
51
+ }
45
52
  }
46
53
 
47
- return { command, arg };
54
+ return { command, args };
48
55
  }
49
56
 
50
57
  module.exports = getNetcat;
data/src/parser/netcat.js CHANGED
@@ -5,11 +5,9 @@
5
5
  const { createConnection } = require("net");
6
6
 
7
7
  const sock = process.argv[process.argv.length - 1];
8
-
9
8
  const client = createConnection(sock, () => process.stdin.pipe(client));
10
9
 
11
10
  client.on("data", (data) => process.stdout.write(data));
12
-
13
11
  client.on("error", (error) => {
14
12
  console.error(error);
15
13
  });
@@ -4,27 +4,37 @@ const requestParse = require("./requestParse");
4
4
  // like it) here since Prettier requires the results of `parse` to be
5
5
  // synchronous and Node.js does not offer a mechanism for synchronous socket
6
6
  // requests.
7
- function parseSync(parser, source) {
8
- const response = requestParse(parser, source);
7
+ function parseSync(parser, source, opts) {
8
+ const { stdout, stderr, status } = requestParse(parser, source, opts);
9
9
 
10
- if (
11
- response.stdout.length === 0 ||
12
- (response.status !== null && response.status !== 0)
13
- ) {
14
- console.error("Could not parse response from server");
15
- console.error(response);
10
+ // We need special handling in case the user's version of nc doesn't support
11
+ // using unix sockets.
12
+ if (stderr.includes("invalid option -- U")) {
13
+ throw new Error(`
14
+ @prettier/plugin-ruby uses netcat to communicate over unix sockets between
15
+ the node.js process running prettier and an underlying Ruby process used
16
+ for parsing. Unfortunately the version of netcat that you have installed
17
+ (GNU netcat) does not support unix sockets. To solve this either uninstall
18
+ GNU netcat and use a different implementation, or change the value of the
19
+ rubyNetcatCommand option in your prettier configuration.
20
+ `);
21
+ }
16
22
 
17
- throw new Error(response.stderr || "An unknown error occurred");
23
+ // If we didn't receive anything over stdout or we have a bad exit status,
24
+ // then throw whatever we can.
25
+ if (stdout.length === 0 || (status !== null && status !== 0)) {
26
+ throw new Error(stderr || "An unknown error occurred");
18
27
  }
19
28
 
20
- const parsed = JSON.parse(response.stdout);
29
+ const parsed = JSON.parse(stdout);
21
30
 
22
31
  if (parsed.error) {
23
- throw new Error(
24
- `@prettier/plugin-ruby encountered an error when attempting to parse \
25
- the ruby source. This usually means there was a syntax error in the \
26
- file in question. You can verify by running \`ruby -i [path/to/file]\`.`
27
- );
32
+ const error = new Error(parsed.error);
33
+ if (parsed.loc) {
34
+ error.loc = parsed.loc;
35
+ }
36
+
37
+ throw error;
28
38
  }
29
39
 
30
40
  return parsed;
@@ -54,11 +54,11 @@ function ensureParseServer() {
54
54
  }
55
55
 
56
56
  // Sends a request to the parse server to parse the given content.
57
- function requestParse(parser, source) {
57
+ function requestParse(parser, source, opts) {
58
58
  ensureParseServer();
59
59
 
60
- const { command, arg } = getNetcat();
61
- const { stdout, stderr, status } = spawnSync(command, [arg, sockfile], {
60
+ const { command, args } = getNetcat(opts);
61
+ const { stdout, stderr, status } = spawnSync(command, args.concat(sockfile), {
62
62
  input: `${parser}|${source}`,
63
63
  maxBuffer: 15 * 1024 * 1024
64
64
  });
data/src/parser/server.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/setup' if ENV['CI']
3
+ require 'bundler/setup' if ENV['PLUGIN_RUBY_CI']
4
4
  require 'socket'
5
5
  require 'json'
6
6
 
@@ -14,7 +14,7 @@ $PROGRAM_NAME = 'prettier-ruby-parser'
14
14
  # Make sure we trap these signals to be sure we get the quit command coming from
15
15
  # the parent node process
16
16
  quit = false
17
- trap(:QUIT) { quit = true }
17
+ trap(:QUIT) { quit = true } if RUBY_PLATFORM != 'java'
18
18
  trap(:INT) { quit = true }
19
19
  trap(:TERM) { quit = true }
20
20
 
@@ -48,6 +48,11 @@ loop do
48
48
  else
49
49
  socket.write('{ "error": true }')
50
50
  end
51
+ rescue Prettier::Parser::ParserError => error
52
+ loc = { start: { line: error.lineno, column: error.column } }
53
+ socket.write(JSON.fast_generate(error: error.message, loc: loc))
54
+ rescue StandardError => error
55
+ socket.write(JSON.fast_generate(error: error.message))
51
56
  ensure
52
57
  socket.close
53
58
  end
data/src/plugin.js CHANGED
@@ -36,6 +36,7 @@ module.exports = {
36
36
  ".rabl",
37
37
  ".rake",
38
38
  ".rb",
39
+ ".rbi",
39
40
  ".rbuild",
40
41
  ".rbw",
41
42
  ".rbx",
@@ -118,6 +119,12 @@ module.exports = {
118
119
  description:
119
120
  "When it fits on one line, allows if, unless, while, and until statements to use the modifier form."
120
121
  },
122
+ rubyNetcatCommand: {
123
+ type: "string",
124
+ category: "Ruby",
125
+ description:
126
+ 'The prefix of the command to execute to communicate between the node.js process and the Ruby process. (For example, "nc -U" or "telnet -u") Normally you should not set this option.'
127
+ },
121
128
  rubySingleQuote: {
122
129
  type: "boolean",
123
130
  category: "Ruby",
data/src/rbs/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("rbs", text);
7
+ function parse(text, _parsers, opts) {
8
+ return parseSync("rbs", text, opts);
9
9
  }
10
10
 
11
11
  const pragmaPattern = /#\s*@(prettier|format)/;
data/src/rbs/parser.rb CHANGED
@@ -23,8 +23,14 @@ end
23
23
  class RBS::Location
24
24
  def to_json(*args)
25
25
  {
26
- start: { line: start_line, column: start_column },
27
- end: { line: end_line, column: end_column },
26
+ start: {
27
+ line: start_line,
28
+ column: start_column
29
+ },
30
+ end: {
31
+ line: end_line,
32
+ column: end_column
33
+ },
28
34
  start_pos: start_pos,
29
35
  end_pos: end_pos
30
36
  }.to_json(*args)
@@ -81,8 +87,6 @@ module Prettier
81
87
  class RBSParser
82
88
  def self.parse(text)
83
89
  { declarations: RBS::Parser.parse_signature(text) }
84
- rescue StandardError
85
- false
86
90
  end
87
91
  end
88
92
  end
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",
@@ -24,18 +24,54 @@ const parsers = {
24
24
  // have a test that exercises it because I'm not sure for which parser it is
25
25
  // necessary, but since it's in prettier core I'm keeping it here.
26
26
  /* istanbul ignore next */
27
- const replaceNewlines = (doc) =>
28
- mapDoc(doc, (currentDoc) =>
27
+ function replaceNewlines(doc) {
28
+ return mapDoc(doc, (currentDoc) =>
29
29
  typeof currentDoc === "string" && currentDoc.includes("\n")
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
  );
37
+ }
37
38
 
38
- const embed = (path, print, textToDoc, _opts) => {
39
+ // Returns a number that represents the minimum amount of leading whitespace
40
+ // that is present on every line in the given string. So for example if you have
41
+ // the following heredoc:
42
+ //
43
+ // <<~HERE
44
+ // my
45
+ // content
46
+ // here
47
+ // HERE
48
+ //
49
+ // then the return value of this function would be 2. If you indented every line
50
+ // of the inner content 2 more spaces then this function would return 4.
51
+ function getCommonLeadingWhitespace(content) {
52
+ const pattern = /^\s+/;
53
+
54
+ return content
55
+ .split("\n")
56
+ .slice(0, -1)
57
+ .reduce((minimum, line) => {
58
+ const matched = pattern.exec(line);
59
+ const length = matched ? matched[0].length : 0;
60
+
61
+ return minimum === null ? length : Math.min(minimum, length);
62
+ }, null);
63
+ }
64
+
65
+ // Returns a new string with the common whitespace stripped out. Effectively it
66
+ // emulates what a squiggly heredoc does in Ruby.
67
+ function stripCommonLeadingWhitespace(content) {
68
+ const lines = content.split("\n");
69
+ const minimum = getCommonLeadingWhitespace(content);
70
+
71
+ return lines.map((line) => line.slice(minimum)).join("\n");
72
+ }
73
+
74
+ function embed(path, print, textToDoc, _opts) {
39
75
  const node = path.getValue();
40
76
 
41
77
  // Currently we only support embedded formatting on heredoc nodes
@@ -45,6 +81,8 @@ const embed = (path, print, textToDoc, _opts) => {
45
81
 
46
82
  // First, ensure that we don't have any interpolation
47
83
  const { beging, body, ending } = node;
84
+ const isSquiggly = beging.body[2] === "~";
85
+
48
86
  if (body.some((part) => part.type !== "@tstring_content")) {
49
87
  return null;
50
88
  }
@@ -56,24 +94,32 @@ const embed = (path, print, textToDoc, _opts) => {
56
94
  return null;
57
95
  }
58
96
 
59
- // Get the content as if it were a source string, and then pass that content
60
- // into the embedded parser. Get back the doc node.
61
- const content = body.map((part) => part.body).join("");
97
+ // Get the content as if it were a source string.
98
+ let content = body.map((part) => part.body).join("");
99
+
100
+ // If we're using a squiggly heredoc, then we're going to manually strip off
101
+ // the leading whitespace of each line up to the minimum leading whitespace so
102
+ // that the embedded parser can handle that for us.
103
+ if (isSquiggly) {
104
+ content = stripCommonLeadingWhitespace(content);
105
+ }
106
+
107
+ // Pass that content into the embedded parser. Get back the doc node.
62
108
  const formatted = concat([
63
- literalLineNoBreak,
109
+ literallineWithoutBreakParent,
64
110
  replaceNewlines(stripTrailingHardline(textToDoc(content, { parser })))
65
111
  ]);
66
112
 
67
113
  // If we're using a squiggly heredoc, then we can properly handle indentation
68
114
  // ourselves.
69
- if (beging.body[2] === "~") {
115
+ if (isSquiggly) {
70
116
  return concat([
71
117
  path.call(print, "beging"),
72
118
  lineSuffix(
73
119
  group(
74
120
  concat([
75
121
  indent(markAsRoot(formatted)),
76
- literalLineNoBreak,
122
+ literallineWithoutBreakParent,
77
123
  ending.trim()
78
124
  ])
79
125
  )
@@ -86,9 +132,11 @@ const embed = (path, print, textToDoc, _opts) => {
86
132
  return markAsRoot(
87
133
  concat([
88
134
  path.call(print, "beging"),
89
- lineSuffix(group(concat([formatted, literalLineNoBreak, ending.trim()])))
135
+ lineSuffix(
136
+ group(concat([formatted, literallineWithoutBreakParent, ending.trim()]))
137
+ )
90
138
  ])
91
139
  );
92
- };
140
+ }
93
141
 
94
142
  module.exports = embed;