dartnative_assists 0.1.1
dartnative_assists: ^0.1.1 copied to clipboard
Analyzer plugin for DartNative: the Flutter-style wrap, remove, swap and convert widget assists, plus warnings for behaviours that fail silently.
dartnative_assists #
Option+Enter widget assists and DartNative-specific warnings for DartNative projects. Runs inside the Dart Analysis Server, so it works the same in Android Studio, IntelliJ and VS Code.
Why #
The analysis server ships "Wrap with Container", "Convert to StatefulWidget"
and the rest of the Flutter assists, but each one checks that the widget
class comes from package:flutter/src/widgets/framework.dart. DartNative's
Widget lives in package:dartnative, so in a DartNative file those assists
never appear. This plugin re-implements them against DartNative's types.
It also turns the DartNative behaviours that fail silently or crash at mount into analyzer warnings, so they are caught while typing instead of on a device.
Setup #
In the analysis_options.yaml at the root of your project:
plugins:
dartnative_assists: ^0.1.1
Restart the Dart Analysis Server once (Android Studio: Tools › Dart › Restart Dart Analysis Server; VS Code: "Dart: Restart Analysis Server"). The first restart after enabling builds the plugin isolate and takes a few seconds.
Requires Dart 3.11 or later; the DartNative dn toolchain ships a newer SDK.
Assists #
With the cursor on a widget creation (the type name or anywhere in its arguments):
| Assist | Result |
|---|---|
| Wrap with Center / Container / SizedBox / Expanded / Flexible / SafeArea / GestureDetector / GlassEffectContainer | Name(child: …) |
| Wrap with Padding | Padding(padding: const EdgeInsets.all(8.0), child: …) |
| Wrap with Column / Row / Stack | multi-line children: [ … ] |
| Wrap with Builder | Builder(builder: (context) => …) |
| Wrap with FutureBuilder / StreamBuilder / ValueListenableBuilder | …builder: (context, snapshot) => … |
| Wrap with widget… | a wrapper name you type |
| Remove this widget | replaces a wrapper with its single child |
| Swap with child / Swap with parent | exchanges two single-child: widgets, keeping their other arguments |
| Convert to children: / Convert to child: | switches between the two slots |
| Move widget up / down | reorders inside a children: list |
With the cursor on a class header line:
| Assist | Result |
|---|---|
| Convert to StatefulWidget | constructors and final fields stay on the widget; other members move to _XState; field references become widget.x, statics become X.y, $x interpolations become ${widget.x} |
| Convert to StatelessWidget | merges the State back; offered only when the State has no lifecycle overrides, mixins, or setState calls |
Warnings (on by default) #
| Rule | What it catches |
|---|---|
dartnative_fab_slot_android_only |
Scaffold.floatingActionButton, which renders on Android and shows nothing on iOS |
dartnative_menu_action_must_be_alone |
a BarButtonItem with menu: beside other actions, which asserts at mount |
dartnative_uniform_border_only |
per-side Border(...), which DartNative ignores in favour of top |
dartnative_mirror_text_controller |
a TextField with a controller and no onChanged; the controller is one-way. Quick fix adds the mirror |
dartnative_custom_paint_finite_size |
CustomPaint(size: Size(double.infinity, …)), which paints off-screen |
dartnative_positioned_must_be_outermost |
a wrapper above Positioned in a Stack, which is dropped |
dartnative_snackbar_action_not_wired |
SnackBarAction.onPressed, which never fires |
Opt-in lint:
| Rule | What it catches |
|---|---|
dartnative_offstage_loses_state |
Offstage, which unmounts its child in DartNative |
Enable it under the plugin entry:
plugins:
dartnative_assists:
version: ^0.1.1
diagnostics:
dartnative_offstage_loses_state: true
Suppress any rule on a line with // ignore: dartnative_assists/<rule>.
Development #
dart pub get
dart test # resolves against a stub package:dartnative, no SDK needed
dart analyze
tool/try_assists.dart runs the assists against a real file inside a
DartNative project:
dart run tool/try_assists.dart path/to/app/lib/main.dart --find "Text(" --apply 1
The analysis_server_plugin and analyzer dependencies move in lockstep
with the Dart SDK. After a dn upgrade, run dart pub upgrade and the tests.
When the plugin is enabled from a local path: and you change its source,
the analysis server keeps running the isolate it already compiled. Delete
~/.dartServer/.plugin_manager and restart the server to pick up the change.
An "error occurred while executing an analyzer plugin" line during
dn analyze after an edit is that stale isolate, not a bug in the change.
Sources of the rules #
Each warning encodes one fact from the DartNative widget reference or from
on-device testing on DartNative 1.0.0 (September 2026). The rule's
description names which. If DartNative changes a behaviour, the rule should
be retired rather than kept as folklore.