prettier 1.0.0.pre.rc2 → 1.2.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,21 +1,25 @@
1
1
  const { concat } = require("../prettier");
2
+ const { hasAncestor } = require("../utils");
2
3
 
3
- function isStringContent(node) {
4
- return node.type === "@tstring_content";
4
+ function hasContent(node, pattern) {
5
+ return node.body.some(
6
+ (child) => child.type === "@tstring_content" && pattern.test(child.body)
7
+ );
5
8
  }
6
9
 
7
- function shouldUseBraces(node) {
8
- const first = node.body[0];
9
-
10
- // If the first part of this regex is plain string content and we have a
11
- // space or an =, then we want to use braces because otherwise we could end up
12
- // with an ambiguous operator, e.g. foo / bar/ or foo /=bar/
13
- if (first && isStringContent(first) && [" ", "="].includes(first.body[0])) {
14
- return true;
15
- }
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];
16
17
 
17
- return node.body.some(
18
- (child) => isStringContent(child) && child.body.includes("/")
18
+ return (
19
+ firstChildNode &&
20
+ firstChildNode.type === "@tstring_content" &&
21
+ [" ", "="].includes(firstChildNode.body[0]) &&
22
+ hasAncestor(path, ["command", "command_call"])
19
23
  );
20
24
  }
21
25
 
@@ -28,13 +32,23 @@ function shouldUseBraces(node) {
28
32
  // itself. In that case we switch over to using %r with braces.
29
33
  function printRegexpLiteral(path, opts, print) {
30
34
  const node = path.getValue();
31
- const useBraces = shouldUseBraces(node);
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, /\//);
32
40
 
33
- const parts = [useBraces ? "%r{" : "/"]
34
- .concat(path.map(print, "body"))
35
- .concat([useBraces ? "}" : "/", node.ending.slice(1)]);
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
+ }
36
46
 
37
- return concat(parts);
47
+ return concat(
48
+ [useBraces ? "%r{" : "/"]
49
+ .concat(docs)
50
+ .concat(useBraces ? "}" : "/", node.ending.slice(1))
51
+ );
38
52
  }
39
53
 
40
54
  module.exports = {
@@ -98,8 +98,8 @@ module.exports = {
98
98
  stmts[0].comments
99
99
  ) {
100
100
  const comments = path.map(
101
- (commentPath, index) => {
102
- stmts[0].comments[index].printed = true;
101
+ (commentPath) => {
102
+ commentPath.getValue().printed = true;
103
103
  return opts.printer.printComment(commentPath);
104
104
  },
105
105
  "body",
@@ -32,7 +32,7 @@ function isSingleQuotable(node) {
32
32
  const quotePattern = new RegExp("\\\\([\\s\\S])|(['\"])", "g");
33
33
 
34
34
  function normalizeQuotes(content, enclosingQuote, originalQuote) {
35
- const replaceOther = ["'", '"'].includes(originalQuote);
35
+ const replaceOther = originalQuote === '"';
36
36
  const otherQuote = enclosingQuote === '"' ? "'" : '"';
37
37
 
38
38
  // Escape and unescape single and double quotes as needed to be able to
@@ -3,18 +3,33 @@ const path = require("path");
3
3
 
4
4
  // In order to properly parse ruby code, we need to tell the ruby process to
5
5
  // parse using UTF-8. Unfortunately, the way that you accomplish this looks
6
- // differently depending on your platform. This object below represents all of
7
- // the possible values of process.platform per:
8
- // https://nodejs.org/api/process.html#process_process_platform
9
- const LANG = {
10
- aix: "C.UTF-8",
11
- darwin: "en_US.UTF-8",
12
- freebsd: "C.UTF-8",
13
- linux: "C.UTF-8",
14
- openbsd: "C.UTF-8",
15
- sunos: "C.UTF-8",
16
- win32: ".UTF-8"
17
- }[process.platform];
6
+ // differently depending on your platform.
7
+ const LANG = (() => {
8
+ const { env, platform } = process;
9
+ const envValue = env.LC_ALL || env.LC_CTYPE || env.LANG;
10
+
11
+ // If an env var is set for the locale that already includes UTF-8 in the
12
+ // name, then assume we can go with that.
13
+ if (envValue && envValue.includes("UTF-8")) {
14
+ return envValue;
15
+ }
16
+
17
+ // Otherwise, we're going to guess which encoding to use based on the system.
18
+ // This is probably not the best approach in the world, as you could be on
19
+ // linux and not have C.UTF-8, but in that case you're probably passing an env
20
+ // var for it. This object below represents all of the possible values of
21
+ // process.platform per:
22
+ // https://nodejs.org/api/process.html#process_process_platform
23
+ return {
24
+ aix: "C.UTF-8",
25
+ darwin: "en_US.UTF-8",
26
+ freebsd: "C.UTF-8",
27
+ linux: "C.UTF-8",
28
+ openbsd: "C.UTF-8",
29
+ sunos: "C.UTF-8",
30
+ win32: ".UTF-8"
31
+ }[platform];
32
+ })();
18
33
 
19
34
  // This function is responsible for taking an input string of text and returning
20
35
  // to prettier a JavaScript object that is the equivalent AST that represents
@@ -63,14 +63,14 @@ class Prettier::Parser < Ripper
63
63
  # would happen to be the innermost keyword). Then the outer one would only be
64
64
  # able to grab the first one. In this way all of the scanner events act as
65
65
  # their own stack.
66
- def find_scanner_event(type, body = :any)
66
+ def find_scanner_event(type, body = :any, consume: true)
67
67
  index =
68
68
  scanner_events.rindex do |scanner_event|
69
69
  scanner_event[:type] == type &&
70
70
  (body == :any || (scanner_event[:body] == body))
71
71
  end
72
72
 
73
- scanner_events.delete_at(index)
73
+ consume ? scanner_events.delete_at(index) : (index && scanner_events[index])
74
74
  end
75
75
 
76
76
  # Scanner events occur when the lexer hits a new token, like a keyword or an
@@ -314,7 +314,9 @@ class Prettier::Parser < Ripper
314
314
  arg.merge(type: :args, body: [arg])
315
315
  else
316
316
  args.merge!(
317
- body: args[:body] << arg, end: arg[:end], char_end: arg[:char_end]
317
+ body: args[:body] << arg,
318
+ end: arg[:end],
319
+ char_end: arg[:char_end]
318
320
  )
319
321
  end
320
322
  end
@@ -673,8 +675,15 @@ class Prettier::Parser < Ripper
673
675
  # It accepts as arguments the switch of the case and the consequent
674
676
  # clause.
675
677
  def on_case(switch, consequent)
676
- find_scanner_event(:@kw, 'case').merge!(
677
- type: :case,
678
+ beging =
679
+ if event = find_scanner_event(:@kw, 'case', consume: false)
680
+ scanner_events.delete(event).merge!(type: :case)
681
+ else
682
+ keyword = find_scanner_event(:@kw, 'in', consume: false)
683
+ switch.merge(type: :rassign, keyword: keyword)
684
+ end
685
+
686
+ beging.merge!(
678
687
  body: [switch, consequent],
679
688
  end: consequent[:end],
680
689
  char_end: consequent[:char_end]
@@ -812,18 +821,43 @@ class Prettier::Parser < Ripper
812
821
  # │ └> params
813
822
  # └> ident
814
823
  #
824
+ # You can also have single-line methods since Ruby 3.0+, which have slightly
825
+ # different syntax but still flow through this method. Those look like:
826
+ #
827
+ # def foo = bar
828
+ # | |
829
+ # | └> stmt
830
+ # └> ident
831
+ #
815
832
  def on_def(ident, params, bodystmt)
816
833
  # Make sure to delete this scanner event in case you're defining something
817
834
  # like def class which would lead to this being a kw and causing all kinds
818
835
  # of trouble
819
836
  scanner_events.delete(ident)
820
837
 
838
+ # Find the beginning of the method definition, which works for single-line
839
+ # and normal method definitions.
840
+ beging = find_scanner_event(:@kw, 'def')
841
+
842
+ # If we don't have a bodystmt node, then we have a single-line method
843
+ if bodystmt[:type] != :bodystmt
844
+ return(
845
+ {
846
+ type: :defsl,
847
+ body: [ident, params, bodystmt],
848
+ start: beging[:start],
849
+ char_start: beging[:char_start],
850
+ end: bodystmt[:end],
851
+ char_end: bodystmt[:char_end]
852
+ }
853
+ )
854
+ end
855
+
821
856
  if params[:type] == :params && !params[:body].any?
822
857
  location = ident[:char_end]
823
858
  params.merge!(char_start: location, char_end: location)
824
859
  end
825
860
 
826
- beging = find_scanner_event(:@kw, 'def')
827
861
  ending = find_scanner_event(:@kw, 'end')
828
862
 
829
863
  bodystmt.bind(
@@ -979,7 +1013,7 @@ class Prettier::Parser < Ripper
979
1013
  #
980
1014
  # which would be the same symbol as above.
981
1015
  def on_dyna_symbol(string)
982
- if scanner_events.any? { |event| event[:type] == :@symbeg }
1016
+ if find_scanner_event(:@symbeg, consume: false)
983
1017
  # A normal dynamic symbol
984
1018
  beging = find_scanner_event(:@symbeg)
985
1019
  ending = find_scanner_event(:@tstring_end)
@@ -1155,6 +1189,24 @@ class Prettier::Parser < Ripper
1155
1189
  }
1156
1190
  end
1157
1191
 
1192
+ # fndptn is a parser event that represents matching against a pattern where
1193
+ # you find a pattern in an array using the Ruby 3.0+ pattern matching syntax.
1194
+ def on_fndptn(const, presplat, args, postsplat)
1195
+ beging = const || find_scanner_event(:@lbracket)
1196
+ ending = find_scanner_event(:@rbracket)
1197
+
1198
+ pieces = [const, presplat, *args, postsplat].compact
1199
+
1200
+ {
1201
+ type: :fndptn,
1202
+ body: [const, presplat, args, postsplat],
1203
+ start: beging[:start],
1204
+ char_start: beging[:char_start],
1205
+ end: ending[:end],
1206
+ char_end: ending[:char_end]
1207
+ }
1208
+ end
1209
+
1158
1210
  # for is a parser event that represents using the somewhat esoteric for
1159
1211
  # loop. It accepts as arguments an ident which is the iterating variable,
1160
1212
  # an enumerable for that which is being enumerated, and a stmts event that
@@ -1186,7 +1238,8 @@ class Prettier::Parser < Ripper
1186
1238
  # Here we're going to expand out the location information for the assocs
1187
1239
  # node so that it can grab up any remaining comments inside the hash.
1188
1240
  assoclist_from_args.merge!(
1189
- char_start: beging[:char_end], char_end: ending[:char_start]
1241
+ char_start: beging[:char_end],
1242
+ char_end: ending[:char_start]
1190
1243
  )
1191
1244
  end
1192
1245
 
@@ -1299,8 +1352,12 @@ class Prettier::Parser < Ripper
1299
1352
  end
1300
1353
 
1301
1354
  # in is a parser event that represents using the in keyword within the
1302
- # Ruby 2.7+ pattern matching syntax.
1355
+ # Ruby 2.7+ pattern matching syntax. Alternatively in Ruby 3+ it is also used
1356
+ # to handle rightward assignment for pattern matching.
1303
1357
  def on_in(pattern, stmts, consequent)
1358
+ # Here we have a rightward assignment
1359
+ return pattern unless stmts
1360
+
1304
1361
  beging = find_scanner_event(:@kw, 'in')
1305
1362
  ending = consequent || find_scanner_event(:@kw, 'end')
1306
1363
 
@@ -1338,8 +1395,8 @@ class Prettier::Parser < Ripper
1338
1395
  def on_lambda(params, stmts)
1339
1396
  beging = find_scanner_event(:@tlambda)
1340
1397
 
1341
- if scanner_events.any? { |event| event[:type] == :@tlambeg }
1342
- opening = find_scanner_event(:@tlambeg)
1398
+ if event = find_scanner_event(:@tlambeg, consume: false)
1399
+ opening = scanner_events.delete(event)
1343
1400
  closing = find_scanner_event(:@rbrace)
1344
1401
  else
1345
1402
  opening = find_scanner_event(:@kw, 'do')
@@ -1448,7 +1505,9 @@ class Prettier::Parser < Ripper
1448
1505
  part.merge(type: :mlhs, body: [part])
1449
1506
  else
1450
1507
  mlhs.merge!(
1451
- body: mlhs[:body] << part, end: part[:end], char_end: part[:char_end]
1508
+ body: mlhs[:body] << part,
1509
+ end: part[:end],
1510
+ char_end: part[:char_end]
1452
1511
  )
1453
1512
  end
1454
1513
  end
@@ -1551,7 +1610,9 @@ class Prettier::Parser < Ripper
1551
1610
  part.merge(type: :mrhs, body: [part])
1552
1611
  else
1553
1612
  mrhs.merge!(
1554
- body: mrhs[:body] << part, end: part[:end], char_end: part[:char_end]
1613
+ body: mrhs[:body] << part,
1614
+ end: part[:end],
1615
+ char_end: part[:char_end]
1555
1616
  )
1556
1617
  end
1557
1618
  end
@@ -1712,7 +1773,8 @@ class Prettier::Parser < Ripper
1712
1773
  # expression literal, like /foo/. It can be followed by any number of
1713
1774
  # regexp_add events, which we'll append onto an array body.
1714
1775
  def on_regexp_new
1715
- find_scanner_event(:@regexp_beg).merge!(type: :regexp, body: [])
1776
+ beging = find_scanner_event(:@regexp_beg)
1777
+ beging.merge!(type: :regexp, body: [], beging: beging[:body])
1716
1778
  end
1717
1779
 
1718
1780
  # regexp_add is a parser event that represents a piece of a regular
@@ -1960,7 +2022,9 @@ class Prettier::Parser < Ripper
1960
2022
  # piece of the string.
1961
2023
  def on_string_add(string, piece)
1962
2024
  string.merge!(
1963
- body: string[:body] << piece, end: piece[:end], char_end: piece[:char_end]
2025
+ body: string[:body] << piece,
2026
+ end: piece[:end],
2027
+ char_end: piece[:char_end]
1964
2028
  )
1965
2029
  end
1966
2030
 
@@ -2296,7 +2360,7 @@ class Prettier::Parser < Ripper
2296
2360
  else
2297
2361
  # You can hit this pattern if you're assigning to a splat using pattern
2298
2362
  # matching syntax in Ruby 2.7+
2299
- { type: :var_field, body: [] }
2363
+ { type: :var_field, body: nil }
2300
2364
  end
2301
2365
  end
2302
2366
 
@@ -2417,7 +2481,9 @@ class Prettier::Parser < Ripper
2417
2481
  piece.merge(type: :word, body: [piece])
2418
2482
  else
2419
2483
  word.merge!(
2420
- body: word[:body] << piece, end: piece[:end], char_end: piece[:char_end]
2484
+ body: word[:body] << piece,
2485
+ end: piece[:end],
2486
+ char_end: piece[:char_end]
2421
2487
  )
2422
2488
  end
2423
2489
  end
@@ -2498,7 +2564,9 @@ class Prettier::Parser < Ripper
2498
2564
  else
2499
2565
  ending = find_scanner_event(:@tstring_end)
2500
2566
  xstring.merge!(
2501
- type: :xstring_literal, end: ending[:end], char_end: ending[:char_end]
2567
+ type: :xstring_literal,
2568
+ end: ending[:end],
2569
+ char_end: ending[:char_end]
2502
2570
  )
2503
2571
  end
2504
2572
  end
@@ -20,6 +20,18 @@ function printNode(path, opts, print) {
20
20
  throw new Error(`Unsupported node encountered: ${type}\n${ast}`);
21
21
  }
22
22
 
23
+ // This is an escape-hatch to ignore nodes in the tree. If you have a comment
24
+ // that includes this pattern, then the entire node will be ignored and just the
25
+ // original source will be printed out.
26
+ function hasPrettierIgnore(path) {
27
+ const node = path.getValue();
28
+
29
+ return (
30
+ node.comments &&
31
+ node.comments.some((comment) => comment.value.includes("prettier-ignore"))
32
+ );
33
+ }
34
+
23
35
  const noComments = [
24
36
  "args",
25
37
  "args_add_block",
@@ -83,6 +95,7 @@ function isBlockComment(comment) {
83
95
  module.exports = {
84
96
  embed,
85
97
  print: printNode,
98
+ hasPrettierIgnore,
86
99
  canAttachComment,
87
100
  getCommentChildNodes,
88
101
  printComment,
@@ -1,6 +1,7 @@
1
1
  const { concat } = require("./prettier");
2
2
  const isEmptyStmts = require("./utils/isEmptyStmts");
3
3
  const literalLineNoBreak = require("./utils/literalLineNoBreak");
4
+ const printEmptyCollection = require("./utils/printEmptyCollection");
4
5
 
5
6
  // If the node is a type of assignment or if the node is a paren and nested
6
7
  // inside that paren is a node that is a type of assignment.
@@ -89,5 +90,6 @@ module.exports = {
89
90
  makeCall,
90
91
  noIndent,
91
92
  prefix,
93
+ printEmptyCollection,
92
94
  skipAssignIndent
93
95
  };
@@ -0,0 +1,42 @@
1
+ const { concat, group, hardline, indent, join, line } = require("../prettier");
2
+
3
+ // Empty collections are array or hash literals that do not contain any
4
+ // contents. They can, however, have comments inside the body. You can solve
5
+ // this by having a child node inside the array that gets the comments attached
6
+ // to it, but that requires modifying the parser. Instead, we can just manually
7
+ // print out the non-leading comments here.
8
+ function printEmptyCollection(path, opts, startToken, endToken) {
9
+ const node = path.getValue();
10
+
11
+ // If there are no comments or only leading comments, then we can just print
12
+ // out the start and end token and be done, as there are no comments inside
13
+ // the body of this node.
14
+ if (!node.comments || !node.comments.some((comment) => !comment.leading)) {
15
+ return `${startToken}${endToken}`;
16
+ }
17
+
18
+ const comments = [];
19
+
20
+ // For each comment, go through its path and print it out manually.
21
+ const printComment = (commentPath) => {
22
+ const comment = commentPath.getValue();
23
+
24
+ if (!comment.leading) {
25
+ comment.printed = true;
26
+ comments.push(opts.printer.printComment(commentPath));
27
+ }
28
+ };
29
+
30
+ path.each(printComment, "comments");
31
+
32
+ return group(
33
+ concat([
34
+ startToken,
35
+ indent(concat([hardline, join(hardline, comments)])),
36
+ line,
37
+ endToken
38
+ ])
39
+ );
40
+ }
41
+
42
+ module.exports = printEmptyCollection;
metadata CHANGED
@@ -1,57 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prettier
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.rc2
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Deisz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-10 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: minitest
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '5.13'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '5.13'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '13.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '13.0'
11
+ date: 2020-12-27 00:00:00.000000000 Z
12
+ dependencies: []
55
13
  description:
56
14
  email:
57
15
  executables:
@@ -115,6 +73,7 @@ files:
115
73
  - src/utils/inlineEnsureParens.js
116
74
  - src/utils/isEmptyStmts.js
117
75
  - src/utils/literalLineNoBreak.js
76
+ - src/utils/printEmptyCollection.js
118
77
  homepage: https://github.com/prettier/plugin-ruby#readme
119
78
  licenses:
120
79
  - MIT
@@ -130,11 +89,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
89
  version: '0'
131
90
  required_rubygems_version: !ruby/object:Gem::Requirement
132
91
  requirements:
133
- - - ">"
92
+ - - ">="
134
93
  - !ruby/object:Gem::Version
135
- version: 1.3.1
94
+ version: '0'
136
95
  requirements: []
137
- rubygems_version: 3.0.3
96
+ rubygems_version: 3.1.4
138
97
  signing_key:
139
98
  specification_version: 4
140
99
  summary: prettier plugin for the Ruby programming language