prettier 1.5.5 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +31 -12
  5. data/node_modules/prettier/bin-prettier.js +13702 -11629
  6. data/node_modules/prettier/index.js +19198 -16572
  7. data/node_modules/prettier/parser-angular.js +61 -40
  8. data/node_modules/prettier/parser-babel.js +22 -1
  9. data/node_modules/prettier/parser-espree.js +22 -1
  10. data/node_modules/prettier/parser-flow.js +22 -1
  11. data/node_modules/prettier/parser-glimmer.js +1 -1
  12. data/node_modules/prettier/parser-graphql.js +1 -1
  13. data/node_modules/prettier/parser-html.js +82 -63
  14. data/node_modules/prettier/parser-markdown.js +24 -9
  15. data/node_modules/prettier/parser-meriyah.js +22 -1
  16. data/node_modules/prettier/parser-postcss.js +22 -1
  17. data/node_modules/prettier/parser-typescript.js +22 -1
  18. data/node_modules/prettier/parser-yaml.js +2 -2
  19. data/node_modules/prettier/third-party.js +1042 -833
  20. data/package.json +3 -3
  21. data/rubocop.yml +9 -0
  22. data/src/haml/parser.js +5 -4
  23. data/src/haml/printer.js +428 -18
  24. data/src/parser/parseSync.js +8 -6
  25. data/src/plugin.js +1 -1
  26. data/src/rbs/parser.js +1 -3
  27. data/src/rbs/printer.js +35 -7
  28. data/src/ruby/nodes/args.js +66 -22
  29. data/src/ruby/nodes/calls.js +8 -1
  30. data/src/ruby/nodes/conditionals.js +47 -45
  31. data/src/ruby/nodes/hashes.js +5 -14
  32. data/src/ruby/nodes/params.js +2 -9
  33. data/src/ruby/nodes/strings.js +95 -2
  34. data/src/ruby/parser.js +1 -3
  35. data/src/ruby/parser.rb +52 -29
  36. data/src/ruby/printer.js +10 -1
  37. data/src/utils/inlineEnsureParens.js +1 -0
  38. data/src/utils/skipAssignIndent.js +8 -1
  39. metadata +3 -12
  40. data/src/haml/nodes/comment.js +0 -27
  41. data/src/haml/nodes/doctype.js +0 -34
  42. data/src/haml/nodes/filter.js +0 -16
  43. data/src/haml/nodes/hamlComment.js +0 -21
  44. data/src/haml/nodes/plain.js +0 -6
  45. data/src/haml/nodes/root.js +0 -8
  46. data/src/haml/nodes/script.js +0 -33
  47. data/src/haml/nodes/silentScript.js +0 -59
  48. data/src/haml/nodes/tag.js +0 -232
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "1.5.5",
3
+ "version": "1.6.0",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
5
  "main": "src/plugin.js",
6
6
  "scripts": {
@@ -24,8 +24,8 @@
24
24
  "devDependencies": {
25
25
  "eslint": "^7.22.0",
26
26
  "eslint-config-prettier": "^8.0.0",
27
- "husky": "^5.0.9",
28
- "jest": "^26.0.0",
27
+ "husky": "^6.0.0",
28
+ "jest": "^27.0.1",
29
29
  "pretty-quick": "^3.1.0"
30
30
  },
31
31
  "eslintConfig": {
data/rubocop.yml CHANGED
@@ -4,6 +4,15 @@
4
4
  Layout:
5
5
  Enabled: false
6
6
 
7
+ # Re-enable Layout/LineLength because certain cops that most projects use
8
+ # (e.g. Style/IfUnlessModifier) require Layout/LineLength to be enabled.
9
+ # By leaving it disabled, those rules will mis-fire.
10
+ #
11
+ # Users can always override these defaults in their own rubocop.yml files.
12
+ # https://github.com/prettier/plugin-ruby/issues/825
13
+ Layout/LineLength:
14
+ Enabled: true
15
+
7
16
  # Disabling all of the following options because they could conflict with a
8
17
  # prettier configuration setting.
9
18
 
data/src/haml/parser.js CHANGED
@@ -1,11 +1,12 @@
1
1
  const parseSync = require("../parser/parseSync");
2
2
 
3
- const parse = (text, _parsers, opts) => {
3
+ function parse(text, _parsers, opts) {
4
4
  return parseSync("haml", text, opts);
5
- };
5
+ }
6
6
 
7
- const pragmaPattern = /^\s*-#\s*@(prettier|format)/;
8
- const hasPragma = (text) => pragmaPattern.test(text);
7
+ function hasPragma(text) {
8
+ return /^\s*-#\s*@(prettier|format)/.test(text);
9
+ }
9
10
 
10
11
  // These functions are just placeholders until we can actually perform this
11
12
  // properly. The functions are necessary otherwise the format with cursor
data/src/haml/printer.js CHANGED
@@ -1,28 +1,438 @@
1
+ const {
2
+ align,
3
+ concat,
4
+ fill,
5
+ group,
6
+ hardline,
7
+ ifBreak,
8
+ indent,
9
+ join,
10
+ line,
11
+ softline
12
+ } = require("../prettier");
1
13
  const embed = require("./embed");
2
- const nodes = {
3
- comment: require("./nodes/comment"),
4
- doctype: require("./nodes/doctype"),
5
- filter: require("./nodes/filter"),
6
- haml_comment: require("./nodes/hamlComment"),
7
- plain: require("./nodes/plain"),
8
- root: require("./nodes/root"),
9
- script: require("./nodes/script"),
10
- silent_script: require("./nodes/silentScript"),
11
- tag: require("./nodes/tag")
14
+
15
+ const docTypes = {
16
+ basic: "Basic",
17
+ frameset: "Frameset",
18
+ mobile: "Mobile",
19
+ rdfa: "RDFa",
20
+ strict: "Strict",
21
+ xml: "XML"
12
22
  };
13
23
 
14
- const genericPrint = (path, opts, print) => {
15
- const { type } = path.getValue();
24
+ const docVersions = ["1.1", "5"];
25
+
26
+ // Prints out a hash key according to the configured prettier options.
27
+ function printHashKey(key, opts) {
28
+ let quoted = key;
29
+ const joiner = opts.rubyHashLabel ? ":" : " =>";
16
30
 
17
- /* istanbul ignore next */
18
- if (!(type in nodes)) {
19
- throw new Error(`Unsupported node encountered: ${type}`);
31
+ if (key.includes(":") || key.includes("-")) {
32
+ const quote = opts.rubySingleQuote ? "'" : '"';
33
+ quoted = `${quote}${key}${quote}`;
20
34
  }
21
35
 
22
- return nodes[type](path, opts, print);
23
- };
36
+ return `${opts.rubyHashLabel ? "" : ":"}${quoted}${joiner}`;
37
+ }
38
+
39
+ // Prints out the value inside of a hash key-value pair according to the
40
+ // configured prettier options.
41
+ function printHashValue(value, opts) {
42
+ if (typeof value !== "string") {
43
+ return value.toString();
44
+ }
45
+
46
+ // This is a very special syntax created by the parser to let us know that
47
+ // this should be printed literally instead of as a string.
48
+ if (value.startsWith("&")) {
49
+ return value.slice(1);
50
+ }
51
+
52
+ const quote = opts.rubySingleQuote && !value.includes("#{") ? "'" : '"';
53
+ return `${quote}${value}${quote}`;
54
+ }
55
+
56
+ // This will print an attributes object to a Doc node. It handles nesting on
57
+ // multiple levels and will print out according to whether or not the version of
58
+ // HAML being used supports multi-line attributes.
59
+ function printAttributes(object, opts, level = 0) {
60
+ if (typeof object !== "object") {
61
+ return printHashValue(object, opts);
62
+ }
63
+
64
+ const boundary = level === 0 ? softline : line;
65
+ const parts = Object.keys(object).map((key) =>
66
+ concat([
67
+ printHashKey(key, opts),
68
+ " ",
69
+ printAttributes(object[key], opts, level + 1)
70
+ ])
71
+ );
72
+
73
+ // If we have support for multi-line attributes laid out like a regular hash,
74
+ // then we print them that way here.
75
+ if (opts.supportsMultiline) {
76
+ return group(
77
+ concat([
78
+ "{",
79
+ indent(group(concat([boundary, join(concat([",", line]), parts)]))),
80
+ boundary,
81
+ "}"
82
+ ])
83
+ );
84
+ }
85
+
86
+ // Otherwise, if we only have one attribute, then just print it inline
87
+ // regardless of how long it is.
88
+ if (parts.length === 0) {
89
+ return group(concat(["{", parts[0], "}"]));
90
+ }
91
+
92
+ // Otherwise, depending on how long the line is it will split the content into
93
+ // multi-line attributes that old Haml understands.
94
+ return group(
95
+ concat([
96
+ "{",
97
+ parts[0],
98
+ ",",
99
+ align(
100
+ opts.headerLength + 1,
101
+ concat([line, join(concat([",", line]), parts.slice(1))])
102
+ ),
103
+ "}"
104
+ ])
105
+ );
106
+ }
107
+
108
+ // A utility function used in a silent script that is meant to determine if a
109
+ // child node is a continuation of a parent node (as in a when clause within a
110
+ // case statement or an else clause within an if).
111
+ function isContinuation(parentNode, childNode) {
112
+ if (childNode.type !== "silent_script") {
113
+ return false;
114
+ }
115
+
116
+ const parent = parentNode.value.keyword;
117
+ const child = childNode.value.keyword;
118
+
119
+ return (
120
+ (parent === "case" && ["when", "else"].includes(child)) ||
121
+ (["if", "unless"].includes(parent) && ["elsif", "else"].includes(child))
122
+ );
123
+ }
124
+
125
+ // This is our printer's main print function that will switch on the type of
126
+ // node and print it out by returning a Doc tree.
127
+ function printNode(path, opts, print) {
128
+ const node = path.getValue();
129
+ const { value } = node;
130
+
131
+ switch (node.type) {
132
+ case "comment":
133
+ return printComment();
134
+ case "doctype":
135
+ return printDoctype();
136
+ case "filter":
137
+ return printFilter();
138
+ case "haml_comment":
139
+ return printHamlComment();
140
+ case "plain":
141
+ return printPlain();
142
+ case "root":
143
+ return printRoot();
144
+ case "script":
145
+ return printScript();
146
+ case "silent_script":
147
+ return printSilentScript();
148
+ case "tag":
149
+ return printTag();
150
+ default:
151
+ throw new Error(`Unsupported node encountered: ${node.type}`);
152
+ }
153
+
154
+ // It's common to a couple of nodes to attach nested child nodes on the
155
+ // children property. This utility prints them out grouped together with their
156
+ // parent node docs.
157
+ function printWithChildren(docs) {
158
+ if (node.children.length === 0) {
159
+ return docs;
160
+ }
161
+
162
+ return group(
163
+ concat([
164
+ docs,
165
+ indent(concat([hardline, join(hardline, path.map(print, "children"))]))
166
+ ])
167
+ );
168
+ }
169
+
170
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#html-comments-
171
+ function printComment() {
172
+ const parts = ["/"];
173
+
174
+ if (value.revealed) {
175
+ parts.push("!");
176
+ }
177
+
178
+ if (value.conditional) {
179
+ parts.push(value.conditional);
180
+ } else if (value.text) {
181
+ parts.push(" ", value.text);
182
+ }
183
+
184
+ return printWithChildren(group(concat(parts)));
185
+ }
186
+
187
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#doctype-
188
+ function printDoctype() {
189
+ const parts = ["!!!"];
190
+
191
+ if (value.type in docTypes) {
192
+ parts.push(docTypes[value.type]);
193
+ } else if (docVersions.includes(value.version)) {
194
+ parts.push(value.version);
195
+ } else {
196
+ parts.push(value.type);
197
+ }
198
+
199
+ if (value.encoding) {
200
+ parts.push(value.encoding);
201
+ }
202
+
203
+ return group(join(" ", parts));
204
+ }
205
+
206
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#filters
207
+ function printFilter() {
208
+ return group(
209
+ concat([
210
+ ":",
211
+ value.name,
212
+ indent(
213
+ concat([hardline, join(hardline, value.text.trim().split("\n"))])
214
+ )
215
+ ])
216
+ );
217
+ }
218
+
219
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#haml-comments--
220
+ function printHamlComment() {
221
+ const parts = ["-#"];
222
+
223
+ if (value.text) {
224
+ if (opts.originalText.split("\n")[node.line - 1].trim() === "-#") {
225
+ const lines = value.text.trim().split("\n");
226
+
227
+ parts.push(indent(concat([hardline, join(hardline, lines)])));
228
+ } else {
229
+ parts.push(" ", value.text.trim());
230
+ }
231
+ }
232
+
233
+ return concat(parts);
234
+ }
235
+
236
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#plain-text
237
+ function printPlain() {
238
+ return value.text;
239
+ }
240
+
241
+ // The root node in the AST that we build in the parser.
242
+ function printRoot() {
243
+ return concat([join(hardline, path.map(print, "children")), hardline]);
244
+ }
245
+
246
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#inserting_ruby
247
+ function printScript() {
248
+ const parts = [];
249
+
250
+ if (value.escape_html) {
251
+ parts.unshift("&");
252
+ }
253
+
254
+ if (value.preserve) {
255
+ parts.push("~");
256
+ } else if (!value.interpolate) {
257
+ parts.push("=");
258
+ }
259
+
260
+ if (value.escape_html && !value.preserve && value.interpolate) {
261
+ parts.push(" ", value.text.trim().slice(1, -1));
262
+ } else {
263
+ parts.push(" ", value.text.trim());
264
+ }
265
+
266
+ return printWithChildren(group(concat(parts)));
267
+ }
268
+
269
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
270
+ function printSilentScript() {
271
+ const parts = [`- ${value.text.trim()}`];
272
+
273
+ if (node.children.length > 0) {
274
+ parts.push(
275
+ concat(
276
+ path.map((childPath) => {
277
+ const child = childPath.getValue();
278
+ const concated = concat([hardline, print(childPath)]);
279
+
280
+ return isContinuation(node, child) ? concated : indent(concated);
281
+ }, "children")
282
+ )
283
+ );
284
+ }
285
+
286
+ return group(concat(parts));
287
+ }
288
+
289
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#element-name-
290
+ function printTag() {
291
+ const { attributes, dynamic_attributes } = value;
292
+ const parts = [];
293
+
294
+ // If we have a tag that isn't a div, then we need to print out that name of
295
+ // that tag first. If it is a div, first we'll check if there are any other
296
+ // things that would force us to print out the div explicitly, and otherwise
297
+ // we'll leave it off.
298
+ if (value.name !== "div") {
299
+ parts.push(`%${value.name}`);
300
+ }
301
+
302
+ // If we have a class attribute, then we're going to print that here using
303
+ // the special class syntax.
304
+ if (attributes.class) {
305
+ parts.push(`.${attributes.class.replace(/ /g, ".")}`);
306
+ }
307
+
308
+ // If we have an id attribute, then we're going to print that here using the
309
+ // special id syntax.
310
+ if (attributes.id) {
311
+ parts.push(`#${attributes.id}`);
312
+ }
313
+
314
+ // If we're using dynamic attributes on this tag, then they come in as a
315
+ // string that looks like the output of Hash#inspect from Ruby. So here
316
+ // we're going to split it all up and print it out nicely.
317
+ if (dynamic_attributes.new) {
318
+ const pairs = dynamic_attributes.new
319
+ .slice(1, -2)
320
+ .split(",")
321
+ .map((pair) => join("=", pair.slice(1).split('" => ')));
322
+
323
+ parts.push(
324
+ group(
325
+ concat([
326
+ "(",
327
+ align(parts.join("").length + 1, fill(join(line, pairs).parts)),
328
+ ")"
329
+ ])
330
+ )
331
+ );
332
+ }
333
+
334
+ // If there are any static attributes that are not class or id (because we
335
+ // already took care of those), then we're going to print them out here.
336
+ const staticAttributes = Object.keys(attributes).filter(
337
+ (name) => !["class", "id"].includes(name)
338
+ );
339
+
340
+ if (staticAttributes.length > 0) {
341
+ const docs = staticAttributes.reduce((accum, key) => {
342
+ const doc = `${printHashKey(key, opts)} ${printHashValue(
343
+ attributes[key],
344
+ opts
345
+ )}`;
346
+
347
+ return accum.length === 0 ? [doc] : accum.concat(",", line, doc);
348
+ }, []);
349
+
350
+ parts.push(
351
+ group(concat(["{", align(parts.join("").length + 1, fill(docs)), "}"]))
352
+ );
353
+ }
354
+
355
+ // If there are dynamic attributes that don't use the newer syntax, then
356
+ // we're going to print them out here.
357
+ if (dynamic_attributes.old) {
358
+ if (parts.length === 0) {
359
+ parts.push("%div");
360
+ }
361
+
362
+ if (typeof dynamic_attributes.old === "string") {
363
+ parts.push(dynamic_attributes.old);
364
+ } else {
365
+ const attrOptions = {
366
+ // This is kind of a total hack in that I don't think you're really
367
+ // supposed to directly use `path.stack`, but it's the easiest way to
368
+ // get the root node without having to know how many levels deep we
369
+ // are.
370
+ supportsMultiline: path.stack[0].supports_multiline,
371
+ headerLength: parts.join("").length
372
+ };
373
+
374
+ parts.push(
375
+ printAttributes(
376
+ dynamic_attributes.old,
377
+ Object.assign({}, opts, attrOptions)
378
+ )
379
+ );
380
+ }
381
+ }
382
+
383
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#object-reference-
384
+ if (value.object_ref) {
385
+ if (parts.length === 0) {
386
+ parts.push("%div");
387
+ }
388
+ parts.push(value.object_ref);
389
+ }
390
+
391
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#whitespace-removal--and-
392
+ if (value.nuke_outer_whitespace) {
393
+ parts.push(">");
394
+ }
395
+
396
+ if (value.nuke_inner_whitespace) {
397
+ parts.push("<");
398
+ }
399
+
400
+ // https://haml.info/docs/yardoc/file.REFERENCE.html#empty-void-tags-
401
+ if (value.self_closing) {
402
+ parts.push("/");
403
+ }
404
+
405
+ if (value.value) {
406
+ const prefix = value.parse ? "= " : ifBreak("", " ");
407
+
408
+ return printWithChildren(
409
+ group(
410
+ concat([
411
+ group(concat(parts)),
412
+ indent(concat([softline, prefix, value.value]))
413
+ ])
414
+ )
415
+ );
416
+ }
417
+
418
+ // In case none of the other if statements have matched and we're printing
419
+ // a div, we need to explicitly add it back into the array.
420
+ if (parts.length === 0 && value.name === "div") {
421
+ parts.push("%div");
422
+ }
423
+
424
+ return printWithChildren(group(concat(parts)));
425
+ }
426
+ }
427
+
428
+ // This function handles adding the format pragma to a source string. This is an
429
+ // optional workflow for incremental adoption.
430
+ function insertPragma(text) {
431
+ return `-# @format${text.startsWith("-#") ? "\n" : "\n\n"}${text}`;
432
+ }
24
433
 
25
434
  module.exports = {
26
435
  embed,
27
- print: genericPrint
436
+ print: printNode,
437
+ insertPragma
28
438
  };