prettier 0.17.0 → 0.19.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "0.17.0",
3
+ "version": "0.19.1",
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.1.2",
26
- "eslint": "^6.0.1",
27
- "eslint-config-airbnb-base": "^14.0.0",
28
- "eslint-config-prettier": "^6.0.0",
29
- "eslint-plugin-import": "^2.16.0",
30
- "jest": "^24.0.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
  }
@@ -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
@@ -1,5 +1,21 @@
1
1
  const { concat, group, hardline, indent, join } = require("../../prettier");
2
2
 
3
+ const findKeywordIndices = (children, keywords) => {
4
+ const indices = [];
5
+
6
+ children.forEach((child, index) => {
7
+ if (child.type !== "silent_script") {
8
+ return;
9
+ }
10
+
11
+ if (keywords.includes(child.value.keyword)) {
12
+ indices.push(index);
13
+ }
14
+ });
15
+
16
+ return indices;
17
+ };
18
+
3
19
  // http://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
4
20
  const silentScript = (path, opts, print) => {
5
21
  const { children, value } = path.getValue();
@@ -9,13 +25,26 @@ const silentScript = (path, opts, print) => {
9
25
  const scripts = path.map(print, "children");
10
26
 
11
27
  if (value.keyword === "case") {
28
+ const keywordIndices = findKeywordIndices(children, ["when", "else"]);
29
+
30
+ parts.push(
31
+ concat(
32
+ scripts.map((script, index) => {
33
+ const concated = concat([hardline, script]);
34
+
35
+ return keywordIndices.includes(index) ? concated : indent(concated);
36
+ })
37
+ )
38
+ );
39
+ } else if (["if", "unless"].includes(value.keyword)) {
40
+ const keywordIndices = findKeywordIndices(children, ["elsif", "else"]);
41
+
12
42
  parts.push(
13
- join(
14
- "",
43
+ concat(
15
44
  scripts.map((script, index) => {
16
45
  const concated = concat([hardline, script]);
17
46
 
18
- return index % 2 === 0 ? concated : indent(concated);
47
+ return keywordIndices.includes(index) ? concated : indent(concated);
19
48
  })
20
49
  )
21
50
  );
@@ -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
 
@@ -71,7 +72,7 @@ const getHeader = (value, opts) => {
71
72
  }
72
73
 
73
74
  if (attributes.class) {
74
- parts.push(`.${attributes.class.replace(" ", ".")}`);
75
+ parts.push(`.${attributes.class.replace(/ /g, ".")}`);
75
76
  }
76
77
 
77
78
  if (attributes.id) {
@@ -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,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'json'
3
+ require 'bundler/setup' if ENV['CI']
4
4
  require 'haml'
5
5
 
6
6
  class Haml::Parser::ParseNode
@@ -46,18 +46,17 @@ class Haml::Parser::ParseNode
46
46
  raise ArgumentError, "Unsupported type: #{type}"
47
47
  end
48
48
  end
49
-
50
- def self.to_json(template)
51
- parser = Haml::Parser.new({})
52
- JSON.fast_generate(parser.call(template).as_json)
53
- end
54
49
  end
55
50
 
56
51
  # If this is the main file we're executing, then most likely this is being
57
52
  # executed from the haml.js spawn. In that case, read the ruby source from
58
53
  # stdin and report back the AST over stdout.
59
-
60
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
+
61
60
  parser = Haml::Parser.new({})
62
61
  template = $stdin.read
63
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
 
@@ -17,6 +17,13 @@ module.exports = {
17
17
  return "";
18
18
  }
19
19
 
20
+ // Here we can skip the entire rest of the method by just checking if it's
21
+ // an args_forward node, as we're guaranteed that there are no other arg
22
+ // nodes.
23
+ if (path.getValue().body[0].type === "args_forward") {
24
+ return "(...)";
25
+ }
26
+
20
27
  const { addTrailingCommas } = opts;
21
28
  const { args, heredocs } = makeArgs(path, opts, print, 0);
22
29
 
@@ -55,7 +62,7 @@ module.exports = {
55
62
  // method_add_block node, and if they are that that node has a block
56
63
  // associated with it. If it does, we're going to attempt to transform it
57
64
  // into the to_proc shorthand and add it to the list of arguments.
58
- [1, 2, 3].find(parent => {
65
+ [1, 2, 3].find((parent) => {
59
66
  const parentNode = path.getParentNode(parent);
60
67
  blockNode =
61
68
  parentNode &&
@@ -65,7 +72,7 @@ module.exports = {
65
72
  return blockNode;
66
73
  });
67
74
 
68
- const proc = blockNode && toProc(blockNode);
75
+ const proc = blockNode && toProc(path, opts, blockNode);
69
76
 
70
77
  // If we have a successful to_proc transformation, but we're part of an aref
71
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],
@@ -8,9 +8,9 @@ const {
8
8
  removeLines,
9
9
  softline
10
10
  } = require("../prettier");
11
- const { empty, first, hasAncestor } = require("../utils");
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,8 +74,7 @@ module.exports = {
74
74
  parts.push("| ");
75
75
  return concat(parts);
76
76
  },
77
- brace_block: printBlock,
78
- do_block: printBlock,
79
- excessed_comma: empty,
80
- number_arg: first
77
+ brace_block: printBlock(true),
78
+ do_block: printBlock(false),
79
+ excessed_comma: empty
81
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, 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(