Source gen to enhance projects using grumpy or grumpy_flutter.
grumpy_gen can generate typed route helpers for any library that declares exactly one concrete RootModule.
If the root also extends AppModule, the generated output includes Flutter navigation helpers on BuildContext. Otherwise it generates only the generic static path API.
- Add a
partdirective to the library that contains the root module. - Run
dart run build_runner build.
Example:
import 'package:grumpy_flutter/grumpy_flutter.dart';
part 'app.routes.dart';
class App extends AppModule<AppConfig> {
App(super.cfg);
@override
List<FlutterRoute<AppConfig>> get routes => [
ModuleRoute(path: '/settings', module: Settings()),
ScreenRoute(path: '/dashboard', view: DashboardScreen()),
];
@override
Screen get notFoundScreen => NotFoundScreen();
@override
Widget buildApp() => const Widget();
}For every RootModule, grumpy_gen emits a GrumpyRoutes static container with full-path strings.
Example usage:
final dashboard = GrumpyRoutes.dashboard;
final advancedSettings = GrumpyRoutes.settings.advanced;
final settingsPrefix = GrumpyRoutes.settings.path;For roots that also extend AppModule, grumpy_gen additionally emits a typed BuildContext extension:
context.to.dashboard();
context.to.settings.advanced();
context.to.users.id(userId).details();Parameterized path segments are represented as explicit segment methods. A route like /users/:id/details becomes:
GrumpyRoutes.users.id(userId).details
context.to.users.id(userId).details()Module boundaries without a root leaf are still generated as typed namespace objects and expose .path, but Flutter call() is intentionally not generated for them.
The generator walks all routes reachable from the root and follows:
LeafRouteScreenRouteLeafRoute.rootScreenRoute.rootModuleRouteShellScreenRouteRoute.root([...])
Path joining follows the runtime router semantics:
ShellScreenRoutecontributes no path segmentModuleRoutedescendants are rooted under the module boundary path- nested children are flattened into full absolute paths
Route generation is intentionally static in v1. The generator currently expects route trees to be declared with direct constructor calls and list literals.
Supported:
@override
List<FlutterRoute<AppConfig>> get routes => [
ScreenRoute(path: '/dashboard', view: DashboardScreen()),
ModuleRoute(path: '/slots', module: Slots()),
];Not supported:
@override
List<FlutterRoute<AppConfig>> get routes => buildRoutes();or route lists built with control flow or spreads.
If a library contains multiple concrete RootModule implementations, generation fails with a clear error.