prettier 0.21.0 → 1.0.1

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +112 -7
  3. data/CONTRIBUTING.md +4 -4
  4. data/README.md +18 -14
  5. data/package.json +9 -6
  6. data/src/embed.js +27 -8
  7. data/src/nodes.js +5 -2
  8. data/src/nodes/alias.js +29 -31
  9. data/src/nodes/aref.js +26 -26
  10. data/src/nodes/args.js +55 -47
  11. data/src/nodes/arrays.js +132 -106
  12. data/src/nodes/assign.js +32 -32
  13. data/src/nodes/blocks.js +8 -3
  14. data/src/nodes/calls.js +163 -60
  15. data/src/nodes/case.js +11 -7
  16. data/src/nodes/class.js +74 -0
  17. data/src/nodes/commands.js +36 -31
  18. data/src/nodes/conditionals.js +44 -30
  19. data/src/nodes/constants.js +39 -21
  20. data/src/nodes/flow.js +11 -1
  21. data/src/nodes/hashes.js +90 -109
  22. data/src/nodes/heredocs.js +34 -0
  23. data/src/nodes/hooks.js +21 -22
  24. data/src/nodes/ints.js +27 -20
  25. data/src/nodes/lambdas.js +14 -27
  26. data/src/nodes/loops.js +10 -5
  27. data/src/nodes/massign.js +87 -65
  28. data/src/nodes/methods.js +48 -73
  29. data/src/nodes/operators.js +70 -39
  30. data/src/nodes/params.js +26 -16
  31. data/src/nodes/patterns.js +108 -33
  32. data/src/nodes/regexp.js +45 -14
  33. data/src/nodes/rescue.js +72 -59
  34. data/src/nodes/statements.js +86 -44
  35. data/src/nodes/strings.js +95 -85
  36. data/src/nodes/super.js +35 -0
  37. data/src/nodes/undef.js +42 -0
  38. data/src/parser.js +86 -0
  39. data/src/parser.rb +2400 -621
  40. data/src/printer.js +90 -0
  41. data/src/ruby.js +19 -41
  42. data/src/toProc.js +4 -4
  43. data/src/utils.js +24 -88
  44. data/src/utils/literalLineNoBreak.js +7 -0
  45. data/src/utils/printEmptyCollection.js +42 -0
  46. metadata +12 -49
  47. data/src/nodes/scopes.js +0 -61
  48. data/src/parse.js +0 -37
  49. data/src/print.js +0 -23
@@ -1,28 +1,29 @@
1
1
  const { concat, group, indent, line } = require("../prettier");
2
2
  const { isEmptyStmts } = require("../utils");
3
3
 
4
- /* The `BEGIN` and `END` keywords are used to hook into the Ruby process. Any
5
- * `BEGIN` blocks are executed right when the process starts up, and the `END`
6
- * blocks are executed right before exiting.
7
- *
8
- * BEGIN {
9
- * # content goes here
10
- * }
11
- *
12
- * END {
13
- * # content goes here
14
- * }
15
- *
16
- * Interesting side note, you don't use `do...end` blocks with these hooks. Both
17
- * nodes contain one child which is a `stmts` node.
18
- */
4
+ // The `BEGIN` and `END` keywords are used to hook into the Ruby process. Any
5
+ // `BEGIN` blocks are executed right when the process starts up, and the `END`
6
+ // blocks are executed right before exiting.
7
+ //
8
+ // BEGIN {
9
+ // # content goes here
10
+ // }
11
+ //
12
+ // END {
13
+ // # content goes here
14
+ // }
15
+ //
16
+ // Interesting side note, you don't use `do...end` blocks with these hooks. Both
17
+ // nodes contain one child which is a `stmts` node.
19
18
  function printHook(name) {
20
- function printHookWithName(path, opts, print) {
21
- const stmtsNode = path.getValue().body[0];
22
- const printedStmts = path.call(print, "body", 0);
19
+ return function printHookWithName(path, opts, print) {
20
+ const stmtsNode = path.getValue().body[1];
21
+ const printedStmts = path.call(print, "body", 1);
23
22
 
24
23
  const parts = [
25
- `${name} {`,
24
+ name,
25
+ " ",
26
+ path.call(print, "body", 0),
26
27
  indent(concat([line, printedStmts])),
27
28
  concat([line, "}"])
28
29
  ];
@@ -34,9 +35,7 @@ function printHook(name) {
34
35
  }
35
36
 
36
37
  return group(concat(parts));
37
- }
38
-
39
- return printHookWithName;
38
+ };
40
39
  }
41
40
 
42
41
  module.exports = {
@@ -1,24 +1,31 @@
1
- module.exports = {
2
- "@int": (path, _opts, _print) => {
3
- const { body } = path.getValue();
1
+ // An @int node is any literal integer in Ruby. They can come in a number of
2
+ // bases, and look like the following:
3
+ //
4
+ // Binary (2) - 0b0110
5
+ // Octal (8) - 0o34 or 034
6
+ // Decimal (10) - a normal number like 159
7
+ // Hexidecimal (16) - 0xac5
8
+ //
9
+ // If it's a decimal number, it can be optional separated by any number of
10
+ // arbitrarily places underscores. This can be useful for dollars and cents
11
+ // (34_99), dates (2020_11_30), and normal 3 digit separation (1_222_333).
12
+ function printInt(path, _opts, _print) {
13
+ const { body } = path.getValue();
4
14
 
5
- // If the number is octal and does not contain the optional "o" character
6
- // after the leading 0, add it in.
7
- if (/^0[0-9]/.test(body)) {
8
- return `0o${body.slice(1)}`;
9
- }
15
+ // If the number is a base 10 number, is sufficiently large, and is not
16
+ // already formatted with underscores, then add them in in between the
17
+ // numbers every three characters starting from the right.
18
+ if (!body.startsWith("0") && body.length >= 5 && !body.includes("_")) {
19
+ return ` ${body}`
20
+ .slice((body.length + 2) % 3)
21
+ .match(/.{3}/g)
22
+ .join("_")
23
+ .trim();
24
+ }
10
25
 
11
- // If the number is a base 10 number, is sufficiently large, and is not
12
- // already formatted with underscores, then add them in in between the
13
- // numbers every three characters starting from the right.
14
- if (!body.startsWith("0") && body.length >= 5 && !body.includes("_")) {
15
- return ` ${body}`
16
- .slice((body.length + 2) % 3)
17
- .match(/.{3}/g)
18
- .join("_")
19
- .trim();
20
- }
26
+ return body;
27
+ }
21
28
 
22
- return body;
23
- }
29
+ module.exports = {
30
+ "@int": printInt
24
31
  };
@@ -1,41 +1,28 @@
1
- const {
2
- concat,
3
- group,
4
- ifBreak,
5
- indent,
6
- line,
7
- softline
8
- } = require("../prettier");
9
- const { hasAncestor, nodeDive } = require("../utils");
1
+ const { concat, group, ifBreak, indent, line } = require("../prettier");
2
+ const { hasAncestor } = require("../utils");
10
3
 
11
4
  // We can have our params coming in as the first child of the main lambda node,
12
5
  // or if we have them wrapped in parens then they'll be one level deeper. Even
13
6
  // though it's possible to omit the parens if you only have one argument, we're
14
7
  // going to keep them in no matter what for consistency.
15
- const printLambdaParams = (path, print) => {
16
- const steps = ["body", 0];
17
- let params = nodeDive(path.getValue(), steps);
8
+ function printLambdaParams(path, print) {
9
+ let node = path.getValue().body[0];
18
10
 
19
- if (params.type !== "params") {
20
- steps.push("body", 0);
21
- params = nodeDive(path.getValue(), steps);
11
+ // In this case we had something like -> (foo) { bar } which would mean that
12
+ // we're looking at a paren node, so we'll descend one level deeper to get at
13
+ // the actual params node.
14
+ if (node.type !== "params") {
15
+ node = node.body[0];
22
16
  }
23
17
 
24
18
  // If we don't have any params at all, then we're just going to bail out and
25
19
  // print nothing. This is to avoid printing an empty set of parentheses.
26
- if (params.body.every((type) => !type)) {
20
+ if (node.body.every((type) => !type)) {
27
21
  return "";
28
22
  }
29
23
 
30
- return group(
31
- concat([
32
- "(",
33
- indent(concat([softline, path.call.apply(path, [print].concat(steps))])),
34
- softline,
35
- ")"
36
- ])
37
- );
38
- };
24
+ return path.call(print, "body", 0);
25
+ }
39
26
 
40
27
  // Lambda nodes represent stabby lambda literals, which can come in a couple of
41
28
  // flavors. They can use either braces or do...end for their block, and their
@@ -64,7 +51,7 @@ const printLambdaParams = (path, print) => {
64
51
  // for the single-line form. However, if we have an ancestor that is a command
65
52
  // or command_call node, then we'll need to use braces either way because of
66
53
  // operator precendence.
67
- const printLambda = (path, opts, print) => {
54
+ function printLambda(path, opts, print) {
68
55
  const params = printLambdaParams(path, print);
69
56
  const inCommand = hasAncestor(path, ["command", "command_call"]);
70
57
 
@@ -82,7 +69,7 @@ const printLambda = (path, opts, print) => {
82
69
  concat(["->", params, " { ", path.call(print, "body", 1), " }"])
83
70
  )
84
71
  );
85
- };
72
+ }
86
73
 
87
74
  module.exports = {
88
75
  lambda: printLambda
@@ -1,5 +1,6 @@
1
1
  const {
2
2
  align,
3
+ breakParent,
3
4
  concat,
4
5
  group,
5
6
  hardline,
@@ -11,12 +12,16 @@ const {
11
12
  const { containsAssignment } = require("../utils");
12
13
  const inlineEnsureParens = require("../utils/inlineEnsureParens");
13
14
 
14
- const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
15
- const [_predicate, statements] = path.getValue().body;
15
+ const printLoop = (keyword, modifier) => (path, { rubyModifier }, print) => {
16
+ const [_predicate, stmts] = path.getValue().body;
16
17
 
17
18
  // If the only statement inside this while loop is a void statement, then we
18
19
  // can shorten to just displaying the predicate and then a semicolon.
19
- if (statements.body.length === 1 && statements.body[0].type === "void_stmt") {
20
+ if (
21
+ stmts.body.length === 1 &&
22
+ stmts.body[0].type === "void_stmt" &&
23
+ !stmts.body[0].comments
24
+ ) {
20
25
  return group(
21
26
  concat([
22
27
  keyword,
@@ -62,8 +67,8 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
62
67
  // an assignment (in which case we can't know for certain that that
63
68
  // assignment doesn't impact the statements inside the loop) then we can't
64
69
  // use the modifier form and we must use the block form.
65
- if (!inlineLoops || containsAssignment(path.getValue().body[0])) {
66
- return blockLoop;
70
+ if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
71
+ return concat([breakParent, blockLoop]);
67
72
  }
68
73
 
69
74
  return group(ifBreak(blockLoop, inlineLoop));
@@ -1,69 +1,91 @@
1
1
  const { concat, group, indent, join, line, softline } = require("../prettier");
2
- const { makeList } = require("../utils");
3
2
 
4
- module.exports = {
5
- massign: (path, opts, print) => {
6
- let right = path.call(print, "body", 1);
7
-
8
- if (
9
- ["mrhs_add_star", "mrhs_new_from_args"].includes(
10
- path.getValue().body[1].type
11
- )
12
- ) {
13
- right = group(join(concat([",", line]), right));
14
- }
15
-
16
- const parts = [join(concat([",", line]), path.call(print, "body", 0))];
17
- if (path.getValue().body[0].comma) {
18
- parts.push(",");
19
- }
20
-
21
- return group(
22
- concat([group(concat(parts)), " =", indent(concat([line, right]))])
23
- );
24
- },
25
- mlhs: makeList,
26
- mlhs_add_post: (path, opts, print) =>
27
- path.call(print, "body", 0).concat(path.call(print, "body", 1)),
28
- mlhs_add_star: (path, opts, print) =>
29
- path
30
- .call(print, "body", 0)
31
- .concat([
32
- path.getValue().body[1]
33
- ? concat(["*", path.call(print, "body", 1)])
34
- : "*"
35
- ]),
36
- mlhs_paren: (path, opts, print) => {
37
- if (["massign", "mlhs_paren"].includes(path.getParentNode().type)) {
38
- // If we're nested in brackets as part of the left hand side of an
39
- // assignment, i.e., (a, b, c) = 1, 2, 3
40
- // ignore the current node and just go straight to the content
41
- return path.call(print, "body", 0);
42
- }
43
-
44
- const parts = [
45
- softline,
46
- join(concat([",", line]), path.call(print, "body", 0))
47
- ];
48
-
49
- if (path.getValue().body[0].comma) {
50
- parts.push(",");
51
- }
52
-
53
- return group(concat(["(", indent(concat(parts)), concat([softline, ")"])]));
54
- },
55
- mrhs: makeList,
56
- mrhs_add_star: (path, opts, print) =>
57
- path
58
- .call(print, "body", 0)
59
- .concat([concat(["*", path.call(print, "body", 1)])]),
60
- mrhs_new_from_args: (path, opts, print) => {
61
- const parts = path.call(print, "body", 0);
62
-
63
- if (path.getValue().body.length > 1) {
64
- parts.push(path.call(print, "body", 1));
65
- }
66
-
67
- return parts;
3
+ function printMAssign(path, opts, print) {
4
+ let right = path.call(print, "body", 1);
5
+
6
+ if (
7
+ ["mrhs_add_star", "mrhs_new_from_args"].includes(
8
+ path.getValue().body[1].type
9
+ )
10
+ ) {
11
+ right = group(join(concat([",", line]), right));
12
+ }
13
+
14
+ const parts = [join(concat([",", line]), path.call(print, "body", 0))];
15
+ if (path.getValue().body[0].comma) {
16
+ parts.push(",");
17
+ }
18
+
19
+ return group(
20
+ concat([group(concat(parts)), " =", indent(concat([line, right]))])
21
+ );
22
+ }
23
+
24
+ function printMLHS(path, opts, print) {
25
+ return path.map(print, "body");
26
+ }
27
+
28
+ function printMLHSAddPost(path, opts, print) {
29
+ return path.call(print, "body", 0).concat(path.call(print, "body", 1));
30
+ }
31
+
32
+ function printMLHSAddStar(path, opts, print) {
33
+ const rightParts = ["*"];
34
+
35
+ if (path.getValue().body[1]) {
36
+ rightParts.push(path.call(print, "body", 1));
37
+ }
38
+
39
+ return path.call(print, "body", 0).concat(concat(rightParts));
40
+ }
41
+
42
+ function printMLHSParen(path, opts, print) {
43
+ if (["massign", "mlhs_paren"].includes(path.getParentNode().type)) {
44
+ // If we're nested in brackets as part of the left hand side of an
45
+ // assignment, i.e., (a, b, c) = 1, 2, 3
46
+ // ignore the current node and just go straight to the content
47
+ return path.call(print, "body", 0);
68
48
  }
49
+
50
+ const parts = [
51
+ softline,
52
+ join(concat([",", line]), path.call(print, "body", 0))
53
+ ];
54
+
55
+ if (path.getValue().body[0].comma) {
56
+ parts.push(",");
57
+ }
58
+
59
+ return group(concat(["(", indent(concat(parts)), concat([softline, ")"])]));
60
+ }
61
+
62
+ function printMRHS(path, opts, print) {
63
+ return path.map(print, "body");
64
+ }
65
+
66
+ function printMRHSAddStar(path, opts, print) {
67
+ const [leftDoc, rightDoc] = path.map(print, "body");
68
+
69
+ return leftDoc.concat([concat(["*", rightDoc])]);
70
+ }
71
+
72
+ function printMRHSNewFromArgs(path, opts, print) {
73
+ const parts = path.call(print, "body", 0);
74
+
75
+ if (path.getValue().body[1]) {
76
+ parts.push(path.call(print, "body", 1));
77
+ }
78
+
79
+ return parts;
80
+ }
81
+
82
+ module.exports = {
83
+ massign: printMAssign,
84
+ mlhs: printMLHS,
85
+ mlhs_add_post: printMLHSAddPost,
86
+ mlhs_add_star: printMLHSAddStar,
87
+ mlhs_paren: printMLHSParen,
88
+ mrhs: printMRHS,
89
+ mrhs_add_star: printMRHSAddStar,
90
+ mrhs_new_from_args: printMRHSNewFromArgs
69
91
  };
@@ -1,80 +1,55 @@
1
- const {
2
- align,
3
- concat,
4
- group,
5
- hardline,
6
- indent,
7
- join,
8
- line
9
- } = require("../prettier");
10
- const { first, literal } = require("../utils");
11
-
12
- const printMethod = (offset) => (path, opts, print) => {
13
- const [_name, params, body] = path.getValue().body.slice(offset);
14
- const declaration = ["def "];
15
-
16
- // In this case, we're printing a method that's defined as a singleton, so we
17
- // need to include the target and the operator
18
- if (offset > 0) {
19
- declaration.push(path.call(print, "body", 0), path.call(print, "body", 1));
20
- }
21
-
22
- // In case there are no parens but there are arguments
23
- const parens =
24
- params.type === "params" && params.body.some((paramType) => paramType);
25
-
26
- declaration.push(
27
- path.call(print, "body", offset),
28
- parens ? "(" : "",
29
- path.call(print, "body", offset + 1),
30
- parens ? ")" : ""
31
- );
1
+ const { concat, group, hardline, indent } = require("../prettier");
2
+ const { first } = require("../utils");
3
+
4
+ function printMethod(offset) {
5
+ return function printMethodWithOffset(path, opts, print) {
6
+ const [_name, params, body] = path.getValue().body.slice(offset);
7
+ const declaration = ["def "];
8
+
9
+ // In this case, we're printing a method that's defined as a singleton, so
10
+ // we need to include the target and the operator
11
+ if (offset > 0) {
12
+ declaration.push(
13
+ path.call(print, "body", 0),
14
+ path.call(print, "body", 1)
15
+ );
16
+ }
32
17
 
33
- // If the body is empty, we can replace with a ;
34
- const stmts = body.body[0].body;
35
- if (stmts.length === 1 && stmts[0].type === "void_stmt") {
36
- return group(concat(declaration.concat(["; end"])));
37
- }
18
+ // In case there are no parens but there are arguments
19
+ const parens =
20
+ params.type === "params" && params.body.some((paramType) => paramType);
21
+
22
+ declaration.push(
23
+ path.call(print, "body", offset),
24
+ parens ? "(" : "",
25
+ path.call(print, "body", offset + 1),
26
+ parens ? ")" : ""
27
+ );
28
+
29
+ // If the body is empty, we can replace with a ;
30
+ const stmts = body.body[0].body;
31
+
32
+ if (
33
+ !body.body.slice(1).some((node) => node) &&
34
+ stmts.length === 1 &&
35
+ stmts[0].type === "void_stmt" &&
36
+ !stmts[0].comments
37
+ ) {
38
+ return group(concat(declaration.concat(["; end"])));
39
+ }
38
40
 
39
- return group(
40
- concat([
41
- group(concat(declaration)),
42
- indent(concat([hardline, path.call(print, "body", offset + 2)])),
43
- group(concat([hardline, "end"]))
44
- ])
45
- );
46
- };
41
+ return group(
42
+ concat([
43
+ group(concat(declaration)),
44
+ indent(concat([hardline, path.call(print, "body", offset + 2)])),
45
+ group(concat([hardline, "end"]))
46
+ ])
47
+ );
48
+ };
49
+ }
47
50
 
48
51
  module.exports = {
49
52
  access_ctrl: first,
50
53
  def: printMethod(0),
51
- defs: printMethod(2),
52
- methref: (path, opts, print) => join(".:", path.map(print, "body")),
53
- super: (path, opts, print) => {
54
- const args = path.getValue().body[0];
55
-
56
- if (args.type === "arg_paren") {
57
- // In case there are explicitly no arguments but they are using parens,
58
- // we assume they are attempting to override the initializer and pass no
59
- // arguments up.
60
- if (args.body[0] === null) {
61
- return "super()";
62
- }
63
-
64
- return concat(["super", path.call(print, "body", 0)]);
65
- }
66
-
67
- return concat(["super ", join(", ", path.call(print, "body", 0))]);
68
- },
69
- undef: (path, opts, print) =>
70
- group(
71
- concat([
72
- "undef ",
73
- align(
74
- "undef ".length,
75
- join(concat([",", line]), path.map(print, "body", 0))
76
- )
77
- ])
78
- ),
79
- zsuper: literal("super")
54
+ defs: printMethod(2)
80
55
  };