mix_lint 2.0.1 copy "mix_lint: ^2.0.1" to clipboard
mix_lint: ^2.0.1 copied to clipboard

Analyzer plugin with lint rules and quick fixes for Mix, the Flutter styling framework. Catches Styler, variant, and design-token mistakes.

mix_lint #

Lint rules and quick fixes for Mix, the Flutter styling framework. mix_lint is an analyzer plugin: it reports problems in your IDE and in dart analyze / flutter analyze.

Requires Dart 3.12 or later (Flutter 3.44 or later).

Setup #

Add the plugin to the top-level plugins section of your analysis_options.yaml. You do not need to add mix_lint to pubspec.yaml; the analysis server downloads it.

plugins:
  mix_lint: ^2.0.1

Then restart the analysis server (or your IDE). Restart it again after any change to the plugins section.

Rules #

Warnings catch bugs and are on by default. Lints enforce Mix style and are off until you enable them.

Rule Kind Fix Checks that
missing_create_constructor Warning @Mixable and @MixableStyler classes have a .create constructor
token_reference_outside_mix Warning token references are only passed to Mix APIs
base_style_after_variant Lint base style calls come before variants
inline_token_definition Lint tokens are not created inside Stylers or MixScope
long_styler_chain Lint Styler chains stay short
unnecessary_styler_constructor Lint Yes nested Stylers use dot shorthands, such as .color(...)
unnecessary_type_name Lint Yes Styler arguments use dot shorthands
variants_without_base_style Lint Stylers set a base style before variants

Quick fixes run in the IDE only; dart fix does not apply plugin fixes. A fix can leave an import unused, which the analyzer then reports as unused_import.

Enable lints and change severity #

List rules under diagnostics. Use true to enable a lint with its default severity, error, warning, or info to set the severity, and false to turn off a rule (including a warning).

plugins:
  mix_lint:
    version: ^2.0.1
    diagnostics:
      base_style_after_variant: true
      inline_token_definition: true
      long_styler_chain: true
      unnecessary_styler_constructor: true
      unnecessary_type_name: true
      variants_without_base_style: true
      token_reference_outside_mix: error

Suppress a diagnostic #

Prefix the rule name with the plugin name:

// ignore: mix_lint/base_style_after_variant
final style = BoxStyler().onHovered(.color(Colors.blue)).padding(.all(16));

Use // ignore_for_file: mix_lint/<rule> for a whole file.

Plugins skip files excluded in analysis_options.yaml. To keep lints out of generated code:

analyzer:
  exclude:
    - "**/*.g.dart"

Configure rules #

Rules that take options read them from a top-level mix_lint: section of the same analysis_options.yaml. The analyzer passes plugins only diagnostics settings, so options go in this separate section.

plugins:
  mix_lint:
    version: ^2.0.1
    diagnostics:
      long_styler_chain: true

mix_lint:
  long_styler_chain:
    max_calls: 20

long_styler_chain takes max_calls, the most calls allowed in one chain (default 15).

Each library uses the nearest analysis_options.yaml above its file. mix_lint follows include: entries, by relative path or package: URI, and values in the including file win. In a pub workspace, put plugins: and mix_lint: in the root options file and have each member include it.

Rule reference #

missing_create_constructor #

Warning. A class annotated with @Mixable or @MixableStyler has no .create constructor. The generated merge() method calls .create, so the generated code does not compile without it. The rule stays silent when the annotation turns off merge() generation (for example methods: GeneratedMixMethods.skipMerge).

Don't:

@Mixable()
final class ShadowMix extends Mix<Shadow> with Diagnosticable, _$ShadowMixMixin {
  final Prop<Color>? $color;

  ShadowMix({Color? color}) : $color = Prop.maybe(color);
}

Do:

@Mixable()
final class ShadowMix extends Mix<Shadow> with Diagnosticable, _$ShadowMixMixin {
  final Prop<Color>? $color;

  ShadowMix({Color? color}) : this.create(color: Prop.maybe(color));

  const ShadowMix.create({Prop<Color>? color}) : $color = color;
}

For new Stylers, prefer @MixableSpec(target: Widget.new); @MixableStyler is deprecated.

token_reference_outside_mix #

Warning. Calling a token ($primary(), $primary.call(), or $body.mix()) creates a token reference. A reference only resolves inside Mix, against the surrounding MixScope. Passed to a Flutter widget or any other API outside Mix, it never resolves.

The rule reports only APIs from other packages, such as Flutter widgets and dart:core. It accepts any API that Mix declares and any Mix value type, including types generated in your package. It also stays silent for:

  • functions and widgets in your own package, because they may forward the value into Mix;
  • Flutter values passed to a Mix .value() conversion, such as TextStyleMix.value(TextStyle(color: $primary())), because Mix converts them field by field and keeps a reference that reaches it unchanged. A nested value counts only when Mix has a value type for it, such as ShadowMix for Shadow; Mix copies other values, such as FontVariation, whole.

To read a concrete value outside Mix, use token.resolve(context).

Don't:

final $primary = ColorToken('primary');

Container(color: $primary());

Do:

final $primary = ColorToken('primary');

Box(style: BoxStyler().color($primary()));
Container(color: $primary.resolve(context));

The check is syntactic: a reference stored in a variable first (final c = $primary(); Container(color: c);) is not detected.

base_style_after_variant #

A base style call, such as padding(), comes after a variant, such as onHovered(). Keep base style first and variants last so the default appearance reads in one place. animate(), keyframeAnimation(), phaseAnimation(), wrap(), modifier(), merge(), and applyVariants() may follow variants.

Don't:

final style = BoxStyler()
    .color(Colors.red)
    .onHovered(.color(Colors.blue))
    .padding(.all(16));

Do:

final style = BoxStyler()
    .color(Colors.red)
    .padding(.all(16))
    .onHovered(.color(Colors.blue))
    .animate(.easeInOut(200.ms));

inline_token_definition #

A design token is created inside a Styler chain or in the token maps of a MixScope, such as colors:. Tokens are meant to be shared: define each one once and reference it. The widget tree under child: is checked like any other code, so a token there is reported only inside a Styler chain.

Don't:

final style = BoxStyler().color(ColorToken('primary')());

MixScope(
  colors: {ColorToken('primary'): Colors.blue},
  child: child,
);

Do:

final $primary = ColorToken('primary');

final style = BoxStyler().color($primary());

MixScope(
  colors: {$primary: Colors.blue},
  child: child,
);

long_styler_chain #

A Styler chain has more calls than the limit (15 by default). Split large styles into smaller Stylers and combine them with merge(). To change the limit, set max_calls (see Configure rules).

Do:

final layout = BoxStyler().padding(.all(8)).margin(.all(4)).alignment(.center);
final surface = BoxStyler().color(Colors.blue).borderRadius(.circular(8));

final card = layout.merge(surface).onHovered(.color(Colors.red));

unnecessary_styler_constructor #

An empty Styler constructor starts a chain where a dot shorthand for the factory would do. The quick fix can also fix the whole file.

The rule reports:

  • BoxStyler().color(...) passed to another Styler method, such as a variant, where the parameter type is BoxStyler;
  • .new().color(...) anywhere.

Both become .color(...). Every generated Styler setter has a matching factory, so the result is the same.

Don't:

final style = BoxStyler()
    .color(Colors.white)
    .onHovered(BoxStyler().color(Colors.blue));

final BoxStyler card = .new().padding(.all(16));

Do:

final style = BoxStyler()
    .color(Colors.white)
    .onHovered(.color(Colors.blue));

final BoxStyler card = .padding(.all(16));

The rule doesn't report a constructor where a dot shorthand has no Styler type to resolve against: a top-level declaration such as final style = BoxStyler()..., or a widget argument such as Box(style: BoxStyler()...), whose parameter type is Style<BoxSpec>. It also stays silent when the first call has no factory, or when the factory doesn't accept the same arguments.

unnecessary_type_name #

An argument in a Styler expression names a type that dot shorthand can infer from the parameter type. A Styler expression is an argument of a Styler call, or of a Mix call nested inside one. The quick fix can also fix the whole file.

Don't:

BoxStyler().padding(EdgeInsetsGeometryMix.all(16));
TextStyler().fontWeight(FontWeight.w600);
BoxStyler().onNot(.widgetState(WidgetState.hovered), .color(Colors.grey));

Do:

BoxStyler().padding(.all(16));
TextStyler().fontWeight(.w600);
BoxStyler().onNot(.widgetState(.hovered), .color(Colors.grey));

The rule only reports a static member or named constructor of the parameter's exact type, because that is where dot shorthand looks it up. It does not report:

  • members of another type, such as Colors.blue for a Color parameter;
  • unnamed constructors, such as BoxShadowMix(...);
  • Mix code outside Styler expressions, such as final v = ContextVariant.widgetState(WidgetState.hovered);;
  • code with a language version below 3.10.

variants_without_base_style #

A Styler chain adds variants but sets no base style, so the style has no default appearance. A chain that uses onBuilder() is allowed, because it builds the whole style from context.

Don't:

final style = BoxStyler()
    .onHovered(.color(Colors.blue))
    .onPressed(.color(Colors.green));

Do:

final style = BoxStyler()
    .color(Colors.grey)
    .onHovered(.color(Colors.blue))
    .onPressed(.color(Colors.green));

Renamed rules #

mix_lint 2.0.0 used different rule names. See the migration table to update analysis_options.yaml and ignore comments.

0
likes
160
points
208
downloads

Documentation

API reference

Publisher

verified publisherleoafarias.com

Weekly Downloads

Analyzer plugin with lint rules and quick fixes for Mix, the Flutter styling framework. Catches Styler, variant, and design-token mistakes.

Homepage
Repository (GitHub)
View/report issues

Topics

#lints #analyzer #flutter #design-system

License

BSD-3-Clause (license)

Dependencies

analysis_server_plugin, analyzer, yaml

More

Packages that depend on mix_lint