prettier 0.18.0 → 0.20.0

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.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(