prettier 2.1.0 → 3.0.0

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 (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
data/dist/haml/parser.rb DELETED
@@ -1,149 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ripper'
4
-
5
- begin
6
- require 'haml'
7
- rescue LoadError
8
- # If we can't load the haml gem, then we're going to provide a shim parser
9
- # that will warn and bail out.
10
- class Prettier::HAMLParser
11
- def self.parse(text)
12
- warn(
13
- 'The `haml` gem could not be loaded. Please ensure you have it ' \
14
- 'installed and that it is available in the gem path.'
15
- )
16
-
17
- false
18
- end
19
- end
20
-
21
- return
22
- end
23
-
24
- class Haml::Parser::ParseNode
25
- class DeepAttributeParser
26
- def parse(string)
27
- Haml::AttributeParser.available? ? parse_value(string) : string
28
- end
29
-
30
- private
31
-
32
- def literal(string, level)
33
- level == 0 ? string : "&#{string}"
34
- end
35
-
36
- def parse_value(string, level = 0)
37
- response = Ripper.sexp(string)
38
- return literal(string, level) unless response
39
-
40
- case response[1][0][0]
41
- when :hash
42
- hash = Haml::AttributeParser.parse(string)
43
-
44
- if hash
45
- # Explicitly not using Enumerable#to_h here to support Ruby 2.5
46
- hash.each_with_object({}) do |(key, value), response|
47
- # For attributes that starts with @, wrap the attribute in quotes
48
- # For other attributes, remove the quotes
49
- # AlpineJS uses @-attributes
50
- # {'type': 'submit'} => {type: 'submit'}
51
- # {'@click': 'open'} => {'@click': 'open'}
52
- key = "\'#{key}\'" if key.start_with?('@')
53
- response[key] = parse_value(value, level + 1)
54
- end
55
- else
56
- literal(string, level)
57
- end
58
- when :string_literal
59
- string[1...-1]
60
- else
61
- literal(string, level)
62
- end
63
- end
64
- end
65
-
66
- ESCAPE = /Haml::Helpers.html_escape\(\((.+)\)\)/.freeze
67
-
68
- # If a node comes in as the plain type but starts with one of the special
69
- # characters that haml parses, then we need to escape it with a \ when
70
- # printing. So here we make a regexp pattern to check if the node needs to be
71
- # escaped.
72
- special_chars =
73
- Haml::Parser::SPECIAL_CHARACTERS.map { |char| Regexp.escape(char) }
74
-
75
- SPECIAL_START = /\A(?:#{special_chars.join('|')})/
76
-
77
- def as_json
78
- case type
79
- when :comment, :doctype, :silent_script
80
- to_h.tap do |json|
81
- json.delete(:parent)
82
- json[:children] = children.map(&:as_json)
83
- end
84
- when :filter, :haml_comment
85
- to_h.tap { |json| json.delete(:parent) }
86
- when :plain
87
- to_h.tap do |json|
88
- json.delete(:parent)
89
- json[:children] = children.map(&:as_json)
90
-
91
- text = json[:value][:text]
92
- json[:value][:text] = "\\#{text}" if text.match?(SPECIAL_START)
93
- end
94
- when :root
95
- to_h.tap do |json|
96
- json[:children] = children.map(&:as_json)
97
-
98
- # We need this information in the printer to know how to lay out
99
- # multi-line attributes.
100
- json[:supports_multiline] =
101
- Gem::Version.new(Haml::VERSION) >= Gem::Version.new('5.2')
102
- end
103
- when :script
104
- to_h.tap do |json|
105
- json.delete(:parent)
106
- json[:children] = children.map(&:as_json)
107
-
108
- if json[:value][:text].match?(ESCAPE)
109
- json[:value][:text].gsub!(ESCAPE) { $1 }
110
- json[:value].merge!(escape_html: 'escape_html', interpolate: true)
111
- end
112
- end
113
- when :tag
114
- to_h.tap do |json|
115
- json.delete(:parent)
116
-
117
- # For some reason this is actually using a symbol to represent a null
118
- # object ref instead of nil itself, so just replacing it here for
119
- # simplicity in the printer
120
- json[:value][:object_ref] = nil if json[:value][:object_ref] == :nil
121
-
122
- # Get a reference to the dynamic attributes hash
123
- dynamic_attributes = value[:dynamic_attributes].to_h
124
-
125
- # If we have any in the old style, then we're going to pass it through
126
- # the deep attribute parser filter.
127
- if dynamic_attributes[:old]
128
- dynamic_attributes[:old] =
129
- DeepAttributeParser.new.parse(dynamic_attributes[:old])
130
- end
131
-
132
- json.merge!(
133
- children: children.map(&:as_json),
134
- value: value.merge(dynamic_attributes: dynamic_attributes)
135
- )
136
- end
137
- else
138
- raise ArgumentError, "Unsupported type: #{type}"
139
- end
140
- end
141
- end
142
-
143
- module Prettier
144
- class HAMLParser
145
- def self.parse(source)
146
- Haml::Parser.new({}).call(source).as_json
147
- end
148
- end
149
- end
data/dist/haml/printer.js DELETED
@@ -1,336 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const prettier_1 = __importDefault(require("../prettier"));
7
- const embed_1 = __importDefault(require("./embed"));
8
- const { align, fill, group, hardline, ifBreak, indent, join, line, makeString, softline } = prettier_1.default;
9
- const docTypes = {
10
- basic: "Basic",
11
- frameset: "Frameset",
12
- mobile: "Mobile",
13
- rdfa: "RDFa",
14
- strict: "Strict",
15
- xml: "XML"
16
- };
17
- const docVersions = ["1.1", "5"];
18
- // Prints out a hash key according to the configured prettier options.
19
- function printHashKey(key, opts) {
20
- let quoted = key;
21
- const joiner = opts.rubyHashLabel ? ":" : " =>";
22
- if (key.includes(":") || key.includes("-")) {
23
- const quote = opts.rubySingleQuote ? "'" : '"';
24
- quoted = `${quote}${key}${quote}`;
25
- }
26
- return `${opts.rubyHashLabel ? "" : ":"}${quoted}${joiner}`;
27
- }
28
- // Prints out the value inside of a hash key-value pair according to the
29
- // configured prettier options.
30
- function printHashValue(value, opts) {
31
- if (typeof value !== "string") {
32
- return value.toString();
33
- }
34
- // This is a very special syntax created by the parser to let us know that
35
- // this should be printed literally instead of as a string.
36
- if (value.startsWith("&")) {
37
- return value.slice(1);
38
- }
39
- const quote = opts.rubySingleQuote && !value.includes("#{") && !value.includes("'")
40
- ? "'"
41
- : '"';
42
- return makeString(value, quote);
43
- }
44
- // This will print an attributes object to a Doc node. It handles nesting on
45
- // multiple levels and will print out according to whether or not the version of
46
- // HAML being used supports multi-line attributes.
47
- function printAttributes(object, opts, level = 0) {
48
- if (typeof object !== "object") {
49
- return printHashValue(object, opts);
50
- }
51
- const boundary = level === 0 ? softline : line;
52
- const parts = Object.keys(object).map((key) => [
53
- printHashKey(key, opts),
54
- " ",
55
- printAttributes(object[key], opts, level + 1)
56
- ]);
57
- // If we have support for multi-line attributes laid out like a regular hash,
58
- // then we print them that way here.
59
- if (opts.supportsMultiline) {
60
- return group([
61
- "{",
62
- indent(group([boundary, join([",", line], parts)])),
63
- boundary,
64
- "}"
65
- ]);
66
- }
67
- // Otherwise, if we only have one attribute, then just print it inline
68
- // regardless of how long it is.
69
- if (parts.length === 0) {
70
- return group(["{", parts[0], "}"]);
71
- }
72
- // Otherwise, depending on how long the line is it will split the content into
73
- // multi-line attributes that old Haml understands.
74
- return group([
75
- "{",
76
- parts[0],
77
- ",",
78
- align(opts.headerLength + 1, [line, join([",", line], parts.slice(1))]),
79
- "}"
80
- ]);
81
- }
82
- // A utility function used in a silent script that is meant to determine if a
83
- // child node is a continuation of a parent node (as in a when clause within a
84
- // case statement or an else clause within an if).
85
- function isContinuation(parentNode, childNode) {
86
- if (childNode.type !== "silent_script") {
87
- return false;
88
- }
89
- const parent = parentNode.value.keyword;
90
- const child = childNode.value.keyword;
91
- return ((parent === "case" && ["when", "else"].includes(child)) ||
92
- (["if", "unless"].includes(parent) && ["elsif", "else"].includes(child)));
93
- }
94
- const printer = {
95
- embed: embed_1.default,
96
- // This is our printer's main print function that will switch on the type of
97
- // node and print it out by returning a Doc tree.
98
- print(path, opts, print) {
99
- const node = path.getValue();
100
- switch (node.type) {
101
- // https://haml.info/docs/yardoc/file.REFERENCE.html#html-comments-
102
- case "comment": {
103
- const { value } = node;
104
- const parts = ["/"];
105
- if (value.revealed) {
106
- parts.push("!");
107
- }
108
- if (value.conditional) {
109
- parts.push(value.conditional);
110
- }
111
- else if (value.text) {
112
- parts.push(" ", value.text);
113
- }
114
- return printWithChildren(node, group(parts));
115
- }
116
- // https://haml.info/docs/yardoc/file.REFERENCE.html#doctype-
117
- case "doctype": {
118
- const { value } = node;
119
- const parts = ["!!!"];
120
- if (value.type in docTypes) {
121
- parts.push(docTypes[value.type]);
122
- }
123
- else if (value.version && docVersions.includes(value.version)) {
124
- parts.push(value.version);
125
- }
126
- else {
127
- parts.push(value.type);
128
- }
129
- if (value.encoding) {
130
- parts.push(value.encoding);
131
- }
132
- return group(join(" ", parts));
133
- }
134
- // https://haml.info/docs/yardoc/file.REFERENCE.html#filters
135
- case "filter":
136
- return group([
137
- ":",
138
- node.value.name,
139
- indent([hardline, join(hardline, node.value.text.trim().split("\n"))])
140
- ]);
141
- // https://haml.info/docs/yardoc/file.REFERENCE.html#haml-comments--
142
- case "haml_comment": {
143
- const { value } = node;
144
- const parts = ["-#"];
145
- if (value.text) {
146
- if (opts.originalText.split("\n")[node.line - 1].trim() === "-#") {
147
- const lines = value.text.trim().split("\n");
148
- parts.push(indent([hardline, join(hardline, lines)]));
149
- }
150
- else {
151
- parts.push(" ", value.text.trim());
152
- }
153
- }
154
- return parts;
155
- }
156
- // https://haml.info/docs/yardoc/file.REFERENCE.html#plain-text
157
- case "plain":
158
- return node.value.text;
159
- // The root node in the AST that we build in the parser.
160
- case "root": {
161
- const nodePath = path;
162
- return [join(hardline, nodePath.map(print, "children")), hardline];
163
- }
164
- // https://haml.info/docs/yardoc/file.REFERENCE.html#inserting_ruby
165
- case "script": {
166
- const { value } = node;
167
- const parts = [];
168
- if (value.escape_html) {
169
- parts.unshift("&");
170
- }
171
- if (value.preserve) {
172
- parts.push("~");
173
- }
174
- else if (!value.interpolate) {
175
- parts.push("=");
176
- }
177
- if (value.escape_html && !value.preserve && value.interpolate) {
178
- parts.push(" ", value.text.trim().slice(1, -1));
179
- }
180
- else {
181
- parts.push(" ", value.text.trim());
182
- }
183
- return printWithChildren(node, group(parts));
184
- }
185
- // https://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
186
- case "silent_script": {
187
- const parts = [`- ${node.value.text.trim()}`];
188
- if (node.children.length > 0) {
189
- const nodePath = path;
190
- parts.push(nodePath.map((childPath) => {
191
- const child = childPath.getValue();
192
- const concated = [hardline, print(childPath)];
193
- return isContinuation(node, child) ? concated : indent(concated);
194
- }, "children"));
195
- }
196
- return group(parts);
197
- }
198
- // https://haml.info/docs/yardoc/file.REFERENCE.html#element-name-
199
- case "tag": {
200
- const { value } = node;
201
- const { attributes, dynamic_attributes } = value;
202
- const parts = [];
203
- // If we have a tag that isn't a div, then we need to print out that
204
- // name of that tag first. If it is a div, first we'll check if there
205
- // are any other things that would force us to print out the div
206
- // explicitly, and otherwise we'll leave it off.
207
- if (value.name !== "div") {
208
- parts.push(`%${value.name}`);
209
- }
210
- // If we have a class attribute, then we're going to print that here
211
- // using the special class syntax.
212
- if (attributes.class) {
213
- parts.push(`.${attributes.class.replace(/ /g, ".")}`);
214
- }
215
- // If we have an id attribute, then we're going to print that here using
216
- // the special id syntax.
217
- if (attributes.id) {
218
- parts.push(`#${attributes.id}`);
219
- }
220
- // If we're using dynamic attributes on this tag, then they come in as a
221
- // string that looks like the output of Hash#inspect from Ruby. So here
222
- // we're going to split it all up and print it out nicely.
223
- if (dynamic_attributes.new) {
224
- const docs = [];
225
- dynamic_attributes.new
226
- .slice(1, -2)
227
- .split(",")
228
- .forEach((pair, index) => {
229
- if (index !== 0) {
230
- docs.push(line);
231
- }
232
- docs.push(join("=", pair.slice(1).split('" => ')));
233
- });
234
- parts.push(group(["(", align(parts.join("").length + 1, fill(docs)), ")"]));
235
- }
236
- // If there are any static attributes that are not class or id (because
237
- // we already took care of those), then we're going to print them out
238
- // here.
239
- const staticAttributes = Object.keys(attributes).filter((name) => !["class", "id"].includes(name));
240
- if (staticAttributes.length > 0) {
241
- const docs = staticAttributes.reduce((accum, key) => {
242
- const doc = `${printHashKey(key, opts)} ${printHashValue(attributes[key], opts)}`;
243
- return accum.length === 0 ? [doc] : [...accum, ",", line, doc];
244
- }, []);
245
- parts.push(group(["{", align(parts.join("").length + 1, fill(docs)), "}"]));
246
- }
247
- // If there are dynamic attributes that don't use the newer syntax, then
248
- // we're going to print them out here.
249
- if (dynamic_attributes.old) {
250
- if (parts.length === 0) {
251
- parts.push("%div");
252
- }
253
- if (typeof dynamic_attributes.old === "string") {
254
- parts.push(dynamic_attributes.old);
255
- }
256
- else {
257
- // This is kind of a total hack in that I don't think you're
258
- // really supposed to directly use `path.stack`, but it's the
259
- // easiest way to get the root node without having to know how
260
- // many levels deep we are.
261
- const root = path.stack[0];
262
- parts.push(printAttributes(dynamic_attributes.old, {
263
- ...opts,
264
- supportsMultiline: root.supports_multiline,
265
- headerLength: parts.join("").length
266
- }));
267
- }
268
- }
269
- // https://haml.info/docs/yardoc/file.REFERENCE.html#object-reference-
270
- if (value.object_ref) {
271
- if (parts.length === 0) {
272
- parts.push("%div");
273
- }
274
- parts.push(value.object_ref);
275
- }
276
- // https://haml.info/docs/yardoc/file.REFERENCE.html#whitespace-removal--and-
277
- if (value.nuke_outer_whitespace) {
278
- parts.push(">");
279
- }
280
- if (value.nuke_inner_whitespace) {
281
- parts.push("<");
282
- }
283
- // https://haml.info/docs/yardoc/file.REFERENCE.html#empty-void-tags-
284
- if (value.self_closing) {
285
- parts.push("/");
286
- }
287
- if (value.value) {
288
- let contents;
289
- if (value.parse && value.value.match(/#[{$@]/)) {
290
- // There's a weird case here where if the value includes
291
- // interpolation and it's marked as { parse: true }, then we don't
292
- // actually want the = prefix, and we want to remove extra escaping.
293
- contents = [
294
- ifBreak("", " "),
295
- value.value.slice(1, -1).replace(/\\"/g, '"')
296
- ];
297
- }
298
- else if (value.parse) {
299
- contents = ["= ", value.value];
300
- }
301
- else {
302
- contents = [ifBreak("", " "), value.value];
303
- }
304
- return printWithChildren(node, group([group(parts), indent([softline, ...contents])]));
305
- }
306
- // In case none of the other if statements have matched and we're
307
- // printing a div, we need to explicitly add it back into the array.
308
- if (parts.length === 0 && value.name === "div") {
309
- parts.push("%div");
310
- }
311
- return printWithChildren(node, group(parts));
312
- }
313
- default:
314
- throw new Error(`Unsupported node encountered: ${node.type}`);
315
- }
316
- // It's common to a couple of nodes to attach nested child nodes on the
317
- // children property. This utility prints them out grouped together with
318
- // their parent node docs.
319
- function printWithChildren(node, docs) {
320
- if (node.children.length === 0) {
321
- return docs;
322
- }
323
- const nodePath = path;
324
- return group([
325
- docs,
326
- indent([hardline, join(hardline, nodePath.map(print, "children"))])
327
- ]);
328
- }
329
- },
330
- // This function handles adding the format pragma to a source string. This is
331
- // an optional workflow for incremental adoption.
332
- insertPragma(text) {
333
- return `-# @format${text.startsWith("-#") ? "\n" : "\n\n"}${text}`;
334
- }
335
- };
336
- exports.default = printer;
@@ -1,179 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getInfoFilepath = exports.getLang = void 0;
7
- const child_process_1 = require("child_process");
8
- const fs_1 = require("fs");
9
- const os_1 = __importDefault(require("os"));
10
- const path_1 = __importDefault(require("path"));
11
- const process_1 = __importDefault(require("process"));
12
- let parserArgs;
13
- if (process_1.default.env.PRETTIER_RUBY_HOST) {
14
- const [cmd, ...args] = process_1.default.env.PRETTIER_RUBY_HOST.split(" ");
15
- parserArgs = { cmd, args };
16
- }
17
- // In order to properly parse ruby code, we need to tell the ruby process to
18
- // parse using UTF-8. Unfortunately, the way that you accomplish this looks
19
- // differently depending on your platform.
20
- /* istanbul ignore next */
21
- function getLang() {
22
- const { env, platform } = process_1.default;
23
- const envValue = env.LC_ALL || env.LC_CTYPE || env.LANG;
24
- // If an env var is set for the locale that already includes UTF-8 in the
25
- // name, then assume we can go with that.
26
- if (envValue && envValue.includes("UTF-8")) {
27
- return envValue;
28
- }
29
- // Otherwise, we're going to guess which encoding to use based on the system.
30
- // This is probably not the best approach in the world, as you could be on
31
- // linux and not have C.UTF-8, but in that case you're probably passing an env
32
- // var for it. This object below represents all of the possible values of
33
- // process.platform per:
34
- // https://nodejs.org/api/process.html#process_process_platform
35
- return {
36
- aix: "C.UTF-8",
37
- android: "C.UTF-8",
38
- cygwin: "C.UTF-8",
39
- darwin: "en_US.UTF-8",
40
- freebsd: "C.UTF-8",
41
- haiku: "C.UTF-8",
42
- linux: "C.UTF-8",
43
- netbsd: "C.UTF-8",
44
- openbsd: "C.UTF-8",
45
- sunos: "C.UTF-8",
46
- win32: ".UTF-8"
47
- }[platform];
48
- }
49
- exports.getLang = getLang;
50
- // Generate the filepath that should be used to communicate the connection
51
- // information between this process and the parser server.
52
- function getInfoFilepath() {
53
- return path_1.default.join(os_1.default.tmpdir(), `prettier-ruby-parser-${process_1.default.pid}.info`);
54
- }
55
- exports.getInfoFilepath = getInfoFilepath;
56
- // Create a file that will act as a communication mechanism, spawn a parser
57
- // server with that filepath as an argument, then spawn another process that
58
- // will read that information in order to enable us to connect to it in the
59
- // spawnSync function.
60
- function spawnServer() {
61
- const tempDir = (0, fs_1.mkdtempSync)(path_1.default.join(os_1.default.tmpdir(), "prettier-plugin-ruby-"));
62
- const filepath = getInfoFilepath();
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], {
108
- env: Object.assign({}, process_1.default.env, { LANG: getLang() }),
109
- detached: true,
110
- stdio: "inherit"
111
- });
112
- server.unref();
113
- process_1.default.on("exit", () => {
114
- if ((0, fs_1.existsSync)(filepath)) {
115
- (0, fs_1.unlinkSync)(filepath);
116
- }
117
- if (cleanupTempFiles != null) {
118
- cleanupTempFiles();
119
- }
120
- try {
121
- if (server.pid) {
122
- process_1.default.kill(-server.pid);
123
- }
124
- }
125
- catch (e) {
126
- if (process_1.default.env.PLUGIN_RUBY_CI) {
127
- throw new Error(`Failed to kill the parser server: ${e}`);
128
- }
129
- }
130
- });
131
- const info = (0, child_process_1.spawnSync)("node", [getInfoJsPath, filepath]);
132
- if (info.status !== 0) {
133
- throw new Error(`
134
- We failed to spawn our parser server. Please report this error on GitHub
135
- at https://github.com/prettier/plugin-ruby. The error message was:
136
-
137
- ${info.stderr.toString()}.
138
- `);
139
- }
140
- const [cmd, ...args] = info.stdout.toString().split(" ");
141
- return { cmd, args };
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
- }
149
- // Formats and sends a request to the parser server. We use netcat (or something
150
- // like it) here since Prettier requires the results of `parse` to be
151
- // synchronous and Node.js does not offer a mechanism for synchronous socket
152
- // requests.
153
- function parseSync(parser, source) {
154
- if (!parserArgs) {
155
- parserArgs = spawnServer();
156
- }
157
- const response = (0, child_process_1.spawnSync)(parserArgs.cmd, parserArgs.args, {
158
- input: `${parser}|${source}`,
159
- maxBuffer: 15 * 1024 * 1024
160
- });
161
- const stdout = response.stdout.toString();
162
- const stderr = response.stderr.toString();
163
- const { status } = response;
164
- // If we didn't receive anything over stdout or we have a bad exit status,
165
- // then throw whatever we can.
166
- if (stdout.length === 0 || (status !== null && status !== 0)) {
167
- throw new Error(stderr || "An unknown error occurred");
168
- }
169
- const parsed = JSON.parse(stdout);
170
- if (parsed.error) {
171
- const error = new Error(parsed.error);
172
- if (parsed.loc) {
173
- error.loc = parsed.loc;
174
- }
175
- throw error;
176
- }
177
- return parsed;
178
- }
179
- exports.default = parseSync;