prettier 1.0.1 → 1.2.3

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -1
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +6 -1
  5. data/lib/prettier.rb +2 -2
  6. data/node_modules/prettier/index.js +54 -54
  7. data/package.json +4 -2
  8. data/src/{ruby.js → plugin.js} +2 -2
  9. data/src/{embed.js → ruby/embed.js} +2 -2
  10. data/src/{nodes.js → ruby/nodes.js} +0 -0
  11. data/src/{nodes → ruby/nodes}/alias.js +1 -1
  12. data/src/{nodes → ruby/nodes}/aref.js +8 -1
  13. data/src/{nodes → ruby/nodes}/args.js +2 -2
  14. data/src/{nodes → ruby/nodes}/arrays.js +2 -3
  15. data/src/{nodes → ruby/nodes}/assign.js +12 -4
  16. data/src/{nodes → ruby/nodes}/blocks.js +3 -3
  17. data/src/{nodes → ruby/nodes}/calls.js +54 -11
  18. data/src/ruby/nodes/case.js +65 -0
  19. data/src/{nodes → ruby/nodes}/class.js +1 -1
  20. data/src/ruby/nodes/commands.js +126 -0
  21. data/src/{nodes → ruby/nodes}/conditionals.js +3 -3
  22. data/src/{nodes → ruby/nodes}/constants.js +2 -2
  23. data/src/{nodes → ruby/nodes}/flow.js +2 -2
  24. data/src/{nodes → ruby/nodes}/hashes.js +32 -10
  25. data/src/{nodes → ruby/nodes}/heredocs.js +2 -2
  26. data/src/{nodes → ruby/nodes}/hooks.js +2 -2
  27. data/src/{nodes → ruby/nodes}/ints.js +0 -0
  28. data/src/{nodes → ruby/nodes}/lambdas.js +2 -2
  29. data/src/ruby/nodes/loops.js +104 -0
  30. data/src/{nodes → ruby/nodes}/massign.js +8 -1
  31. data/src/{nodes → ruby/nodes}/methods.js +34 -6
  32. data/src/{nodes → ruby/nodes}/operators.js +2 -2
  33. data/src/{nodes → ruby/nodes}/params.js +9 -2
  34. data/src/{nodes → ruby/nodes}/patterns.js +45 -10
  35. data/src/ruby/nodes/regexp.js +56 -0
  36. data/src/{nodes → ruby/nodes}/rescue.js +2 -2
  37. data/src/ruby/nodes/return.js +98 -0
  38. data/src/{nodes → ruby/nodes}/statements.js +1 -1
  39. data/src/{nodes → ruby/nodes}/strings.js +1 -1
  40. data/src/{nodes → ruby/nodes}/super.js +2 -2
  41. data/src/{nodes → ruby/nodes}/undef.js +1 -1
  42. data/src/{parser.js → ruby/parser.js} +2 -2
  43. data/src/{parser.rb → ruby/parser.rb} +323 -317
  44. data/src/{printer.js → ruby/printer.js} +46 -1
  45. data/src/{toProc.js → ruby/toProc.js} +0 -0
  46. data/src/utils.js +10 -93
  47. data/src/utils/containsAssignment.js +11 -0
  48. data/src/utils/getTrailingComma.js +5 -0
  49. data/src/utils/hasAncestor.js +17 -0
  50. data/src/utils/literal.js +7 -0
  51. data/src/utils/makeCall.js +11 -0
  52. data/src/utils/noIndent.js +10 -0
  53. data/src/utils/skipAssignIndent.js +10 -0
  54. metadata +48 -41
  55. data/src/nodes/case.js +0 -61
  56. data/src/nodes/commands.js +0 -91
  57. data/src/nodes/loops.js +0 -101
  58. data/src/nodes/regexp.js +0 -49
  59. data/src/nodes/return.js +0 -72
@@ -1,5 +1,5 @@
1
- const { concat, group, lineSuffix, join } = require("../prettier");
2
- const { literalLineNoBreak } = require("../utils");
1
+ const { concat, group, lineSuffix, join } = require("../../prettier");
2
+ const { literalLineNoBreak } = require("../../utils");
3
3
 
4
4
  function printHeredoc(path, opts, print) {
5
5
  const { body, ending } = path.getValue();
@@ -1,5 +1,5 @@
1
- const { concat, group, indent, line } = require("../prettier");
2
- const { isEmptyStmts } = require("../utils");
1
+ const { concat, group, indent, line } = require("../../prettier");
2
+ const { isEmptyStmts } = require("../../utils");
3
3
 
4
4
  // The `BEGIN` and `END` keywords are used to hook into the Ruby process. Any
5
5
  // `BEGIN` blocks are executed right when the process starts up, and the `END`
File without changes
@@ -1,5 +1,5 @@
1
- const { concat, group, ifBreak, indent, line } = require("../prettier");
2
- const { hasAncestor } = require("../utils");
1
+ const { concat, group, ifBreak, indent, line } = require("../../prettier");
2
+ const { hasAncestor } = require("../../utils");
3
3
 
4
4
  // We can have our params coming in as the first child of the main lambda node,
5
5
  // or if we have them wrapped in parens then they'll be one level deeper. Even
@@ -0,0 +1,104 @@
1
+ const {
2
+ align,
3
+ breakParent,
4
+ concat,
5
+ group,
6
+ hardline,
7
+ ifBreak,
8
+ indent,
9
+ join,
10
+ softline
11
+ } = require("../../prettier");
12
+
13
+ const { containsAssignment } = require("../../utils");
14
+ const inlineEnsureParens = require("../../utils/inlineEnsureParens");
15
+
16
+ function printLoop(keyword, modifier) {
17
+ return function printLoopWithOptions(path, { rubyModifier }, print) {
18
+ const [_predicate, stmts] = path.getValue().body;
19
+
20
+ // If the only statement inside this while loop is a void statement, then we
21
+ // can shorten to just displaying the predicate and then a semicolon.
22
+ if (
23
+ stmts.body.length === 1 &&
24
+ stmts.body[0].type === "void_stmt" &&
25
+ !stmts.body[0].comments
26
+ ) {
27
+ return group(
28
+ concat([
29
+ keyword,
30
+ " ",
31
+ path.call(print, "body", 0),
32
+ ifBreak(softline, "; "),
33
+ "end"
34
+ ])
35
+ );
36
+ }
37
+
38
+ const inlineLoop = concat(
39
+ inlineEnsureParens(path, [
40
+ path.call(print, "body", 1),
41
+ ` ${keyword} `,
42
+ path.call(print, "body", 0)
43
+ ])
44
+ );
45
+
46
+ // If we're in the modifier form and we're modifying a `begin`, then this is
47
+ // a special case where we need to explicitly use the modifier form because
48
+ // otherwise the semantic meaning changes. This looks like:
49
+ //
50
+ // begin
51
+ // foo
52
+ // end while bar
53
+ //
54
+ // The above is effectively a `do...while` loop (which we don't have in
55
+ // ruby).
56
+ if (modifier && path.getValue().body[1].type === "begin") {
57
+ return inlineLoop;
58
+ }
59
+
60
+ const blockLoop = concat([
61
+ concat([
62
+ `${keyword} `,
63
+ align(keyword.length + 1, path.call(print, "body", 0))
64
+ ]),
65
+ indent(concat([softline, path.call(print, "body", 1)])),
66
+ concat([softline, "end"])
67
+ ]);
68
+
69
+ // If we're disallowing inline loops or if the predicate of the loop
70
+ // contains an assignment (in which case we can't know for certain that that
71
+ // assignment doesn't impact the statements inside the loop) then we can't
72
+ // use the modifier form and we must use the block form.
73
+ if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
74
+ return concat([breakParent, blockLoop]);
75
+ }
76
+
77
+ return group(ifBreak(blockLoop, inlineLoop));
78
+ };
79
+ }
80
+
81
+ function printFor(path, opts, print) {
82
+ const [varDoc, rangeDoc, stmtsDoc] = path.map(print, "body");
83
+ const varsDoc =
84
+ path.getValue().body[0].type === "mlhs" ? join(", ", varDoc) : varDoc;
85
+
86
+ return group(
87
+ concat([
88
+ "for ",
89
+ varsDoc,
90
+ " in ",
91
+ rangeDoc,
92
+ indent(concat([hardline, stmtsDoc])),
93
+ concat([hardline, "end"])
94
+ ])
95
+ );
96
+ }
97
+
98
+ module.exports = {
99
+ while: printLoop("while", false),
100
+ while_mod: printLoop("while", true),
101
+ until: printLoop("until", false),
102
+ until_mod: printLoop("until", true),
103
+ for: printFor
104
+ };
@@ -1,4 +1,11 @@
1
- const { concat, group, indent, join, line, softline } = require("../prettier");
1
+ const {
2
+ concat,
3
+ group,
4
+ indent,
5
+ join,
6
+ line,
7
+ softline
8
+ } = require("../../prettier");
2
9
 
3
10
  function printMAssign(path, opts, print) {
4
11
  let right = path.call(print, "body", 1);
@@ -1,5 +1,4 @@
1
- const { concat, group, hardline, indent } = require("../prettier");
2
- const { first } = require("../utils");
1
+ const { concat, group, hardline, indent, line } = require("../../prettier");
3
2
 
4
3
  function printMethod(offset) {
5
4
  return function printMethodWithOffset(path, opts, print) {
@@ -16,8 +15,7 @@ function printMethod(offset) {
16
15
  }
17
16
 
18
17
  // In case there are no parens but there are arguments
19
- const parens =
20
- params.type === "params" && params.body.some((paramType) => paramType);
18
+ const parens = params.type === "params" && params.body.some((type) => type);
21
19
 
22
20
  declaration.push(
23
21
  path.call(print, "body", offset),
@@ -48,8 +46,38 @@ function printMethod(offset) {
48
46
  };
49
47
  }
50
48
 
49
+ function printSingleLineMethod(path, opts, print) {
50
+ let paramsNode = path.getValue().body[1];
51
+ let paramsDoc = "";
52
+
53
+ if (paramsNode) {
54
+ if (paramsNode.body[0].type === "params") {
55
+ paramsNode = paramsNode.body[0];
56
+ }
57
+
58
+ if (paramsNode.type === "params" && paramsNode.body.some((type) => type)) {
59
+ paramsDoc = path.call(print, "body", 1);
60
+ }
61
+ }
62
+
63
+ return group(
64
+ concat([
65
+ "def ",
66
+ path.call(print, "body", 0),
67
+ paramsDoc,
68
+ " =",
69
+ indent(group(concat([line, path.call(print, "body", 2)])))
70
+ ])
71
+ );
72
+ }
73
+
74
+ function printAccessControl(path, opts, print) {
75
+ return path.call(print, "body", 0);
76
+ }
77
+
51
78
  module.exports = {
52
- access_ctrl: first,
79
+ access_ctrl: printAccessControl,
53
80
  def: printMethod(0),
54
- defs: printMethod(2)
81
+ defs: printMethod(2),
82
+ defsl: printSingleLineMethod
55
83
  };
@@ -1,5 +1,5 @@
1
- const { concat, group, indent, line, softline } = require("../prettier");
2
- const { noIndent } = require("../utils");
1
+ const { concat, group, indent, line, softline } = require("../../prettier");
2
+ const { noIndent } = require("../../utils");
3
3
 
4
4
  function printBinary(path, opts, print) {
5
5
  const [_leftNode, operator, rightNode] = path.getValue().body;
@@ -1,5 +1,12 @@
1
- const { concat, group, join, indent, line, softline } = require("../prettier");
2
- const { literal } = require("../utils");
1
+ const {
2
+ concat,
3
+ group,
4
+ join,
5
+ indent,
6
+ line,
7
+ softline
8
+ } = require("../../prettier");
9
+ const { literal } = require("../../utils");
3
10
 
4
11
  function printRestParam(symbol) {
5
12
  return function printRestParamWithSymbol(path, opts, print) {
@@ -1,4 +1,13 @@
1
- const { concat, group, hardline, indent, join, line } = require("../prettier");
1
+ const {
2
+ concat,
3
+ group,
4
+ hardline,
5
+ indent,
6
+ join,
7
+ line
8
+ } = require("../../prettier");
9
+
10
+ const patterns = ["aryptn", "binary", "fndptn", "hshptn", "rassign"];
2
11
 
3
12
  function printPatternArg(path, opts, print) {
4
13
  // Pinning is a really special syntax in pattern matching that's not really
@@ -34,10 +43,7 @@ function printAryPtn(path, opts, print) {
34
43
 
35
44
  args = group(join(concat([",", line]), args));
36
45
 
37
- if (
38
- constant ||
39
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
40
- ) {
46
+ if (constant || patterns.includes(path.getParentNode().type)) {
41
47
  args = concat(["[", args, "]"]);
42
48
  }
43
49
 
@@ -48,6 +54,22 @@ function printAryPtn(path, opts, print) {
48
54
  return args;
49
55
  }
50
56
 
57
+ function printFndPtn(path, opts, print) {
58
+ const [constant] = path.getValue().body;
59
+
60
+ let args = [concat(["*", path.call(print, "body", 1)])]
61
+ .concat(path.map(print, "body", 2))
62
+ .concat(concat(["*", path.call(print, "body", 3)]));
63
+
64
+ args = concat(["[", group(join(concat([",", line]), args)), "]"]);
65
+
66
+ if (constant) {
67
+ return concat([path.call(print, "body", 0), args]);
68
+ }
69
+
70
+ return args;
71
+ }
72
+
51
73
  function printHshPtn(path, opts, print) {
52
74
  const [constant, keyValuePairs, keyValueRest] = path.getValue().body;
53
75
  let args = [];
@@ -80,10 +102,8 @@ function printHshPtn(path, opts, print) {
80
102
 
81
103
  if (constant) {
82
104
  args = concat(["[", args, "]"]);
83
- } else if (
84
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
85
- ) {
86
- args = concat(["{", args, "}"]);
105
+ } else if (patterns.includes(path.getParentNode().type)) {
106
+ args = concat(["{ ", args, " }"]);
87
107
  }
88
108
 
89
109
  if (constant) {
@@ -111,8 +131,23 @@ function printIn(path, opts, print) {
111
131
  return group(concat(parts));
112
132
  }
113
133
 
134
+ function printRAssign(path, opts, print) {
135
+ const { keyword } = path.getValue();
136
+ const [leftDoc, rightDoc] = path.map(print, "body");
137
+
138
+ return group(
139
+ concat([
140
+ leftDoc,
141
+ keyword ? " in" : " =>",
142
+ group(indent(concat([line, rightDoc])))
143
+ ])
144
+ );
145
+ }
146
+
114
147
  module.exports = {
115
148
  aryptn: printAryPtn,
149
+ fndptn: printFndPtn,
116
150
  hshptn: printHshPtn,
117
- in: printIn
151
+ in: printIn,
152
+ rassign: printRAssign
118
153
  };
@@ -0,0 +1,56 @@
1
+ const { concat } = require("../../prettier");
2
+ const { hasAncestor } = require("../../utils");
3
+
4
+ function hasContent(node, pattern) {
5
+ return node.body.some(
6
+ (child) => child.type === "@tstring_content" && pattern.test(child.body)
7
+ );
8
+ }
9
+
10
+ // If the first part of this regex is plain string content, we have a space
11
+ // or an =, and we're contained within a command or command_call node, then we
12
+ // want to use braces because otherwise we could end up with an ambiguous
13
+ // operator, e.g. foo / bar/ or foo /=bar/
14
+ function forwardSlashIsAmbiguous(path) {
15
+ const node = path.getValue();
16
+ const firstChildNode = node.body[0];
17
+
18
+ return (
19
+ firstChildNode &&
20
+ firstChildNode.type === "@tstring_content" &&
21
+ [" ", "="].includes(firstChildNode.body[0]) &&
22
+ hasAncestor(path, ["command", "command_call"])
23
+ );
24
+ }
25
+
26
+ // This function is responsible for printing out regexp_literal nodes. They can
27
+ // either use the special %r literal syntax or they can use forward slashes. At
28
+ // the end of either of those they can have modifiers like m or x that have
29
+ // special meaning for the regex engine.
30
+ //
31
+ // We favor the use of forward slashes unless the regex contains a forward slash
32
+ // itself. In that case we switch over to using %r with braces.
33
+ function printRegexpLiteral(path, opts, print) {
34
+ const node = path.getValue();
35
+ const docs = path.map(print, "body");
36
+
37
+ // We should use braces if using a forward slash would be ambiguous in the
38
+ // current context or if there's a forward slash in the content of the regexp.
39
+ const useBraces = forwardSlashIsAmbiguous(path) || hasContent(node, /\//);
40
+
41
+ // If we should be using braces but we have braces in the body of the regexp,
42
+ // then we're just going to resort to using whatever the original content was.
43
+ if (useBraces && hasContent(node, /[{}]/)) {
44
+ return concat([node.beging].concat(docs).concat(node.ending));
45
+ }
46
+
47
+ return concat(
48
+ [useBraces ? "%r{" : "/"]
49
+ .concat(docs)
50
+ .concat(useBraces ? "}" : "/", node.ending.slice(1))
51
+ );
52
+ }
53
+
54
+ module.exports = {
55
+ regexp_literal: printRegexpLiteral
56
+ };
@@ -6,8 +6,8 @@ const {
6
6
  indent,
7
7
  join,
8
8
  line
9
- } = require("../prettier");
10
- const { literal } = require("../utils");
9
+ } = require("../../prettier");
10
+ const { literal } = require("../../utils");
11
11
 
12
12
  function printBegin(path, opts, print) {
13
13
  return concat([
@@ -0,0 +1,98 @@
1
+ const {
2
+ concat,
3
+ group,
4
+ ifBreak,
5
+ indent,
6
+ line,
7
+ join,
8
+ softline
9
+ } = require("../../prettier");
10
+ const { literal } = require("../../utils");
11
+
12
+ // You can't skip the parentheses if you have comments or certain operators with
13
+ // lower precedence than the return keyword.
14
+ const canSkipParens = (args) => {
15
+ const stmts = args.body[0].body[0];
16
+
17
+ // return(
18
+ // # a
19
+ // b
20
+ // )
21
+ if (stmts.comments) {
22
+ return false;
23
+ }
24
+
25
+ const stmt = stmts.body[0];
26
+
27
+ // return (a or b)
28
+ if (stmt.type === "binary" && ["and", "or"].includes(stmt.body[1])) {
29
+ return false;
30
+ }
31
+
32
+ // return (not a)
33
+ if (stmt.type === "unary" && stmt.oper === "not") {
34
+ return false;
35
+ }
36
+
37
+ return true;
38
+ };
39
+
40
+ const printReturn = (path, opts, print) => {
41
+ let args = path.getValue().body[0].body[0];
42
+ let steps = ["body", 0, "body", 0];
43
+
44
+ if (!args) {
45
+ return "return";
46
+ }
47
+
48
+ if (args.body.length === 1) {
49
+ // If the body of the return contains parens, then just skip directly to the
50
+ // content of the parens so that we can skip printing parens if we don't
51
+ // want them.
52
+ if (args.body[0] && args.body[0].type === "paren" && canSkipParens(args)) {
53
+ args = args.body[0].body[0];
54
+ steps = steps.concat("body", 0, "body", 0);
55
+ }
56
+
57
+ // If we're returning an array literal that isn't a special array, single
58
+ // element array, or an empty array, then we want to grab the arguments so
59
+ // that we can print them out as if they were normal return arguments.
60
+ if (
61
+ args.body[0] &&
62
+ args.body[0].type === "array" &&
63
+ args.body[0].body[0] &&
64
+ args.body[0].body[0].body.length > 1 &&
65
+ ["args", "args_add_star"].includes(args.body[0].body[0].type)
66
+ ) {
67
+ steps = steps.concat("body", 0, "body", 0);
68
+ }
69
+ }
70
+
71
+ // Now that we've established which actual node is the arguments to return,
72
+ // we grab it out of the path by diving down the steps that we've set up.
73
+ const parts = path.call.apply(path, [print].concat(steps));
74
+
75
+ // If we got the value straight out of the parens, then `parts` would only
76
+ // be a singular doc as opposed to an array.
77
+ const value = Array.isArray(parts) ? join(concat([",", line]), parts) : parts;
78
+
79
+ // We only get here if we have comments somewhere that would prevent us from
80
+ // skipping the parentheses.
81
+ if (args.body.length === 1 && args.body[0].type === "paren") {
82
+ return concat(["return", value]);
83
+ }
84
+
85
+ return group(
86
+ concat([
87
+ "return",
88
+ ifBreak(parts.length > 1 ? " [" : "(", " "),
89
+ indent(concat([softline, value])),
90
+ concat([softline, ifBreak(parts.length > 1 ? "]" : ")", "")])
91
+ ])
92
+ );
93
+ };
94
+
95
+ module.exports = {
96
+ return: printReturn,
97
+ return0: literal("return")
98
+ };