prettier 0.18.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
5
  "main": "src/ruby.js",
6
6
  "scripts": {
@@ -22,17 +22,45 @@
22
22
  "prettier": ">=1.10"
23
23
  },
24
24
  "devDependencies": {
25
- "all-contributors-cli": "^6.12.0",
26
- "eslint": "^6.8.0",
27
- "eslint-config-airbnb-base": "^14.0.0",
28
- "eslint-config-prettier": "^6.9.0",
29
- "eslint-plugin-import": "^2.20.0",
30
- "jest": "^25.1.0"
25
+ "all-contributors-cli": "^6.14.1",
26
+ "eslint": "^7.1.0",
27
+ "eslint-config-prettier": "^6.10.1",
28
+ "husky": "^4.2.5",
29
+ "jest": "^26.0.0",
30
+ "pretty-quick": "^3.0.0"
31
+ },
32
+ "eslintConfig": {
33
+ "extends": [
34
+ "eslint:recommended",
35
+ "prettier"
36
+ ],
37
+ "env": {
38
+ "es6": true,
39
+ "jest": true,
40
+ "node": true
41
+ },
42
+ "rules": {
43
+ "no-unused-vars": [
44
+ "error",
45
+ {
46
+ "argsIgnorePattern": "^_",
47
+ "varsIgnorePattern": "^_"
48
+ }
49
+ ]
50
+ }
31
51
  },
32
52
  "jest": {
33
53
  "setupFilesAfterEnv": [
34
54
  "./test/js/setupTests.js"
35
55
  ],
36
56
  "testRegex": ".test.js$"
57
+ },
58
+ "husky": {
59
+ "hooks": {
60
+ "pre-commit": "pretty-quick --staged"
61
+ }
62
+ },
63
+ "prettier": {
64
+ "trailingComma": "none"
37
65
  }
38
66
  }
@@ -0,0 +1,71 @@
1
+ const {
2
+ concat,
3
+ indent,
4
+ literalline,
5
+ mapDoc,
6
+ markAsRoot,
7
+ stripTrailingHardline
8
+ } = require("./prettier");
9
+
10
+ const parsers = {
11
+ css: "css",
12
+ javascript: "babel",
13
+ js: "babel",
14
+ less: "less",
15
+ markdown: "markdown",
16
+ ruby: "ruby",
17
+ scss: "scss"
18
+ };
19
+
20
+ const replaceNewlines = (doc) =>
21
+ mapDoc(doc, (currentDoc) =>
22
+ typeof currentDoc === "string" && currentDoc.includes("\n")
23
+ ? concat(
24
+ currentDoc
25
+ .split(/(\n)/g)
26
+ .map((v, i) => (i % 2 === 0 ? v : literalline))
27
+ )
28
+ : currentDoc
29
+ );
30
+
31
+ const embed = (path, _print, textToDoc, _opts) => {
32
+ const node = path.getValue();
33
+
34
+ // Currently we only support embedded formatting on heredoc nodes
35
+ if (node.type !== "heredoc") {
36
+ return null;
37
+ }
38
+
39
+ // First, ensure that we don't have any interpolation
40
+ const { beging, body, ending } = node;
41
+ if (body.some((part) => part.type !== "@tstring_content")) {
42
+ return null;
43
+ }
44
+
45
+ // Next, find the parser associated with this heredoc (if there is one). For
46
+ // example, if you use <<~CSS, we'd hook it up to the css parser.
47
+ const parser = parsers[beging.slice(3).toLowerCase()];
48
+ if (!parser) {
49
+ return null;
50
+ }
51
+
52
+ // Get the content as if it were a source string, and then pass that content
53
+ // into the embedded parser. Get back the doc node.
54
+ const content = body.map((part) => part.body).join("");
55
+ const formatted = concat([
56
+ literalline,
57
+ replaceNewlines(stripTrailingHardline(textToDoc(content, { parser })))
58
+ ]);
59
+
60
+ // If we're using a squiggly heredoc, then we can properly handle indentation
61
+ // ourselves.
62
+ if (beging[2] === "~") {
63
+ return concat([beging, indent(markAsRoot(formatted)), literalline, ending]);
64
+ }
65
+
66
+ // Otherwise, we need to just assume it's formatted correctly and return the
67
+ // content as it is.
68
+ return markAsRoot(concat([beging, formatted, literalline, ending]));
69
+ };
70
+
71
+ module.exports = embed;
@@ -3,13 +3,13 @@ const parse = require("./haml/parse");
3
3
  const print = require("./haml/print");
4
4
 
5
5
  const pragmaPattern = /^\s*-#\s*@(prettier|format)/;
6
- const hasPragma = text => pragmaPattern.test(text);
6
+ const hasPragma = (text) => pragmaPattern.test(text);
7
7
 
8
8
  // These functions are just placeholders until we can actually perform this
9
9
  // properly. The functions are necessary otherwise the format with cursor
10
10
  // functions break.
11
- const locStart = _node => 0;
12
- const locEnd = _node => 0;
11
+ const locStart = (_node) => 0;
12
+ const locEnd = (_node) => 0;
13
13
 
14
14
  module.exports = {
15
15
  embed,
@@ -17,8 +17,8 @@ const parsers = {
17
17
  scss: "scss"
18
18
  };
19
19
 
20
- const replaceNewlines = doc =>
21
- mapDoc(doc, currentDoc =>
20
+ const replaceNewlines = (doc) =>
21
+ mapDoc(doc, (currentDoc) =>
22
22
  typeof currentDoc === "string" && currentDoc.includes("\n")
23
23
  ? concat(
24
24
  currentDoc
@@ -4,6 +4,7 @@ const {
4
4
  fill,
5
5
  group,
6
6
  hardline,
7
+ ifBreak,
7
8
  indent,
8
9
  join,
9
10
  line,
@@ -14,10 +15,10 @@ const getDynamicAttributes = (header, attributes) => {
14
15
  const pairs = attributes
15
16
  .slice(1, -2)
16
17
  .split(",")
17
- .map(pair => pair.slice(1).split('" => '));
18
+ .map((pair) => pair.slice(1).split('" => '));
18
19
  const parts = [concat([pairs[0][0], "=", pairs[0][1]])];
19
20
 
20
- pairs.slice(1).forEach(pair => {
21
+ pairs.slice(1).forEach((pair) => {
21
22
  parts.push(line, concat([pair[0], "=", pair[1]]));
22
23
  });
23
24
 
@@ -49,13 +50,13 @@ const getHashLabel = (key, value, opts) => {
49
50
 
50
51
  const getStaticAttributes = (header, attributes, opts) => {
51
52
  const keys = Object.keys(attributes).filter(
52
- name => !["class", "id"].includes(name)
53
+ (name) => !["class", "id"].includes(name)
53
54
  );
54
55
 
55
56
  const getKeyValuePair = opts.preferHashLabels ? getHashLabel : getHashRocket;
56
57
  const parts = [getKeyValuePair(keys[0], attributes[keys[0]], opts)];
57
58
 
58
- keys.slice(1).forEach(key => {
59
+ keys.slice(1).forEach((key) => {
59
60
  parts.push(",", line, getKeyValuePair(key, attributes[key], opts));
60
61
  });
61
62
 
@@ -84,11 +85,16 @@ const getHeader = (value, opts) => {
84
85
  );
85
86
  }
86
87
 
87
- if (Object.keys(attributes).some(name => name !== "class" && name !== "id")) {
88
+ if (
89
+ Object.keys(attributes).some((name) => name !== "class" && name !== "id")
90
+ ) {
88
91
  parts.push(getStaticAttributes(parts.join("").length, attributes, opts));
89
92
  }
90
93
 
91
94
  if (value.dynamic_attributes.old) {
95
+ if (parts.length === 0) {
96
+ parts.push("%div");
97
+ }
92
98
  parts.push(value.dynamic_attributes.old);
93
99
  }
94
100
 
@@ -112,12 +118,12 @@ const getHeader = (value, opts) => {
112
118
  }
113
119
 
114
120
  if (value.value) {
115
- const prefix = value.parse ? "=" : "";
121
+ const prefix = value.parse ? "= " : ifBreak("", " ");
116
122
 
117
123
  return group(
118
124
  concat([
119
125
  group(concat(parts)),
120
- indent(concat([softline, `${prefix} ${value.value}`]))
126
+ indent(concat([softline, prefix, value.value]))
121
127
  ])
122
128
  );
123
129
  }
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'json'
4
-
5
3
  require 'bundler/setup' if ENV['CI']
6
4
  require 'haml'
7
5
 
@@ -48,18 +46,17 @@ class Haml::Parser::ParseNode
48
46
  raise ArgumentError, "Unsupported type: #{type}"
49
47
  end
50
48
  end
51
-
52
- def self.to_json(template)
53
- parser = Haml::Parser.new({})
54
- JSON.fast_generate(parser.call(template).as_json)
55
- end
56
49
  end
57
50
 
58
51
  # If this is the main file we're executing, then most likely this is being
59
52
  # executed from the haml.js spawn. In that case, read the ruby source from
60
53
  # stdin and report back the AST over stdout.
61
-
62
54
  if $0 == __FILE__
55
+ # Don't explicitly require JSON if there is already as JSON loaded, as this
56
+ # can lead to all kinds of trouble where one version of it was already
57
+ # "activated" by rubygems.
58
+ require 'json' unless defined?(JSON)
59
+
63
60
  parser = Haml::Parser.new({})
64
61
  template = $stdin.read
65
62
 
@@ -1,7 +1,7 @@
1
1
  const { concat, join } = require("../prettier");
2
2
 
3
- const usingSymbols = path => {
4
- const [left, right] = path.getValue().body.map(node => node.body[0].type);
3
+ const usingSymbols = (path) => {
4
+ const [left, right] = path.getValue().body.map((node) => node.body[0].type);
5
5
  return left === "symbol" && right === "symbol";
6
6
  };
7
7
 
@@ -62,7 +62,7 @@ module.exports = {
62
62
  // method_add_block node, and if they are that that node has a block
63
63
  // associated with it. If it does, we're going to attempt to transform it
64
64
  // into the to_proc shorthand and add it to the list of arguments.
65
- [1, 2, 3].find(parent => {
65
+ [1, 2, 3].find((parent) => {
66
66
  const parentNode = path.getParentNode(parent);
67
67
  blockNode =
68
68
  parentNode &&
@@ -72,7 +72,7 @@ module.exports = {
72
72
  return blockNode;
73
73
  });
74
74
 
75
- const proc = blockNode && toProc(blockNode);
75
+ const proc = blockNode && toProc(path, opts, blockNode);
76
76
 
77
77
  // If we have a successful to_proc transformation, but we're part of an aref
78
78
  // node, that means it's something to the effect of
@@ -9,19 +9,23 @@ const {
9
9
  softline
10
10
  } = require("../prettier");
11
11
 
12
- const isStringArray = args =>
12
+ const preserveArraySubstrings = [" ", "\\"];
13
+
14
+ const isStringArray = (args) =>
13
15
  args.body.every(
14
- arg =>
16
+ (arg) =>
15
17
  arg.type === "string_literal" &&
16
18
  arg.body[0].body.length === 1 &&
17
19
  arg.body[0].body[0].type === "@tstring_content" &&
18
- !arg.body[0].body[0].body.includes(" ")
20
+ !preserveArraySubstrings.some((str) =>
21
+ arg.body[0].body[0].body.includes(str)
22
+ )
19
23
  );
20
24
 
21
- const isSymbolArray = args =>
22
- args.body.every(arg => arg.type === "symbol_literal");
25
+ const isSymbolArray = (args) =>
26
+ args.body.every((arg) => arg.type === "symbol_literal");
23
27
 
24
- const makeArray = start => (path, opts, print) =>
28
+ const makeArray = (start) => (path, opts, print) =>
25
29
  [start].concat(path.map(print, "body"));
26
30
 
27
31
  const getSpecialArrayParts = (path, print, args) =>
@@ -44,7 +48,7 @@ const printAref = (path, opts, print) =>
44
48
  ])
45
49
  );
46
50
 
47
- const printSpecialArray = parts =>
51
+ const printSpecialArray = (parts) =>
48
52
  group(
49
53
  concat([
50
54
  parts[0],
@@ -10,7 +10,7 @@ const {
10
10
  } = require("../prettier");
11
11
  const { empty, hasAncestor } = require("../utils");
12
12
 
13
- const printBlock = (path, opts, print) => {
13
+ const printBlock = (braces) => (path, opts, print) => {
14
14
  const [variables, statements] = path.getValue().body;
15
15
  const stmts =
16
16
  statements.type === "stmts" ? statements.body : statements.body[0].body;
@@ -25,7 +25,7 @@ const printBlock = (path, opts, print) => {
25
25
  // as opposed to the current node (because of the difference in operator
26
26
  // precedence). Instead, we still use a multi-line format but switch to using
27
27
  // braces instead.
28
- const useBraces = hasAncestor(path, ["command", "command_call"]);
28
+ const useBraces = braces && hasAncestor(path, ["command", "command_call"]);
29
29
 
30
30
  const doBlock = concat([
31
31
  useBraces ? " {" : " do",
@@ -38,7 +38,7 @@ const printBlock = (path, opts, print) => {
38
38
  // comment.
39
39
  if (
40
40
  stmts.length > 1 &&
41
- stmts.filter(stmt => stmt.type !== "@comment").length === 1
41
+ stmts.filter((stmt) => stmt.type !== "@comment").length === 1
42
42
  ) {
43
43
  return concat([breakParent, doBlock]);
44
44
  }
@@ -74,7 +74,7 @@ module.exports = {
74
74
  parts.push("| ");
75
75
  return concat(parts);
76
76
  },
77
- brace_block: printBlock,
78
- do_block: printBlock,
77
+ brace_block: printBlock(true),
78
+ do_block: printBlock(false),
79
79
  excessed_comma: empty
80
80
  };
@@ -1,29 +1,64 @@
1
- const { concat, group, indent, softline } = require("../prettier");
1
+ const { concat, group, indent, literalline, softline } = require("../prettier");
2
2
  const toProc = require("../toProc");
3
3
  const { concatBody, first, makeCall } = require("../utils");
4
4
 
5
5
  const noIndent = ["array", "hash", "if", "method_add_block", "xstring_literal"];
6
6
 
7
+ const getHeredoc = (path, print, node) => {
8
+ if (node.type === "heredoc") {
9
+ const { beging, ending } = node;
10
+ return { beging, ending, content: ["body", 0, "body"] };
11
+ }
12
+
13
+ if (node.type === "string_literal" && node.body[0].type === "heredoc") {
14
+ const { beging, ending } = node.body[0];
15
+ return { beging, ending, content: ["body", 0, "body", 0, "body"] };
16
+ }
17
+
18
+ return null;
19
+ };
20
+
7
21
  module.exports = {
8
22
  call: (path, opts, print) => {
9
- const receiver = path.call(print, "body", 0);
10
- const operator = makeCall(path, opts, print);
11
- let name = path.getValue().body[2];
23
+ const [receiverNode, _operatorNode, messageNode] = path.getValue().body;
24
+
25
+ const printedReceiver = path.call(print, "body", 0);
26
+ const printedOperator = makeCall(path, opts, print);
12
27
 
13
28
  // You can call lambdas with a special syntax that looks like func.(*args).
14
29
  // In this case, "call" is returned for the 3rd child node.
15
- if (name !== "call") {
16
- name = path.call(print, "body", 2);
30
+ const printedMessage =
31
+ messageNode === "call" ? messageNode : path.call(print, "body", 2);
32
+
33
+ // If we have a heredoc as a receiver, then we need to move the operator and
34
+ // the message up to start of the heredoc declaration, as in:
35
+ //
36
+ // <<~TEXT.strip
37
+ // content
38
+ // TEXT
39
+ const heredoc = getHeredoc(path, print, receiverNode);
40
+ if (heredoc) {
41
+ return concat([
42
+ heredoc.beging,
43
+ printedOperator,
44
+ printedMessage,
45
+ literalline,
46
+ concat(path.map.apply(path, [print].concat(heredoc.content))),
47
+ heredoc.ending
48
+ ]);
17
49
  }
18
50
 
19
51
  // For certain left sides of the call nodes, we want to attach directly to
20
52
  // the } or end.
21
- if (noIndent.includes(path.getValue().body[0].type)) {
22
- return concat([receiver, operator, name]);
53
+ if (noIndent.includes(receiverNode.type)) {
54
+ return concat([printedReceiver, printedOperator, printedMessage]);
23
55
  }
24
56
 
25
57
  return group(
26
- concat([receiver, group(indent(concat([softline, operator, name])))])
58
+ concat([
59
+ printedReceiver,
60
+ group(indent(concat([softline, printedOperator, printedMessage])))
61
+ ])
27
62
  );
28
63
  },
29
64
  fcall: concatBody,
@@ -41,7 +76,7 @@ module.exports = {
41
76
  },
42
77
  method_add_block: (path, opts, print) => {
43
78
  const [method, block] = path.getValue().body;
44
- const proc = toProc(block);
79
+ const proc = toProc(path, opts, block);
45
80
 
46
81
  if (proc && method.type === "call") {
47
82
  return group(