Skip to content

Commit a866478

Browse files
authored
Format record literals. (#1301)
* Format record literals. * Sort ast_extensions.
1 parent 56e427d commit a866478

File tree

6 files changed

+270
-10
lines changed

6 files changed

+270
-10
lines changed

lib/src/ast_extensions.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ extension ExpressionExtensions on Expression {
113113
ParenthesizedExpression(:var expression) => expression.isDelimited,
114114
ListLiteral() => true,
115115
MethodInvocation() => true,
116+
RecordLiteral() => true,
116117
SetOrMapLiteral() => true,
117118
SwitchExpression() => true,
118-
// TODO(tall): Record literals.
119119
// TODO(tall): Instance creation expressions (`new` and `const`).
120120
_ => false,
121121
};

lib/src/front_end/ast_node_visitor.dart

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,13 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
662662

663663
@override
664664
void visitListLiteral(ListLiteral node) {
665-
createCollection(node, node.leftBracket, node.elements, node.rightBracket);
665+
createCollection(
666+
node.constKeyword,
667+
typeArguments: node.typeArguments,
668+
node.leftBracket,
669+
node.elements,
670+
node.rightBracket,
671+
);
666672
}
667673

668674
@override
@@ -858,7 +864,21 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
858864

859865
@override
860866
void visitRecordLiteral(RecordLiteral node) {
861-
throw UnimplementedError();
867+
ListStyle style;
868+
if (node.fields.length == 1 && node.fields[0] is! NamedExpression) {
869+
// Single-element records always have a trailing comma, unless the single
870+
// element is a named field.
871+
style = const ListStyle(commas: Commas.alwaysTrailing);
872+
} else {
873+
style = const ListStyle(commas: Commas.trailing);
874+
}
875+
createCollection(
876+
node.constKeyword,
877+
node.leftParenthesis,
878+
node.fields,
879+
node.rightParenthesis,
880+
style: style,
881+
);
862882
}
863883

864884
@override
@@ -920,7 +940,13 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
920940

921941
@override
922942
void visitSetOrMapLiteral(SetOrMapLiteral node) {
923-
createCollection(node, node.leftBracket, node.elements, node.rightBracket);
943+
createCollection(
944+
node.constKeyword,
945+
typeArguments: node.typeArguments,
946+
node.leftBracket,
947+
node.elements,
948+
node.rightBracket,
949+
);
924950
}
925951

926952
@override

lib/src/front_end/piece_factory.dart

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@ mixin PieceFactory implements CommentWriter {
8989
}
9090

9191
/// Creates a [ListPiece] for a collection literal.
92-
void createCollection(TypedLiteral literal, Token leftBracket,
93-
List<AstNode> elements, Token rightBracket) {
94-
modifier(literal.constKeyword);
95-
visit(literal.typeArguments);
92+
void createCollection(Token? constKeyword, Token leftBracket,
93+
List<AstNode> elements, Token rightBracket,
94+
{TypeArgumentList? typeArguments, ListStyle style = const ListStyle()}) {
95+
modifier(constKeyword);
96+
visit(typeArguments);
9697

9798
// TODO(tall): Support a line comment inside a collection literal as a
9899
// signal to preserve internal newlines. So if you have:
@@ -107,7 +108,12 @@ mixin PieceFactory implements CommentWriter {
107108
// The formatter will preserve the newline after element 3 and the lack of
108109
// them after the other elements.
109110

110-
createList(leftBracket: leftBracket, elements, rightBracket: rightBracket);
111+
createList(
112+
leftBracket: leftBracket,
113+
elements,
114+
rightBracket: rightBracket,
115+
style: style,
116+
);
111117
}
112118

113119
/// Creates metadata annotations for a directive.

lib/src/piece/list.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class ListPiece extends Piece {
8080
for (var i = 0; i < _elements.length; i++) {
8181
var isLast = i == _elements.length - 1;
8282
var appendComma = switch (_style.commas) {
83+
// Has a comma after every element.
84+
Commas.alwaysTrailing => true,
8385
// Trailing comma after the last element if split but not otherwise.
8486
Commas.trailing => !(state == State.unsplit && isLast),
8587
// Never a trailing comma after the last element.
@@ -209,11 +211,14 @@ final class ListElement {
209211

210212
/// Where commas should be added in a [ListPiece].
211213
enum Commas {
214+
/// Add a comma after every element, regardless of whether or not it is split.
215+
alwaysTrailing,
216+
212217
/// Add a comma after every element when the elements split, including the
213218
/// last. When not split, omit the trailing comma.
214219
trailing,
215220

216-
/// Add a comme after every element except for the last, regardless of whether
221+
/// Add a comma after every element except for the last, regardless of whether
217222
/// or not it is split.
218223
nonTrailing,
219224

test/expression/record.stmt

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
40 columns |
2+
>>> Empty record.
3+
var record = ( );
4+
<<<
5+
var record = ();
6+
>>> Single-element records don't split after ",".
7+
var record = ( value , );
8+
<<<
9+
var record = (value,);
10+
>>> Multi-element record.
11+
var record = ( first , second , third );
12+
<<<
13+
var record = (first, second, third);
14+
>>> Remove trailing comma from record if unsplit
15+
var record = (
16+
1,
17+
2,
18+
);
19+
<<<
20+
var record = (1, 2);
21+
>>> Named record fields.
22+
var record = ( first : 1 , 2 , third : 3 );
23+
<<<
24+
var record = (first: 1, 2, third: 3);
25+
>>> Const record.
26+
var record = const ( 1 , 2 );
27+
<<<
28+
var record = const (1, 2);
29+
>>> Empty records don't split.
30+
var longVariableName_______________ = ();
31+
<<<
32+
var longVariableName_______________ =
33+
();
34+
>>> Single-element record.
35+
var record = (veryLongRecordField________________,);
36+
<<<
37+
var record = (
38+
veryLongRecordField________________,
39+
);
40+
>>> Single-element named record doesn't have comma added.
41+
var record = (a: b);
42+
<<<
43+
var record = (a: b);
44+
>>> Single-element named record with comma removed.
45+
var record = (a: b,);
46+
<<<
47+
var record = (a: b);
48+
>>> Long single-element named record that splits.
49+
var record = (longFieldName: longRecordFieldValue);
50+
<<<
51+
var record = (
52+
longFieldName: longRecordFieldValue,
53+
);
54+
>>> Long single-element named record splits at name.
55+
var record = (longFieldName: veryLongRecordFieldValue);
56+
<<<
57+
var record = (
58+
longFieldName:
59+
veryLongRecordFieldValue,
60+
);
61+
>>> Exactly 40 characters.
62+
(first, second, third, fourth, seventh);
63+
<<<
64+
(first, second, third, fourth, seventh);
65+
>>> Split with multiple elements.
66+
(first, second, third, fourth, fifth, sixth);
67+
<<<
68+
(
69+
first,
70+
second,
71+
third,
72+
fourth,
73+
fifth,
74+
sixth,
75+
);
76+
>>> Don't force outer record to split.
77+
((first,), (second, third));
78+
<<<
79+
((first,), (second, third));
80+
>>> Don't force outer list to split.
81+
[(first,), (second, third)];
82+
<<<
83+
[(first,), (second, third)];
84+
>>> inner list doesn't force split
85+
([first], [second, third]);
86+
<<<
87+
([first], [second, third]);
88+
>>> Nested split record.
89+
(first, (second, third, fourth), fifth, (sixth, seventh, eighth, nine, tenth,
90+
eleventh));
91+
<<<
92+
(
93+
first,
94+
(second, third, fourth),
95+
fifth,
96+
(
97+
sixth,
98+
seventh,
99+
eighth,
100+
nine,
101+
tenth,
102+
eleventh,
103+
),
104+
);
105+
>>> Trailing comma in single-element does not split.
106+
(1,);
107+
<<<
108+
(1,);
109+
>>> Don't allow splitting between field name and record.
110+
var record = (argument, argument, argument, recordFieldName: (veryLongElement__________,));
111+
<<<
112+
var record = (
113+
argument,
114+
argument,
115+
argument,
116+
recordFieldName: (
117+
veryLongElement__________,
118+
),
119+
);

test/expression/record_comment.stmt

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
40 columns |
2+
>>> Empty record block comment.
3+
var record = ( /* comment */ );
4+
<<<
5+
var record = (/* comment */);
6+
>>> Empty record line comment.
7+
var record = ( // comment
8+
);
9+
<<<
10+
var record = (
11+
// comment
12+
);
13+
>>> Single-element record block comment, after comma.
14+
var record = ( element , /* comment */ );
15+
<<<
16+
var record = (element /* comment */,);
17+
>>> Single-element record block comment, before comma.
18+
var record = ( element /* comment */ , );
19+
<<<
20+
var record = (element /* comment */,);
21+
>>> Long single-element record block comment, before comma.
22+
var record = ( element /* very long adhered to element */ , );
23+
<<<
24+
var record = (
25+
element /* very long adhered to element */,
26+
);
27+
>>> Long single-element record block comment, after comma.
28+
var record = ( element, /* very long adhered to element */ );
29+
<<<
30+
var record = (
31+
element /* very long adhered to element */,
32+
);
33+
>>> Single-element record line comment, before comma.
34+
var record = ( element , // comment
35+
);
36+
<<<
37+
var record = (
38+
element, // comment
39+
);
40+
>>> Single-element record line comment, after comma.
41+
var record = ( element // comment
42+
,);
43+
<<<
44+
var record = (
45+
element, // comment
46+
);
47+
>>> Multi-element record block comment, before comma.
48+
var record = ( 1 /* comment */ , 2 );
49+
<<<
50+
var record = (1 /* comment */, 2);
51+
>>> Multi-element record block comment, after comma.
52+
var record = ( 1 , /* comment */ 2 );
53+
<<<
54+
var record = (1, /* comment */ 2);
55+
>>> Multi-element record line comment, before comma.
56+
var record = ( 1 // comment
57+
, 2 );
58+
<<<
59+
var record = (
60+
1, // comment
61+
2,
62+
);
63+
>>> Multi-element record line comment, after comma.
64+
var record = ( 1, // comment
65+
2 );
66+
<<<
67+
var record = (
68+
1, // comment
69+
2,
70+
);
71+
>>> Ignore line comment after the ")".
72+
(
73+
a,b,c,
74+
d
75+
) // comment
76+
;
77+
<<<
78+
(a, b, c, d) // comment
79+
;
80+
>>> Preserve blank lines between comments and elements.
81+
(
82+
83+
84+
element,
85+
86+
87+
88+
// comment
89+
element,
90+
91+
92+
93+
element
94+
95+
96+
);
97+
<<<
98+
(
99+
element,
100+
101+
// comment
102+
element,
103+
element,
104+
);

0 commit comments

Comments
 (0)