require-trailing-commas

Same as require_trailing_commas in Dart lints

Group
Style
Path
lint/style/require-trailing-commas
Default
Off, opt in
Origin
Dart lints
Rule
431 of 512

Flags a multi-line call, declaration, assert, or collection literal that is missing a trailing comma.

When the opening and closing delimiters of an argument list, parameter list, assert, or list/set/map literal sit on different lines, the last element must be followed by a comma so the formatter keeps one element per line:

foo(a, b);                    // fine: fits on one line
foo(
  a,
  b                           // flagged at `)`
);
void f({
  required int a              // flagged at `}`
}) {}

A positional last element that itself spans several lines is exempt when it is a block-bodied function literal, a string literal, an immediately invoked function literal whose arguments fit on one line, or a list, set, or map literal — the classic test('name', () { ... }); shape. Named arguments and parameters never get the exemption. Record literals, type argument lists, and extension type representation clauses are not checked.

Delimiters inside string interpolations ('${f(a, b)}') are matched like any others.

Like the official lint, the rule is off in libraries at language version 3.7 or later, where the formatter's tall style owns trailing commas.

Invalid

example.dartdart
// Tall-style formatting (language 3.7+) disables the lint; pin an older version.
// @dart = 3.6
void call(Object a, [Object? b, Object? c]) {}
void named({Object? a, Object? b}) {}

class Point {
  final int x;
  final int y;

  Point(
    this.x,
    this.y)
      : assert(x >= 0,
            'x must be non-negative');

  Point.origin({
    this.x = 0,
    this.y = 0});
}

void declaration(
  int a,
  int b) {}

void optional(
  int a, [
  int b = 0]) {}

void f() {
  call('a',
      'b');

  named(a: 1,
      b: () {
        print('named function literals get no exemption');
      });

  final list = [
    1,
    2];

  final map = {
    'a': 1,
    'b': 2};

  assert(list.isNotEmpty,
      map.toString());

  call(1, 2,
      3);
}

typedef Callback = void Function(
  int a,
  int b);

List<Object> nestedLast() => [
      [0, 'a'],
      [1, 'b']
    ];

String nestedInterpolation() => '${call(
      1,
      2)}';
Add the required trailing comma.
11 this.x,
12 this.y)
Add the required trailing comma.
13 : assert(x >= 0,
14 'x must be non-negative');
Add the required trailing comma.
17 this.x = 0,
18 this.y = 0});
Add the required trailing comma.
22 int a,
23 int b) {}
Add the required trailing comma.
26 int a, [
27 int b = 0]) {}
Add the required trailing comma.
30 call('a',
31 'b');
Add the required trailing comma.
35 print('named function literals get no exemption');
36 });
Add the required trailing comma.
39 1,
40 2];
Add the required trailing comma.
43 'a': 1,
44 'b': 2};
Add the required trailing comma.
46 assert(list.isNotEmpty,
47 map.toString());
Add the required trailing comma.
49 call(1, 2,
50 3);
Add the required trailing comma.
54 int a,
55 int b);
Add the required trailing comma.
59 [1, 'b']
60 ];
Add the required trailing comma.
63 1,
64 2)}';

Valid

example.dartdart
// Tall-style formatting (language 3.7+) disables the lint; pin an older version.
// @dart = 3.6
void call(Object a, [Object? b, Object? c]) {}
void named({Object? a, Object? b}) {}
void test(String name, void Function() body) {}

class Point {
  final int x;
  final int y;

  Point(
    this.x,
    this.y,
  ) : assert(x >= 0, 'x must be non-negative');

  Point.origin({
    this.x = 0,
    this.y = 0,
  });
}

void declaration(int a, int b) {}

void f() {
  call('a', 'b');

  // A multi-line block-bodied function literal as the last argument is exempt.
  test('name', () {
    print('body');
  });

  // So is a multi-line string literal ...
  call('a', '''
first line
second line
''');

  // ... and a multi-line collection literal.
  call(1, [
    2,
    3,
  ]);
  call(1, {
    'a': 2,
  });

  final list = [
    1,
    2,
  ];
  final map = {'a': 1, 'b': 2};
  print(map);
  named(
    a: 1,
    b: 2,
  );
  named();
}

final list = <int>[];

typedef Callback = void Function(
  int a,
  int b,
);

void interpolated() {
  // Calls inside string interpolations are checked on their own delimiters.
  test('${'x'.padLeft(2, ' ')}', () {});
  test('group', () {
    call(1);
  });
}

Configure require-trailing-commas

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "require-trailing-commas": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/require-trailing-commas: <reason>
  • sized-box-shrink-expandsized_box_shrink_expandrecommendedflutter

    Prefers SizedBox.shrink() / SizedBox.expand() over a SizedBox sized to zero or infinity.

  • slash-for-doc-commentsslash_for_doc_commentsrecommended

    Flags /** ...

  • sort-child-properties-lastsort_child_properties_lastrecommendedflutter

    Sort Widget-valued child properties last, except before closure arguments.

  • sort-constructors-firstsort_constructors_first

    Flags a constructor declared after a non-constructor member.

  • sort-unnamed-constructors-firstsort_unnamed_constructors_first

    Flags an unnamed constructor declared after a named constructor.

  • tighten-type-of-initializing-formalstighten_type_of_initializing_formals

    Flags a nullable this.x or super.x initializing formal whose constructor asserts x != null.

  • type-annotate-public-apistype_annotate_public_apisrecommended

    Requires type annotations on public declarations.

  • type-init-formalstype_init_formalsrecommended

    Flags a *redundant* type annotation on an initializing formal or super parameter (type-init-formals, adopted from package:lints).