bloc_event_status_generator 1.1.0 copy "bloc_event_status_generator: ^1.1.0" to clipboard
bloc_event_status_generator: ^1.1.0 copied to clipboard

Code generator for bloc_event_status: turns a @blocEventStatus-annotated Bloc into a typed Emitter extension with one method per event status.

BlocEventStatusGenerator #

BlocEventStatusGenerator CI pub package pub points pub monthly downloads pub Likes License: MIT

Code generation for bloc_event_status: annotate a Bloc and get a typed Emitter extension, one method per status.

Installation #

dart pub add bloc_event_status
dart pub add --dev bloc_event_status_generator build_runner

Overview #

Emitting an event status by hand means rebuilding the state on every call:

emit(
  state.copyWith(
    eventStatuses: state.eventStatuses.update(event, const LoadingEventStatus()),
  ),
);

The usual fix is a hand-written Emitter extension (see the bloc_event_status README), which has to be kept in sync with your status type by hand. This package writes that extension for you:

emit.loading(event, state);

Getting Started #

Step 1: Annotate your Bloc #

Add the part directive and the @blocEventStatus annotation:

import 'package:bloc/bloc.dart';
import 'package:bloc_event_status/bloc_event_status.dart';

part 'todo_bloc.bes.g.dart';

@blocEventStatus
class TodoBloc extends Bloc<TodoEvent, TodoState> {
  TodoBloc() : super(const TodoState()) {
    on<AddTodo>(_onAddTodo);
  }

  Future<void> _onAddTodo(AddTodo event, Emitter<TodoState> emit) async {
    emit.loading(event, state);

    try {
      final todos = await _repository.add(event.title);
      emit.success(event, state.copyWith(todos: todos));
    } on Exception catch (e) {
      emit.failure(event, state, e.toString());
    }
  }
}

Step 2: Run the generator #

dart run build_runner build

Or, while developing:

dart run build_runner watch

The builder is applied automatically to any package that depends on it (auto_apply: dependents) and writes *.bes.g.dart next to the source file, so no build.yaml is required in your project.

Requirements #

The generator reads everything it needs from your existing types. For a @blocEventStatus-annotated class it expects:

Requirement Why
The class extends Bloc<TEvent, TState> TEvent and TState are read from the supertype.
TState uses EventStatusesMixin<TEvent, TStatus> TStatus is read from the mixin.
TState has a copyWith({eventStatuses}) The generated helper emits state.copyWith(eventStatuses: ...).
TStatus has concrete subtypes in the same library One method is generated per concrete subtype.
A part '<file>.bes.g.dart'; directive The extension is generated as a part of your file.

A complete, runnable setup lives in example/lib/main.dart.

If any of these is missing, the build fails with an explicit message — for example State class must use EventStatusesMixin<TEvent, TStatus>. or No concrete subtypes found for EventStatus.

What Gets Generated #

Given this status type and state:

sealed class EventStatus extends Equatable {
  const EventStatus();

  @override
  List<Object?> get props => [];
}

class LoadingEventStatus extends EventStatus {
  const LoadingEventStatus();
}

class SuccessEventStatus extends EventStatus {
  const SuccessEventStatus();
}

class FailureEventStatus extends EventStatus {
  const FailureEventStatus(this.message);
  final String message;

  @override
  List<Object?> get props => [message];
}

class TodoState extends Equatable
    with EventStatusesMixin<TodoEvent, EventStatus> {
  const TodoState({
    this.todos = const [],
    this.eventStatuses = const EventStatuses(),
  });

  final List<String> todos;

  @override
  final EventStatuses<TodoEvent, EventStatus> eventStatuses;

  TodoState copyWith({
    List<String>? todos,
    EventStatuses<TodoEvent, EventStatus>? eventStatuses,
  }) { /* ... */ }

  @override
  List<Object?> get props => [todos, eventStatuses];
}

todo_bloc.bes.g.dart contains:

extension $TodoBlocEmitterX on Emitter<TodoState> {
  void _emitEventStatus<T extends TodoEvent>(
    T event,
    EventStatus status,
    TodoState state,
  ) {
    this(
      state.copyWith(
        eventStatuses: state.eventStatuses.update(event, status),
      ),
    );
  }

  void loading<T extends TodoEvent>(T event, TodoState state) =>
      _emitEventStatus(event, const LoadingEventStatus(), state);

  void success<T extends TodoEvent>(T event, TodoState state) =>
      _emitEventStatus(event, const SuccessEventStatus(), state);

  void failure<T extends TodoEvent>(T event, TodoState state, String message) =>
      _emitEventStatus(event, FailureEventStatus(message), state);
}

Every method takes the event and the state to emit, plus whatever its status constructor needs.

Method names #

The method name is the subtype name with the prefix and suffix it shares with the base status type stripped, lowerCamelCased:

Status base type Concrete subtype Method
EventStatus LoadingEventStatus loading
CounterEventStatus LoadingEventStatus loading
CustomEventStatus CustomSuccessEventStatus success

Constructor parameters #

Status constructor parameters are forwarded as-is, keeping their kind and defaults:

  • required positional → required positional on the method
  • optional positional (with or without default) → optional positional
  • required named → required named
  • optional named (with or without default) → optional named
  • generic type parameters (including bounds) → declared on the method, forwarded to the constructor
  • a const constructor with no arguments → const instantiation in the generated call

Troubleshooting #

Version solving fails on analyzer. Every analyzer release is breaking, so build, build_runner and every generator pin a range. If pub reports that bloc_event_status_generator is forbidden, make sure you are on the latest version of this package — analyzer upper bounds are widened as new releases land. Version 1.1.0 supports analyzer >=8.0.0 <15.0.0 (build_runner up to 2.16.x).

Nothing is generated. Check that the file declares part '<file>.bes.g.dart'; and that the annotated class is a Bloc subclass. dart run build_runner build --verbose shows which builders ran.

--delete-conflicting-outputs is ignored. Recent build_runner versions dropped that option and log a warning when it is passed; plain dart run build_runner build is enough.

VS Code tip #

To keep generated *.g.dart files nested under their source file in the Explorer, add this to your .vscode/settings.json:

{
  "explorer.fileNesting.patterns": {
    "*.dart": "${capture}*.g.dart"
  }
}
0
likes
160
points
94
downloads

Documentation

Documentation
API reference

Publisher

verified publisherjacopoguzzo.dev

Weekly Downloads

Code generator for bloc_event_status: turns a @blocEventStatus-annotated Bloc into a typed Emitter extension with one method per event status.

Repository (GitHub)
View/report issues

Topics

#bloc #state-management #code-generation

License

MIT (license)

Dependencies

analyzer, bloc_event_status, build, source_gen

More

Packages that depend on bloc_event_status_generator