agentsclimarketplace

Dart

Skill ndisisnd/cook/standards/dart

Dart 3.x language standards and code quality conventions. Use when writing or reviewing any Dart code — null safety, patterns, sealed classes, records, class modifiers, naming, immutability, collections, async, and import organisation.From its SKILL.md

Install
npx -y skills add ndisisnd/cook --skill dart

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

9.0 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it

Dart Standards

Priority: P0 — Language Correctness

Null Safety

  • Avoid !. Prefer local promotion, null-check patterns, and private final fields.
  • Use ! only for documented invariants or framework/external boundaries where non-null is guaranteed but not expressible to the analyzer.
  • Prefer ?., ??, and null-aware patterns over forced unwrapping.
  • AVOID late if you need to check whether the variable was initialised — use nullable + null-check instead.
  • DON'T explicitly initialise variables to null; let the type system express optionality.

Immutability

  • Use const > final > var. Use @freezed for data classes.
  • Prefer final for all class members. Use var only for locally-obvious short-lived locals.
  • AVOID public late final fields without initializers.

Pattern Matching (Dart 3.x)

Use switch expressions with exhaustive patterns and destructuring. Supported pattern types:

PatternExample
Constantcase 42:
Variablecase var x:
Wildcardcase _:
Objectcase Circle(radius: var r):
Recordcase (String name, int age):
Listcase [first, ...rest]:
Mapcase {'key': var v}:
Logical-or`case 1
Guardcase var x when x > 0:
String describe(Shape s) => switch (s) {
  Circle(radius: var r) when r > 10 => 'large circle',
  Circle(radius: var r) => 'circle r=$r',
  Rectangle(width: var w, height: var h) => '${w}x$h rect',
};

Records

  • Use records for returning multiple values: (String, int).
  • Use named fields for clarity beyond two elements: ({String name, int age}).

Class Modifiers (Dart 3.x)

Choose the right modifier to express API intent explicitly:

ModifierExtends outside libImplements outside libUse for
sealednonoExhaustive domain state (enables exhaustive switch)
finalnonoClosed hierarchy — no extension or implementation
baseyesnoAllow inheritance, prevent external implementation
interfacenoyesPure contracts — implementation only
  • sealed is implicitly abstract; direct subtypes must be in the same library for exhaustive switching.
  • Subclasses of a sealed class are not implicitly abstract — mark each subtype intentionally.
  • Use final instead of sealed when you want to close external subtyping but still add subtypes later without breaking exhaustive switches.
sealed class AuthState {}
final class Authenticated extends AuthState { final User user; Authenticated(this.user); }
final class Unauthenticated extends AuthState {}

Mixins

  • Use mixin for behaviour shared across unrelated class hierarchies.
  • Use mixin class (Dart 3.0) when the type must also be usable as a standalone class.
  • Prefer mixin over abstract class when no constructor is needed.

Enhanced Enums (Dart 2.17+)

Enums can have fields, constructors, and methods. Prefer over utility classes with static constants.

enum Status {
  active('Active'),
  inactive('Inactive');

  const Status(this.label);
  final String label;
}

Extensions

  • Use extension to add utility methods to third-party or built-in types.
  • Always name extensions (extension StringX on String) — unnamed extensions are harder to import selectively.

Wildcards (Dart 3.7+)

Use _ for unused variables in declarations and patterns.

Async

  • Prefer async/await over raw Future.then.
  • Use unawaited() for intentional fire-and-forget; never silently discard a future.
  • DON'T mark a function async if it contains no await — it adds overhead with no benefit.
  • AVOID using Completer directly; prefer async/await or StreamController.
  • AVOID FutureOr<T> as a return type.
  • AVOID returning nullable Future, Stream, or collection types from public APIs.
  • Cancel StreamSubscriptions and close owned StreamControllers or Sinks.
  • Avoid async void except for framework callbacks that require void.

Error Handling

  • Use on ExceptionType catch (e) — never bare catch without on (swallows everything).
  • DON'T silently discard caught errors.
  • Throw Error subclasses only for programmatic errors (bugs). Use Exception for recoverable runtime conditions.
  • Use rethrow to re-propagate after partial handling; never re-throw the caught object manually.
  • Use assert() for development-time invariants — stripped in production.

Types

  • No dynamic. Use Object, Object?, or generics.
  • Annotate return types and parameter types on all public declarations.
  • DON'T redundantly annotate initialised local variables — let inference work.
  • Use typedef for named type aliases (typedef UserId = String). Prefer inline function type syntax in parameter positions over typedef.

Members & Constructors

  • Use initializing formals: const User({required this.name}).
  • Use ; not {} for empty constructor bodies.
  • Never use new.
  • DON'T use this. except to redirect constructors or avoid shadowing.
  • DON'T perform complex calculations or async work inside constructors.
  • Use a getter for pure computations: int get invoiceTotal => not int calcTotal().

Equality

  • If you override operator ==, override hashCode.
  • Equality must be reflexive, symmetric, transitive, and stable over time.
  • Avoid custom equality on mutable classes; prefer immutable value types.
  • Use identical(this, other) as the fast path before structural comparison.

Priority: P1 — Style & Conventions

Naming

  • Types and extensions: UpperCamelCase
  • Members, variables, parameters: lowerCamelCase
  • Files, packages, directories: lowercase_with_underscores
  • Import prefixes: lowercase_with_underscores
  • Constants: prefer lowerCamelCase (not SCREAMING_CAPS) unless matching generated or existing code style.
  • Capitalise acronyms longer than two letters as words: HttpRequest, parseUrl
  • DON'T use a leading _ on non-private identifiers.
  • Name value-object converters for their target context: get apiFilterType not get filterType.

Scoping

  • No top-level mutable state. Encapsulate in a class or inject via DI.
  • Library-private identifiers use _ prefix.

Strings

  • Prefer single quotes. Use double quotes only when the string itself contains a single quote.
  • Prefer interpolation over concatenation: 'Hello $name' not 'Hello ' + name.
  • Adjacent string literals can be concatenated without +.
  • Omit curly braces in interpolation unless required: '$name' not '${name}'.

Trailing Commas

Always use trailing commas for multi-line argument lists and collection literals.

Expression Bodies

Prefer => for single-expression functions and getters.

Collections

  • Use .isEmpty / .isNotEmpty — never .length == 0.
  • Use collection if, for, and spread ... for composable collections.
  • Type empty collections explicitly: <String>[], <String, User>{}.
  • Prefer .map, .where, .fold, .any over manual loops where clarity wins.
  • Use .firstOrNull, .lastOrNull, .elementAtOrNull(i) for safe indexed access.
  • DON'T use Iterable.forEach() with a function literal — use for loops or tear-offs.
  • DON'T use cast() when a nearby operation will do.

Imports

  • Group order: dart:package: → relative. Sort each section alphabetically.
  • Use relative imports for intra-package files; never package:app/... within the same package.
  • Specify exports in a separate section after all imports.

Tear-offs

Prefer list.forEach(print) over list.forEach((e) => print(e)).


Anti-Patterns

  • ! without a documented invariant, local promotion alternative, or framework boundary
  • Overriding == without hashCode
  • Custom equality on mutable classes
  • var for class members
  • dynamic anywhere
  • async on a function with no await
  • async void outside framework callbacks
  • Leaked StreamSubscription, StreamController, or Sink
  • Bare catch without on
  • Global mutable state
  • new keyword
  • Package imports within the same package
  • FutureOr<T> as a return type
  • Logic or async work inside constructors
  • Zero-argument methods for pure computations — use a getter

References

Load only what the current task requires:

  • tooling — setting up or modifying analysis_options, dart format, DCM, build_runner, pubspec, coverage, CI, or pre-commit hooks
  • testing — writing or reviewing unit tests, mocks (mocktail), stream tests, or fake_async time-dependent tests

What ships with it: 3 files

7.8 KB alongside SKILL.md

refs/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.