prettier 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -6
  3. data/README.md +16 -16
  4. data/exe/rbprettier +2 -2
  5. data/lib/prettier/rake/task.rb +5 -5
  6. data/lib/prettier.rb +11 -11
  7. data/package.json +9 -23
  8. data/rubocop.yml +6 -6
  9. data/{dist/parser → src}/getInfo.js +0 -1
  10. data/{dist/parser → src}/netcat.js +0 -1
  11. data/src/parseSync.js +212 -0
  12. data/src/plugin.js +161 -0
  13. data/{dist/parser → src}/server.rb +45 -31
  14. metadata +94 -78
  15. data/bin/console +0 -7
  16. data/dist/haml/embed.js +0 -53
  17. data/dist/haml/parser.js +0 -31
  18. data/dist/haml/parser.rb +0 -149
  19. data/dist/haml/printer.js +0 -336
  20. data/dist/parser/parseSync.js +0 -179
  21. data/dist/plugin.js +0 -143
  22. data/dist/prettier.js +0 -15
  23. data/dist/rbs/parser.js +0 -34
  24. data/dist/rbs/parser.rb +0 -155
  25. data/dist/rbs/printer.js +0 -525
  26. data/dist/ruby/embed.js +0 -115
  27. data/dist/ruby/location.js +0 -19
  28. data/dist/ruby/nodes/alias.js +0 -60
  29. data/dist/ruby/nodes/aref.js +0 -51
  30. data/dist/ruby/nodes/args.js +0 -138
  31. data/dist/ruby/nodes/arrays.js +0 -122
  32. data/dist/ruby/nodes/assign.js +0 -37
  33. data/dist/ruby/nodes/blocks.js +0 -90
  34. data/dist/ruby/nodes/calls.js +0 -263
  35. data/dist/ruby/nodes/case.js +0 -50
  36. data/dist/ruby/nodes/class.js +0 -54
  37. data/dist/ruby/nodes/commands.js +0 -138
  38. data/dist/ruby/nodes/conditionals.js +0 -246
  39. data/dist/ruby/nodes/constants.js +0 -35
  40. data/dist/ruby/nodes/flow.js +0 -59
  41. data/dist/ruby/nodes/hashes.js +0 -126
  42. data/dist/ruby/nodes/heredocs.js +0 -30
  43. data/dist/ruby/nodes/hooks.js +0 -35
  44. data/dist/ruby/nodes/ints.js +0 -27
  45. data/dist/ruby/nodes/lambdas.js +0 -70
  46. data/dist/ruby/nodes/loops.js +0 -75
  47. data/dist/ruby/nodes/massign.js +0 -60
  48. data/dist/ruby/nodes/methods.js +0 -50
  49. data/dist/ruby/nodes/operators.js +0 -68
  50. data/dist/ruby/nodes/params.js +0 -95
  51. data/dist/ruby/nodes/patterns.js +0 -119
  52. data/dist/ruby/nodes/regexp.js +0 -45
  53. data/dist/ruby/nodes/rescue.js +0 -86
  54. data/dist/ruby/nodes/return.js +0 -100
  55. data/dist/ruby/nodes/statements.js +0 -110
  56. data/dist/ruby/nodes/strings.js +0 -220
  57. data/dist/ruby/nodes/super.js +0 -26
  58. data/dist/ruby/nodes/undef.js +0 -31
  59. data/dist/ruby/nodes.js +0 -177
  60. data/dist/ruby/parser.js +0 -35
  61. data/dist/ruby/parser.rb +0 -9134
  62. data/dist/ruby/printer.js +0 -67
  63. data/dist/ruby/toProc.js +0 -91
  64. data/dist/types/haml.js +0 -4
  65. data/dist/types/plugin.js +0 -3
  66. data/dist/types/rbs.js +0 -4
  67. data/dist/types/ruby.js +0 -4
  68. data/dist/types/utils.js +0 -2
  69. data/dist/types.js +0 -34
  70. data/dist/utils/containsAssignment.js +0 -18
  71. data/dist/utils/getChildNodes.js +0 -305
  72. data/dist/utils/getTrailingComma.js +0 -6
  73. data/dist/utils/hasAncestor.js +0 -15
  74. data/dist/utils/inlineEnsureParens.js +0 -49
  75. data/dist/utils/isEmptyBodyStmt.js +0 -10
  76. data/dist/utils/isEmptyParams.js +0 -12
  77. data/dist/utils/isEmptyStmts.js +0 -10
  78. data/dist/utils/literal.js +0 -8
  79. data/dist/utils/literallineWithoutBreakParent.js +0 -8
  80. data/dist/utils/makeCall.js +0 -14
  81. data/dist/utils/noIndent.js +0 -11
  82. data/dist/utils/printEmptyCollection.js +0 -46
  83. data/dist/utils/skipAssignIndent.js +0 -19
  84. data/dist/utils.js +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34ffeeada2b06900ec6759f31a42ca387c8748a6a22843a1792fd906bfb4ffda
4
- data.tar.gz: ddbceb38e8263f881fd12f66560615db880cf7870f0cb926671c2da656aad6f8
3
+ metadata.gz: edc974795ef0adb86312682bdedfa30cca29905f660b97334326494b8623144f
4
+ data.tar.gz: 9dcdc7ecb78e7ee4fa333b45e9f2e4b5ea5df4615869ce6b172377bf21126560
5
5
  SHA512:
6
- metadata.gz: 300acaf432b28f15d5b7690effbe7ca8fff778af699c5f79d0872c15f3241ec9be2e8fd83f86a9e65e6807cd152504b78d79760b30926c418bc7358d5d9f7524
7
- data.tar.gz: a7d658200446e7dde838d07b502303fa30e168e800f3053e48e6cf05940fbb92892d0eaca9c48304a48b13d6c94dce09019bb7a2c18acc18c48b3c241d4d4637
6
+ metadata.gz: ed0166367d99fc0af3135d76c47dae06bcddd92eaf9a7d3d680726d403a2eed16f08af8fe410c527113bf00d1a0fe11b4c6743820e4c907b2de2707884655ef3
7
+ data.tar.gz: c8fa9abb2ecf3561c913f9505f7d07c56e322c6f3031d44b9725c314bfb1576c0dc68c7c7e28f8a15f9d876c4307c0c90549e1db83a4c94b184e0a872413208d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.0.0] - 2022-05-04
10
+
11
+ ### Added
12
+
13
+ - [#1190](https://github.com/prettier/plugin-ruby/pull/1190) - kddnewton - Encoding for source files is now guessed in a much better way.
14
+
15
+ ### Changed
16
+
17
+ - [#1198](https://github.com/prettier/plugin-ruby/issues/1198) - pas-f, kddnewton - Fix crashes on JRuby with do blocks.
18
+ - [#1131](https://github.com/prettier/plugin-ruby/issues/1131) - hyrious, kddnewton - Ensure zombie processes are not left around when the server exits.
19
+ - [#1206](https://github.com/prettier/plugin-ruby/pull/1206) - kddnewton - Switch back to plain JavaScript for development.
20
+ - [#1190](https://github.com/prettier/plugin-ruby/pull/1190) - kddnewton - Switch over to using Syntax Tree for the backend.
21
+
22
+ ### Removed
23
+
24
+ - [#1190](https://github.com/prettier/plugin-ruby/pull/1190) - kddnewton - The configuration options have been removed. Instead, configuration is to be done through modifying Syntax Tree.
25
+
9
26
  ## [2.1.0] - 2022-04-04
10
27
 
11
28
  ### Added
@@ -316,7 +333,6 @@ The comment in the above example should stay in place.
316
333
 
317
334
  ```ruby
318
335
  begin
319
-
320
336
  rescue Foo, Bar
321
337
  # comment
322
338
  end
@@ -472,7 +488,8 @@ return (a or b) if c?
472
488
  - kddnewton - Support for the `nokw_param` node for specifying when methods should no accept keywords, as in:
473
489
 
474
490
  ```ruby
475
- def foo(**nil); end
491
+ def foo(**nil)
492
+ end
476
493
  ```
477
494
 
478
495
  - kddnewton - Support for the `args_forward` node for forwarding all types of arguments, as in:
@@ -518,9 +535,9 @@ will now be printed as:
518
535
 
519
536
  ```ruby
520
537
  Config::Download.new(
521
- 'prettier',
522
- filename: 'prettier.yml',
523
- url: 'https://raw.githubusercontent.com/...'
538
+ "prettier",
539
+ filename: "prettier.yml",
540
+ url: "https://raw.githubusercontent.com/..."
524
541
  ).perform
525
542
  ```
526
543
 
@@ -1208,7 +1225,8 @@ would previously result in `array[]`, but now prints properly.
1208
1225
 
1209
1226
  - Initial release 🎉
1210
1227
 
1211
- [unreleased]: https://github.com/prettier/plugin-ruby/compare/v2.1.0...HEAD
1228
+ [unreleased]: https://github.com/prettier/plugin-ruby/compare/v3.0.0...HEAD
1229
+ [3.0.0]: https://github.com/prettier/plugin-ruby/compare/v2.1.0...v3.0.0
1212
1230
  [2.1.0]: https://github.com/prettier/plugin-ruby/compare/v2.0.0...v2.1.0
1213
1231
  [2.0.0]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc4...v2.0.0
1214
1232
  [2.0.0-rc4]: https://github.com/prettier/plugin-ruby/compare/v2.0.0-rc3...v2.0.0-rc4
data/README.md CHANGED
@@ -59,9 +59,9 @@ d = [
59
59
  30_643_069_058
60
60
  ]
61
61
  a, s = [], $*[0]
62
- s.each_byte { |b| a << ('%036b' % d[b.chr.to_i]).scan(/\d{6}/) }
62
+ s.each_byte { |b| a << ("%036b" % d[b.chr.to_i]).scan(/\d{6}/) }
63
63
  a.transpose.each do |a|
64
- a.join.each_byte { |i| print i == 49 ? ($*[1] || '#') : 32.chr }
64
+ a.join.each_byte { |i| print i == 49 ? ($*[1] || "#") : 32.chr }
65
65
  puts
66
66
  end
67
67
  ```
@@ -83,7 +83,7 @@ This plugin currently supports formatting the following kinds of files:
83
83
  Add this line to your application's Gemfile:
84
84
 
85
85
  ```ruby
86
- gem 'prettier'
86
+ gem "prettier"
87
87
  ```
88
88
 
89
89
  And then execute:
@@ -118,6 +118,12 @@ Or if you're using `yarn`, then add the plugin by:
118
118
  yarn add --dev prettier @prettier/plugin-ruby
119
119
  ```
120
120
 
121
+ You'll also need to add the necessary Ruby dependencies. You can do this by running:
122
+
123
+ ```bash
124
+ gem install syntax_tree syntax_tree-haml syntax_tree-rbs
125
+ ```
126
+
121
127
  The `prettier` executable is now installed and ready for use:
122
128
 
123
129
  ```bash
@@ -128,31 +134,25 @@ The `prettier` executable is now installed and ready for use:
128
134
 
129
135
  Below are the options (from [`src/plugin.js`](src/plugin.js)) that `@prettier/plugin-ruby` currently supports:
130
136
 
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` | `"none"` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#trailing-comma)). `"es5"` is equivalent to `true`. |
137
+ | API Option | CLI Option | Default | Description |
138
+ | --------------- | ------------------ | :-----: | --------------------------------------------------------------------------------------------------- |
139
+ | `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
140
+ | `requirePragma` | `--require-pragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
141
+ | `tabWidth` | `--tab-width` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
142
142
 
143
143
  Any of these can be added to your existing [prettier configuration
144
144
  file](https://prettier.io/docs/en/configuration.html). For example:
145
145
 
146
146
  ```json
147
147
  {
148
- "rubySingleQuote": false
148
+ "tabWidth": 4
149
149
  }
150
150
  ```
151
151
 
152
152
  Or, they can be passed to `prettier` as arguments:
153
153
 
154
154
  ```bash
155
- bundle exec rbprettier --ruby-single-quote false --write '**/*'
155
+ bundle exec rbprettier --tab-width 4 --write '**/*'
156
156
  ```
157
157
 
158
158
  ### Usage with RuboCop
data/exe/rbprettier CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- $:.unshift(File.expand_path(File.join('..', 'lib'), __dir__))
5
- require 'prettier'
4
+ $:.unshift(File.expand_path(File.join("..", "lib"), __dir__))
5
+ require "prettier"
6
6
 
7
7
  exit(Prettier.run(ARGV))
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rake'
4
- require 'rake/tasklib'
3
+ require "rake"
4
+ require "rake/tasklib"
5
5
 
6
6
  module Prettier
7
7
  module Rake
@@ -35,7 +35,7 @@ module Prettier
35
35
  def initialize(name = :prettier)
36
36
  @name = name
37
37
  @write = true
38
- @source_files = 'lib/**/*.rb'
38
+ @source_files = "lib/**/*.rb"
39
39
 
40
40
  yield self if block_given?
41
41
  define_task
@@ -44,12 +44,12 @@ module Prettier
44
44
  private
45
45
 
46
46
  def define_task
47
- desc 'Runs prettier over source files'
47
+ desc "Runs prettier over source files"
48
48
  task(name) { run_task }
49
49
  end
50
50
 
51
51
  def run_task
52
- Prettier.run([('--write' if write), source_files].compact)
52
+ Prettier.run([("--write" if write), source_files].compact)
53
53
  exit($?.exitstatus) if $?&.exited?
54
54
  end
55
55
  end
data/lib/prettier.rb CHANGED
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json' unless defined?(JSON)
4
- require 'open3'
3
+ require "json" unless defined?(JSON)
4
+ require "open3"
5
5
 
6
6
  module Prettier
7
- PLUGIN = -File.expand_path('..', __dir__)
8
- BINARY = -File.join(PLUGIN, 'node_modules', 'prettier', 'bin-prettier.js')
9
- VERSION = -JSON.parse(File.read(File.join(PLUGIN, 'package.json')))['version']
7
+ PLUGIN = -File.expand_path("..", __dir__)
8
+ BINARY = -File.join(PLUGIN, "node_modules", "prettier", "bin-prettier.js")
9
+ VERSION = -JSON.parse(File.read(File.join(PLUGIN, "package.json")))["version"]
10
10
 
11
11
  def self.run(args)
12
- quoted = args.map { |arg| arg.start_with?('-') ? arg : "\"#{arg}\"" }
13
- command = "node #{BINARY} --plugin \"#{PLUGIN}\" #{quoted.join(' ')}"
12
+ quoted = args.map { |arg| arg.start_with?("-") ? arg : "\"#{arg}\"" }
13
+ command = "node #{BINARY} --plugin \"#{PLUGIN}\" #{quoted.join(" ")}"
14
14
 
15
15
  stdout, stderr, status =
16
- Open3.capture3({ 'RBPRETTIER' => '1' }, command, stdin_data: STDIN)
16
+ Open3.capture3({ "RBPRETTIER" => "1" }, command, stdin_data: STDIN)
17
17
  STDOUT.puts(stdout)
18
18
 
19
19
  # If we completed successfully, then just exit out.
@@ -30,11 +30,11 @@ module Prettier
30
30
  If you installed this dependency through git instead of from rubygems,
31
31
  it does not install the necessary files by default. To fix this you can
32
32
  either install them yourself by cd-ing into the directory where this gem
33
- is located (#{File.expand_path('..', __dir__)}) and running:
33
+ is located (#{File.expand_path("..", __dir__)}) and running:
34
34
 
35
- `yarn && yarn prepublishOnly`
35
+ `yarn install`
36
36
  or
37
- `npm install && npm run prepublishOnly`
37
+ `npm install`
38
38
  or
39
39
  you can change the source in your Gemfile to point directly to rubygems.
40
40
  MSG
data/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
- "main": "dist/plugin.js",
5
+ "main": "src/plugin.js",
6
6
  "scripts": {
7
7
  "checkFormat": "prettier --check '**/*'",
8
8
  "lint": "eslint --cache .",
9
- "prepublishOnly": "tsc -p tsconfig.build.json && cp src/parser/getInfo.js dist/parser && cp src/parser/netcat.js dist/parser && cp src/parser/server.rb dist/parser && cp src/haml/parser.rb dist/haml && cp src/rbs/parser.rb dist/rbs && cp src/ruby/parser.rb dist/ruby",
10
9
  "test": "jest"
11
10
  },
12
11
  "repository": {
@@ -23,24 +22,15 @@
23
22
  "prettier": ">=2.3.0"
24
23
  },
25
24
  "devDependencies": {
26
- "@types/jest": "^27.0.1",
27
- "@types/node": "^17.0.0",
28
- "@types/prettier": "^2.4.2",
29
- "@typescript-eslint/eslint-plugin": "^5.18.0",
30
- "@typescript-eslint/parser": "^5.18.0",
31
25
  "eslint": "^8.1.0",
32
26
  "eslint-config-prettier": "^8.0.0",
33
27
  "husky": "^7.0.0",
34
- "jest": "^27.0.1",
35
- "pretty-quick": "^3.1.2",
36
- "ts-jest": "^27.0.5",
37
- "ts-node": "^10.2.1",
38
- "typescript": "^4.5.2"
28
+ "jest": "^28.0.1",
29
+ "pretty-quick": "^3.1.2"
39
30
  },
40
31
  "eslintConfig": {
41
32
  "extends": [
42
33
  "eslint:recommended",
43
- "plugin:@typescript-eslint/recommended",
44
34
  "prettier"
45
35
  ],
46
36
  "env": {
@@ -48,21 +38,17 @@
48
38
  "jest": true,
49
39
  "node": true
50
40
  },
51
- "parser": "@typescript-eslint/parser",
52
41
  "rules": {
53
- "no-unused-vars": "off",
54
- "@typescript-eslint/explicit-module-boundary-types": "off",
55
- "@typescript-eslint/no-explicit-any": "off"
42
+ "no-unused-vars": "off"
56
43
  }
57
44
  },
58
45
  "jest": {
59
- "globalSetup": "./test/js/globalSetup.ts",
60
- "globalTeardown": "./test/js/globalTeardown.ts",
61
- "preset": "ts-jest",
46
+ "globalSetup": "./test/js/globalSetup.js",
47
+ "globalTeardown": "./test/js/globalTeardown.js",
62
48
  "setupFilesAfterEnv": [
63
- "./test/js/setupTests.ts"
49
+ "./test/js/setupTests.js"
64
50
  ],
65
- "testRegex": ".test.ts$"
51
+ "testRegex": ".test.js$"
66
52
  },
67
53
  "husky": {
68
54
  "hooks": {
data/rubocop.yml CHANGED
@@ -13,7 +13,7 @@ Layout:
13
13
  Layout/LineLength:
14
14
  Enabled: true
15
15
 
16
- Style/MultilineIfModifier: # rubyModifier
16
+ Style/MultilineIfModifier:
17
17
  Enabled: false
18
18
 
19
19
  # When method chains with multiple blocks are chained together, rubocop will let
@@ -23,19 +23,19 @@ Style/MultilineIfModifier: # rubyModifier
23
23
  Style/MultilineBlockChain:
24
24
  Enabled: false
25
25
 
26
- Style/SymbolArray: # rubyArrayLiteral
26
+ Style/SymbolArray:
27
27
  Enabled: false
28
28
 
29
- Style/WordArray: # rubyArrayLiteral
29
+ Style/WordArray:
30
30
  Enabled: false
31
31
 
32
- Style/TrailingCommaInArguments: # trailingComma
32
+ Style/TrailingCommaInArguments:
33
33
  Enabled: false
34
34
 
35
- Style/TrailingCommaInArrayLiteral: # trailingComma
35
+ Style/TrailingCommaInArrayLiteral:
36
36
  Enabled: false
37
37
 
38
- Style/TrailingCommaInHashLiteral: # trailingComma
38
+ Style/TrailingCommaInHashLiteral:
39
39
  Enabled: false
40
40
 
41
41
  # lambdas that are constructed with the lambda method call cannot be safely
@@ -1,4 +1,3 @@
1
- // eslint-disable-next-line @typescript-eslint/no-var-requires
2
1
  const { existsSync, readFileSync } = require("fs");
3
2
 
4
3
  // This is how long to wait for the parser to spin up. For the most part, 5
@@ -2,7 +2,6 @@
2
2
  // On average, this is 2-3x slower than netcat, but still much faster than
3
3
  // spawning a new Ruby process.
4
4
 
5
- // eslint-disable-next-line @typescript-eslint/no-var-requires
6
5
  const { createConnection } = require("net");
7
6
 
8
7
  const sock = process.argv[process.argv.length - 1];
data/src/parseSync.js ADDED
@@ -0,0 +1,212 @@
1
+ const { spawn, spawnSync } = require("child_process");
2
+ const {
3
+ existsSync,
4
+ unlinkSync,
5
+ mkdtempSync,
6
+ copyFileSync,
7
+ mkdirSync,
8
+ rmdirSync
9
+ } = require("fs");
10
+ const os = require("os");
11
+ const path = require("path");
12
+ const process = require("process");
13
+
14
+ let parserArgs;
15
+
16
+ if (process.env.PRETTIER_RUBY_HOST) {
17
+ const [cmd, ...args] = process.env.PRETTIER_RUBY_HOST.split(" ");
18
+ parserArgs = { cmd, args };
19
+ }
20
+
21
+ // In order to properly parse ruby code, we need to tell the ruby process to
22
+ // parse using UTF-8. Unfortunately, the way that you accomplish this looks
23
+ // differently depending on your platform.
24
+ /* istanbul ignore next */
25
+ function getLang() {
26
+ const { env, platform } = process;
27
+ const envValue = env.LC_ALL || env.LC_CTYPE || env.LANG;
28
+
29
+ // If an env var is set for the locale that already includes UTF-8 in the
30
+ // name, then assume we can go with that.
31
+ if (envValue && envValue.includes("UTF-8")) {
32
+ return envValue;
33
+ }
34
+
35
+ // Otherwise, we're going to guess which encoding to use based on the system.
36
+ // This is probably not the best approach in the world, as you could be on
37
+ // linux and not have C.UTF-8, but in that case you're probably passing an env
38
+ // var for it. This object below represents all of the possible values of
39
+ // process.platform per:
40
+ // https://nodejs.org/api/process.html#process_process_platform
41
+ return {
42
+ aix: "C.UTF-8",
43
+ android: "C.UTF-8",
44
+ cygwin: "C.UTF-8",
45
+ darwin: "en_US.UTF-8",
46
+ freebsd: "C.UTF-8",
47
+ haiku: "C.UTF-8",
48
+ linux: "C.UTF-8",
49
+ netbsd: "C.UTF-8",
50
+ openbsd: "C.UTF-8",
51
+ sunos: "C.UTF-8",
52
+ win32: ".UTF-8"
53
+ }[platform];
54
+ }
55
+
56
+ // Generate the filepath that should be used to communicate the connection
57
+ // information between this process and the parser server.
58
+ function getInfoFilepath() {
59
+ return path.join(os.tmpdir(), `prettier-ruby-parser-${process.pid}.info`);
60
+ }
61
+
62
+ // Create a file that will act as a communication mechanism, spawn a parser
63
+ // server with that filepath as an argument, then spawn another process that
64
+ // will read that information in order to enable us to connect to it in the
65
+ // spawnSync function.
66
+ function spawnServer() {
67
+ const tempDir = mkdtempSync(path.join(os.tmpdir(), "prettier-plugin-ruby-"));
68
+ const filepath = getInfoFilepath();
69
+
70
+ let serverRbPath = path.join(__dirname, "./server.rb");
71
+ let getInfoJsPath = path.join(__dirname, "./getInfo.js");
72
+ let cleanupTempFiles;
73
+
74
+ if (runningInPnPZip()) {
75
+ // If we're running in a Yarn PnP environment inside a ZIP file, it's not possible to run
76
+ // the Ruby server or the getInfo.js script directly. Instead, we need to copy them and all
77
+ // the files they depend on to a temporary directory.
78
+
79
+ const sourceFiles = ["server.rb", "getInfo.js", "netcat.js"];
80
+ serverRbPath = path.join(tempDir, "server.rb");
81
+ getInfoJsPath = path.join(tempDir, "getInfo.js");
82
+
83
+ sourceFiles.forEach((rubyFile) => {
84
+ const destDir = path.join(tempDir, path.dirname(rubyFile));
85
+ if (!existsSync(destDir)) {
86
+ mkdirSync(destDir);
87
+ }
88
+ copyFileSync(
89
+ path.join(__dirname, "..", "src", rubyFile),
90
+ path.join(tempDir, rubyFile)
91
+ );
92
+ });
93
+
94
+ cleanupTempFiles = () => {
95
+ [
96
+ getInfoJsPath,
97
+ ...sourceFiles.map((rubyFile) => path.join(tempDir, rubyFile))
98
+ ].forEach((tmpFilePath) => {
99
+ if (existsSync(tmpFilePath)) {
100
+ unlinkSync(tmpFilePath);
101
+ }
102
+ });
103
+
104
+ sourceFiles.forEach((rubyFile) => {
105
+ const tempSubdir = path.join(tempDir, path.dirname(rubyFile));
106
+ if (existsSync(tempSubdir)) {
107
+ rmdirSync(tempSubdir);
108
+ }
109
+ });
110
+
111
+ if (existsSync(tempDir)) {
112
+ rmdirSync(tempDir);
113
+ }
114
+ };
115
+ }
116
+
117
+ const server = spawn("ruby", [serverRbPath, filepath], {
118
+ env: Object.assign({}, process.env, { LANG: getLang() }),
119
+ detached: true,
120
+ stdio: "inherit"
121
+ });
122
+
123
+ server.unref();
124
+ process.on("exit", () => {
125
+ if (existsSync(filepath)) {
126
+ unlinkSync(filepath);
127
+ }
128
+
129
+ if (cleanupTempFiles != null) {
130
+ cleanupTempFiles();
131
+ }
132
+
133
+ try {
134
+ if (server.pid) {
135
+ // Kill the server process if it's still running. If we're on windows
136
+ // we're going to use the process ID number. If we're not, we're going
137
+ // to use the negative process ID to indicate the group.
138
+ const pid = process.platform === "win32" ? server.pid : -server.pid;
139
+ process.kill(pid);
140
+ }
141
+ } catch (e) {
142
+ if (process.env.PLUGIN_RUBY_CI) {
143
+ throw new Error(`Failed to kill the parser server: ${e}`);
144
+ }
145
+ }
146
+ });
147
+
148
+ const info = spawnSync("node", [getInfoJsPath, filepath]);
149
+
150
+ if (info.status !== 0) {
151
+ throw new Error(`
152
+ We failed to spawn our parser server. Please report this error on GitHub
153
+ at https://github.com/prettier/plugin-ruby. The error message was:
154
+
155
+ ${info.stderr.toString()}.
156
+ `);
157
+ }
158
+
159
+ const [cmd, ...args] = info.stdout.toString().split(" ");
160
+ return { cmd, args };
161
+ }
162
+
163
+ // If we're in a yarn Plug'n'Play environment, then the relative paths being
164
+ // used by the parser server and the various scripts used to communicate
165
+ // therein are not going to work with its virtual file system.
166
+ function runningInPnPZip() {
167
+ return process.versions.pnp && __dirname.includes(".zip");
168
+ }
169
+
170
+ // Formats and sends a request to the parser server. We use netcat (or something
171
+ // like it) here since Prettier requires the results of `parse` to be
172
+ // synchronous and Node.js does not offer a mechanism for synchronous socket
173
+ // requests.
174
+ function parseSync(parser, source) {
175
+ if (!parserArgs) {
176
+ parserArgs = spawnServer();
177
+ }
178
+
179
+ const response = spawnSync(parserArgs.cmd, parserArgs.args, {
180
+ input: `${parser}|${source}`,
181
+ maxBuffer: 15 * 1024 * 1024
182
+ });
183
+
184
+ const stdout = response.stdout.toString();
185
+ const stderr = response.stderr.toString();
186
+ const { status } = response;
187
+
188
+ // If we didn't receive anything over stdout or we have a bad exit status,
189
+ // then throw whatever we can.
190
+ if (stdout.length === 0 || (status !== null && status !== 0)) {
191
+ throw new Error(stderr || "An unknown error occurred");
192
+ }
193
+
194
+ const parsed = JSON.parse(stdout);
195
+
196
+ if (parsed.error) {
197
+ const error = new Error(parsed.error);
198
+ if (parsed.loc) {
199
+ error.loc = parsed.loc;
200
+ }
201
+
202
+ throw error;
203
+ }
204
+
205
+ return parsed;
206
+ }
207
+
208
+ module.exports = {
209
+ getLang,
210
+ getInfoFilepath,
211
+ parseSync
212
+ };