widget-tree-depth

Path
lint/complexity/widget-tree-depth
Default
Off, opt in
Origin
Falcon
Domain
flutter
Rule
512 of 512
flutter

Limits the depth of an inline Flutter widget construction tree.

Only resolved constructors of Flutter Widget subtypes add a level. Canonical Flutter SizedBox constructors are transparent and do not count. Lists, parentheses, casts, null assertions and conditional branches add no levels. Helper calls and closures start independent trees: their bodies/arguments are not evidence of the widget returned by the call. References to extracted widgets likewise do not expand a tree. Each tree is reported once at its root.

max-nesting (integer, default: 8) is the maximum permitted widget depth; the root is level one. This follows the widgets-nesting-level metric's default.

Invalid

example.dartdart
import 'package:flutter/widgets.dart' as f;

class Panel extends f.Widget {
  const Panel({required this.child});
  const Panel.named({required this.child});
  final f.Widget child;
}
typedef PanelAlias = Panel;

f.Widget direct() => f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
f.Widget explicitNew() => new f.Center(child: new f.Center(child: new f.Center(child: new f.Text('deep'))));
f.Widget constant() => const f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
f.Widget children() => f.Column(children: [f.Center(child: f.Center(child: f.Text('deep'))), f.Text('sibling')]);
f.Widget conditional(bool flag) => f.Center(child: flag ? f.Center(child: f.Center(child: f.Text('deep'))) : f.Text('shallow'));
f.Widget custom() => Panel.named(child: PanelAlias(child: f.Center(child: f.Text('deep'))));
f.Widget parentheses() => f.Center(child: ((f.Center(child: (f.Center(child: f.Text('deep')))))));
f.Widget collectionIf(bool flag) => f.Column(children: [if (flag) f.Center(child: f.Center(child: f.Text('deep')))]);
f.Widget collectionSpread() => f.Column(children: [...[f.Center(child: f.Center(child: f.Text('deep')))]]);
f.Widget sizedBoxIsTransparent() => f.Center(child: f.SizedBox(child: f.Center(child: f.Center(child: f.Text('deep')))));

class SizedBox extends f.Widget {
  const SizedBox({required this.child});
  final f.Widget child;
}
f.Widget unrelatedSizedBoxCounts() => SizedBox(child: SizedBox(child: SizedBox(child: f.Text('deep'))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
9
10f.Widget direct() => f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
10f.Widget direct() => f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
11f.Widget explicitNew() => new f.Center(child: new f.Center(child: new f.Center(child: new f.Text('deep'))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
11f.Widget explicitNew() => new f.Center(child: new f.Center(child: new f.Center(child: new f.Text('deep'))));
12f.Widget constant() => const f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
12f.Widget constant() => const f.Center(child: f.Center(child: f.Center(child: f.Text('deep'))));
13f.Widget children() => f.Column(children: [f.Center(child: f.Center(child: f.Text('deep'))), f.Text('sibling')]);
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
13f.Widget children() => f.Column(children: [f.Center(child: f.Center(child: f.Text('deep'))), f.Text('sibling')]);
14f.Widget conditional(bool flag) => f.Center(child: flag ? f.Center(child: f.Center(child: f.Text('deep'))) : f.Text('shallow'));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
14f.Widget conditional(bool flag) => f.Center(child: flag ? f.Center(child: f.Center(child: f.Text('deep'))) : f.Text('shallow'));
15f.Widget custom() => Panel.named(child: PanelAlias(child: f.Center(child: f.Text('deep'))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
15f.Widget custom() => Panel.named(child: PanelAlias(child: f.Center(child: f.Text('deep'))));
16f.Widget parentheses() => f.Center(child: ((f.Center(child: (f.Center(child: f.Text('deep')))))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
16f.Widget parentheses() => f.Center(child: ((f.Center(child: (f.Center(child: f.Text('deep')))))));
17f.Widget collectionIf(bool flag) => f.Column(children: [if (flag) f.Center(child: f.Center(child: f.Text('deep')))]);
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
17f.Widget collectionIf(bool flag) => f.Column(children: [if (flag) f.Center(child: f.Center(child: f.Text('deep')))]);
18f.Widget collectionSpread() => f.Column(children: [...[f.Center(child: f.Center(child: f.Text('deep')))]]);
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
18f.Widget collectionSpread() => f.Column(children: [...[f.Center(child: f.Center(child: f.Text('deep')))]]);
19f.Widget sizedBoxIsTransparent() => f.Center(child: f.SizedBox(child: f.Center(child: f.Center(child: f.Text('deep')))));
Widget tree has a depth of 4 (max 3). Extract a subtree into a widget.
24}
25f.Widget unrelatedSizedBoxCounts() => SizedBox(child: SizedBox(child: SizedBox(child: f.Text('deep'))));

Valid

example.dartdart
import 'package:flutter/widgets.dart' as f;

f.Widget leaf() => f.Text('one');
f.Widget atLimit() => f.Center(child: f.Center(child: f.Text('three')));
f.Widget parentheses() => (((((f.Text('one'))))));
f.Widget siblings() => f.Column(children: [f.Text('a'), f.Text('b'), f.Text('c'), f.Text('d'), f.Text('e')]);
f.Widget conditional(bool flag) => f.Center(child: flag ? f.Center(child: f.Text('three')) : f.Text('two'));
f.Widget collectionFor(List<String> names) => f.Column(children: [for (final name in names) f.Text(name)]);
f.Widget extracted(f.Widget subtree) => f.Center(child: subtree);
f.Widget identity(f.Widget widget) => widget;
f.Widget helperBoundary() => f.Center(child: identity(f.Center(child: f.Center(child: f.Text('three')))));

class Deferred extends f.Widget {
  const Deferred(this.builder);
  final f.Widget Function() builder;
}
f.Widget callbackBoundary() => Deferred(() => f.Center(child: f.Center(child: f.Text('three'))));

void shadowed() {
  final Center = (Object value) => value;
  Center(Center(Center(Center('not widget construction'))));
}

class Wrapper {
  Wrapper(Object value);
}
Object unrelatedConstructors() => Wrapper(Wrapper(Wrapper(Wrapper(f.Text('one')))));

f.Widget ignoredSizedBoxes() => f.SizedBox(child: f.SizedBox(child: f.SizedBox(child: f.SizedBox(child: f.Text('one')))));
f.Widget sizedBoxWithinTree() => f.Center(child: f.SizedBox(child: f.Center(child: f.Text('three'))));

Configure widget-tree-depth

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "complexity": {
        "widget-tree-depth": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/complexity/widget-tree-depth: <reason>