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
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;