prettier 0.20.1 → 0.21.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/CONTRIBUTING.md +5 -3
- data/README.md +51 -48
- data/node_modules/prettier/bin-prettier.js +181 -148
- data/node_modules/prettier/index.js +10335 -7465
- data/node_modules/prettier/third-party.js +33 -140
- data/package.json +1 -1
- data/src/nodes.js +1 -0
- data/src/nodes/alias.js +67 -24
- data/src/nodes/aref.js +55 -0
- data/src/nodes/arrays.js +6 -38
- data/src/nodes/calls.js +4 -19
- data/src/nodes/conditionals.js +12 -24
- data/src/nodes/flow.js +36 -18
- data/src/nodes/hashes.js +45 -45
- data/src/nodes/hooks.js +36 -6
- data/src/nodes/lambdas.js +75 -45
- data/src/nodes/loops.js +9 -24
- data/src/nodes/strings.js +0 -6
- data/src/parse.js +1 -1
- data/src/{ripper.rb → parser.rb} +27 -50
- data/src/ruby.js +1 -1
- data/src/utils.js +21 -19
- data/src/utils/inlineEnsureParens.js +42 -0
- data/src/utils/isEmptyStmts.js +7 -0
- metadata +6 -3
data/src/nodes/loops.js
CHANGED
@@ -7,7 +7,9 @@ const {
|
|
7
7
|
indent,
|
8
8
|
softline
|
9
9
|
} = require("../prettier");
|
10
|
+
|
10
11
|
const { containsAssignment } = require("../utils");
|
12
|
+
const inlineEnsureParens = require("../utils/inlineEnsureParens");
|
11
13
|
|
12
14
|
const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
13
15
|
const [_predicate, statements] = path.getValue().body;
|
@@ -26,30 +28,13 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
|
26
28
|
);
|
27
29
|
}
|
28
30
|
|
29
|
-
|
30
|
-
path
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
// besides a local variable then we can't inline the entire expression
|
37
|
-
// without wrapping it in parentheses. This is because the following
|
38
|
-
// expressions have different semantic meaning:
|
39
|
-
//
|
40
|
-
// hash[:key] = break :value while false
|
41
|
-
// hash[:key] = while false do break :value end
|
42
|
-
//
|
43
|
-
// The first one will not result in an empty hash, whereas the second one
|
44
|
-
// will result in `{ key: nil }`. In this case what we need to do for the
|
45
|
-
// first expression to align is wrap it in parens, as in:
|
46
|
-
//
|
47
|
-
// hash[:key] = (break :value while false)
|
48
|
-
if (["assign", "massign"].includes(path.getParentNode().type)) {
|
49
|
-
inlineParts = ["("].concat(inlineParts).concat(")");
|
50
|
-
}
|
51
|
-
|
52
|
-
const inlineLoop = concat(inlineParts);
|
31
|
+
const inlineLoop = concat(
|
32
|
+
inlineEnsureParens(path, [
|
33
|
+
path.call(print, "body", 1),
|
34
|
+
` ${keyword} `,
|
35
|
+
path.call(print, "body", 0)
|
36
|
+
])
|
37
|
+
);
|
53
38
|
|
54
39
|
// If we're in the modifier form and we're modifying a `begin`, then this is a
|
55
40
|
// special case where we need to explicitly use the modifier form because
|
data/src/nodes/strings.js
CHANGED
@@ -133,12 +133,6 @@ module.exports = {
|
|
133
133
|
const stringLiteral = path.getValue();
|
134
134
|
const string = stringLiteral.body[0];
|
135
135
|
|
136
|
-
// If this string is actually a heredoc, bail out and return to the print
|
137
|
-
// function for heredocs
|
138
|
-
if (string.type === "heredoc") {
|
139
|
-
return path.call(print, "body", 0);
|
140
|
-
}
|
141
|
-
|
142
136
|
// If the string is empty, it will not have any parts, so just print out the
|
143
137
|
// quotes corresponding to the config
|
144
138
|
if (string.body.length === 0) {
|
data/src/parse.js
CHANGED
@@ -19,7 +19,7 @@ const LANG = {
|
|
19
19
|
module.exports = (text, _parsers, _opts) => {
|
20
20
|
const child = spawnSync(
|
21
21
|
"ruby",
|
22
|
-
["--disable-gems", path.join(__dirname, "./
|
22
|
+
["--disable-gems", path.join(__dirname, "./parser.rb")],
|
23
23
|
{
|
24
24
|
env: Object.assign({}, process.env, { LANG }),
|
25
25
|
input: text,
|
data/src/{ripper.rb → parser.rb}
RENAMED
@@ -16,7 +16,9 @@ end
|
|
16
16
|
require 'json' unless defined?(JSON)
|
17
17
|
require 'ripper'
|
18
18
|
|
19
|
-
|
19
|
+
module Prettier; end
|
20
|
+
|
21
|
+
class Prettier::Parser < Ripper
|
20
22
|
attr_reader :source, :lines, :__end__
|
21
23
|
|
22
24
|
def initialize(source, *args)
|
@@ -476,7 +478,7 @@ class RipperJS < Ripper
|
|
476
478
|
def on_comment(body)
|
477
479
|
sexp = { type: :@comment, body: body.chomp, start: lineno, end: lineno }
|
478
480
|
|
479
|
-
case
|
481
|
+
case Prettier::Parser.lex_state_name(state).gsub('EXPR_', '')
|
480
482
|
when 'END', 'ARG|LABELED', 'ENDFN'
|
481
483
|
last_sexp.merge!(comments: [sexp])
|
482
484
|
when 'CMDARG', 'END|ENDARG', 'ENDARG', 'ARG', 'FNAME|FITEM', 'CLASS',
|
@@ -565,7 +567,7 @@ class RipperJS < Ripper
|
|
565
567
|
|
566
568
|
def on_comment(body)
|
567
569
|
super(body).tap do |sexp|
|
568
|
-
lex_state =
|
570
|
+
lex_state = Prettier::Parser.lex_state_name(state).gsub('EXPR_', '')
|
569
571
|
block_comments << sexp if lex_state == 'BEG'
|
570
572
|
end
|
571
573
|
end
|
@@ -614,34 +616,39 @@ class RipperJS < Ripper
|
|
614
616
|
|
615
617
|
private
|
616
618
|
|
617
|
-
|
618
|
-
super(body).tap { |sexp| heredoc_stack << sexp }
|
619
|
-
end
|
620
|
-
|
621
|
-
def on_embexpr_end(body)
|
622
|
-
super(body).tap { heredoc_stack.pop }
|
623
|
-
end
|
624
|
-
|
619
|
+
# This is a scanner event that represents the beginning of the heredoc.
|
625
620
|
def on_heredoc_beg(beging)
|
626
|
-
|
627
|
-
|
621
|
+
{
|
622
|
+
type: :heredoc,
|
623
|
+
beging: beging,
|
624
|
+
start: lineno,
|
625
|
+
end: lineno,
|
626
|
+
char_start: char_pos - beging.length + 1,
|
627
|
+
char_end: char_pos
|
628
|
+
}.tap { |node| heredoc_stack << node }
|
628
629
|
end
|
629
630
|
|
631
|
+
# This is a scanner event that represents the end of the heredoc.
|
630
632
|
def on_heredoc_end(ending)
|
631
|
-
heredoc_stack[-1].merge!(
|
633
|
+
heredoc_stack[-1].merge!(
|
634
|
+
ending: ending.chomp, end: lineno, char_end: char_pos
|
635
|
+
)
|
632
636
|
end
|
633
637
|
|
638
|
+
# This is a parser event that occurs when you're using a heredoc with a
|
639
|
+
# tilde. These are considered `heredoc_dedent` nodes, whereas the hyphen
|
640
|
+
# heredocs show up as string literals.
|
634
641
|
def on_heredoc_dedent(string, _width)
|
635
|
-
|
636
|
-
string.merge!(heredoc.slice(:type, :beging, :ending, :start, :end))
|
642
|
+
heredoc_stack[-1].merge!(string.slice(:body))
|
637
643
|
end
|
638
644
|
|
645
|
+
# String literals are either going to be a normal string or they're going
|
646
|
+
# to be a heredoc with a hyphen.
|
639
647
|
def on_string_literal(string)
|
640
648
|
heredoc = heredoc_stack[-1]
|
641
649
|
|
642
|
-
if heredoc &&
|
643
|
-
heredoc_stack.pop
|
644
|
-
string.merge!(heredoc.slice(:type, :beging, :ending, :start, :end))
|
650
|
+
if heredoc && heredoc[:ending]
|
651
|
+
heredoc_stack.pop.merge!(string.slice(:body))
|
645
652
|
else
|
646
653
|
super
|
647
654
|
end
|
@@ -731,36 +738,6 @@ class RipperJS < Ripper
|
|
731
738
|
super(ident, params, def_bodystmt)
|
732
739
|
end
|
733
740
|
|
734
|
-
# By default, Ripper parses the expression `lambda { foo }` as a
|
735
|
-
# `method_add_block` node, so we can't turn it back into `-> { foo }`.
|
736
|
-
# This module overrides that behavior and reports it back as a `lambda`
|
737
|
-
# node instead.
|
738
|
-
def on_method_add_block(invocation, block)
|
739
|
-
# It's possible to hit a `method_add_block` node without going through
|
740
|
-
# `method_add_arg` node, ex: `super {}`. In that case we're definitely
|
741
|
-
# not going to transform into a lambda.
|
742
|
-
return super if invocation[:type] != :method_add_arg
|
743
|
-
|
744
|
-
fcall, args = invocation[:body]
|
745
|
-
|
746
|
-
# If there are arguments to the `lambda`, that means `lambda` has been
|
747
|
-
# overridden as a function so we cannot transform it into a `lambda`
|
748
|
-
# node.
|
749
|
-
if fcall[:type] != :fcall || args[:type] != :args || args[:body].any?
|
750
|
-
return super
|
751
|
-
end
|
752
|
-
|
753
|
-
ident = fcall.dig(:body, 0)
|
754
|
-
return super if ident[:type] != :@ident || ident[:body] != 'lambda'
|
755
|
-
|
756
|
-
super.tap do |sexp|
|
757
|
-
params, stmts = block[:body]
|
758
|
-
params ||= { type: :params, body: [] }
|
759
|
-
|
760
|
-
sexp.merge!(type: :lambda, body: [params, stmts])
|
761
|
-
end
|
762
|
-
end
|
763
|
-
|
764
741
|
# We need to track for `mlhs_paren` and `massign` nodes whether or not
|
765
742
|
# there was an extra comma at the end of the expression. For some reason
|
766
743
|
# it's not showing up in the AST in an obvious way. In this case we're
|
@@ -794,7 +771,7 @@ end
|
|
794
771
|
# stdin and report back the AST over stdout.
|
795
772
|
|
796
773
|
if $0 == __FILE__
|
797
|
-
builder =
|
774
|
+
builder = Prettier::Parser.new($stdin.read)
|
798
775
|
response = builder.parse
|
799
776
|
|
800
777
|
if !response || builder.error?
|
data/src/ruby.js
CHANGED
data/src/utils.js
CHANGED
@@ -5,6 +5,7 @@ const {
|
|
5
5
|
lineSuffix,
|
6
6
|
literalline
|
7
7
|
} = require("./prettier");
|
8
|
+
const isEmptyStmts = require("./utils/isEmptyStmts");
|
8
9
|
|
9
10
|
const concatBody = (path, opts, print) => concat(path.map(print, "body"));
|
10
11
|
|
@@ -65,27 +66,16 @@ const makeArgs = (path, opts, print, argsIndex) => {
|
|
65
66
|
const heredocs = [];
|
66
67
|
|
67
68
|
argNodes.body.forEach((argNode, index) => {
|
68
|
-
let pattern;
|
69
|
-
let heredoc;
|
70
|
-
|
71
69
|
if (argNode.type === "heredoc") {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
[
|
80
|
-
} else {
|
81
|
-
return;
|
70
|
+
const content = path.map.apply(
|
71
|
+
path,
|
72
|
+
argPattern.slice().concat([index, "body"])
|
73
|
+
);
|
74
|
+
heredocs.push(
|
75
|
+
concat([literalline].concat(content).concat([argNode.ending]))
|
76
|
+
);
|
77
|
+
args[index] = argNode.beging;
|
82
78
|
}
|
83
|
-
|
84
|
-
const content = path.map.apply(path, argPattern.slice().concat(pattern));
|
85
|
-
heredocs.push(
|
86
|
-
concat([literalline].concat(content).concat([heredoc.ending]))
|
87
|
-
);
|
88
|
-
args[index] = heredoc.beging;
|
89
79
|
});
|
90
80
|
|
91
81
|
return { args, heredocs };
|
@@ -103,6 +93,16 @@ const makeCall = (path, opts, print) => {
|
|
103
93
|
|
104
94
|
const makeList = (path, opts, print) => path.map(print, "body");
|
105
95
|
|
96
|
+
const nodeDive = (node, steps) => {
|
97
|
+
let current = node;
|
98
|
+
|
99
|
+
steps.forEach((step) => {
|
100
|
+
current = current[step];
|
101
|
+
});
|
102
|
+
|
103
|
+
return current;
|
104
|
+
};
|
105
|
+
|
106
106
|
const prefix = (value) => (path, opts, print) =>
|
107
107
|
concat([value, path.call(print, "body", 0)]);
|
108
108
|
|
@@ -146,10 +146,12 @@ module.exports = {
|
|
146
146
|
empty,
|
147
147
|
first,
|
148
148
|
hasAncestor,
|
149
|
+
isEmptyStmts,
|
149
150
|
literal,
|
150
151
|
makeArgs,
|
151
152
|
makeCall,
|
152
153
|
makeList,
|
154
|
+
nodeDive,
|
153
155
|
prefix,
|
154
156
|
printComments,
|
155
157
|
skipAssignIndent,
|
@@ -0,0 +1,42 @@
|
|
1
|
+
const needsParens = ["args", "assign", "assoc_new", "massign", "opassign"];
|
2
|
+
|
3
|
+
// If you have a modifier statement (for instance an inline if statement or an
|
4
|
+
// inline while loop) there are times when you need to wrap the entire statement
|
5
|
+
// in parentheses. This occurs when you have something like:
|
6
|
+
//
|
7
|
+
// foo[:foo] =
|
8
|
+
// if bar?
|
9
|
+
// baz
|
10
|
+
// end
|
11
|
+
//
|
12
|
+
// Normally we would shorten this to an inline version, which would result in:
|
13
|
+
//
|
14
|
+
// foo[:foo] = baz if bar?
|
15
|
+
//
|
16
|
+
// but this actually has different semantic meaning. The first example will
|
17
|
+
// result in a nil being inserted into the hash for the :foo key, whereas the
|
18
|
+
// second example will result in an empty hash because the if statement applies
|
19
|
+
// to the entire assignment.
|
20
|
+
//
|
21
|
+
// We can fix this in a couple of ways. We can use the then keyword, as in:
|
22
|
+
//
|
23
|
+
// foo[:foo] = if bar? then baz end
|
24
|
+
//
|
25
|
+
// but I haven't actually seen this anywhere. We can also just leave it as is
|
26
|
+
// with the multi-line version, but for a short predicate and short value it
|
27
|
+
// looks pretty silly. The last option and the one I've selected here is to add
|
28
|
+
// parentheses on both sides of the expression, as in:
|
29
|
+
//
|
30
|
+
// foo[:foo] = (baz if bar?)
|
31
|
+
//
|
32
|
+
// This approach maintains the nice conciseness of the inline version, while
|
33
|
+
// keeping the correct semantic meaning.
|
34
|
+
const inlineEnsureParens = (path, parts) => {
|
35
|
+
if (needsParens.includes(path.getParentNode().type)) {
|
36
|
+
return ["("].concat(parts, ")");
|
37
|
+
}
|
38
|
+
|
39
|
+
return parts;
|
40
|
+
};
|
41
|
+
|
42
|
+
module.exports = inlineEnsureParens;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prettier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
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-
|
11
|
+
date: 2020-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- src/embed.js
|
76
76
|
- src/nodes.js
|
77
77
|
- src/nodes/alias.js
|
78
|
+
- src/nodes/aref.js
|
78
79
|
- src/nodes/args.js
|
79
80
|
- src/nodes/arrays.js
|
80
81
|
- src/nodes/assign.js
|
@@ -102,12 +103,14 @@ files:
|
|
102
103
|
- src/nodes/statements.js
|
103
104
|
- src/nodes/strings.js
|
104
105
|
- src/parse.js
|
106
|
+
- src/parser.rb
|
105
107
|
- src/prettier.js
|
106
108
|
- src/print.js
|
107
|
-
- src/ripper.rb
|
108
109
|
- src/ruby.js
|
109
110
|
- src/toProc.js
|
110
111
|
- src/utils.js
|
112
|
+
- src/utils/inlineEnsureParens.js
|
113
|
+
- src/utils/isEmptyStmts.js
|
111
114
|
homepage: https://github.com/prettier/plugin-ruby#readme
|
112
115
|
licenses:
|
113
116
|
- MIT
|