deriveAutoRoute function

AutoRouteDerivation deriveAutoRoute(
  1. List<ScannedFile> files,
  2. void warn(
    1. String
    )
)

Leitet Screens aus @RoutePage()-Klassen ab; AutoRoute(page:, path:)- Einträge liefern die Pfad-Zuordnung.

Implementation

AutoRouteDerivation deriveAutoRoute(
  List<ScannedFile> files,
  void Function(String) warn,
) {
  final result = AutoRouteDerivation();

  for (final file in files) {
    for (final decl in file.unit.declarations) {
      if (decl is! ClassDeclaration) continue;
      final hasRoutePage = decl.metadata.any((a) {
        final name = a.name;
        final simple = name is PrefixedIdentifier ? name.identifier.name : name.name;
        return simple == 'RoutePage';
      });
      if (!hasRoutePage) continue;

      final className = decl.namePart.typeName.lexeme;
      final id = screenIdFromClassName(className);
      result.nodes.add(GraphNode(
        id: id,
        type: 'screen',
        title: humanize(id),
        source: SourceKind.derived,
        sourceRef: file.refAt(decl.namePart.typeName.offset, symbol: className),
      ));
      result.classToScreen.putIfAbsent(className, () => id);
    }
  }

  // AutoRoute(page: LoginRoute.page, path: '/login') — der generierte
  // Routenname entsteht aus dem Klassennamen ohne Screen/Page-Suffix + 'Route'.
  for (final file in files) {
    final collector = _AutoRouteEntryCollector();
    file.unit.accept(collector);
    for (final entry in collector.entries) {
      Expression? pageExpr;
      String? path;
      for (final arg in entry.arguments) {
        if (arg is! NamedArgument) continue;
        switch (arg.name.lexeme) {
          case 'page':
            pageExpr = arg.argumentExpression;
          case 'path':
            final expr = arg.argumentExpression;
            if (expr is StringLiteral) path = expr.stringValue;
        }
      }
      if (pageExpr == null || path == null) continue;
      final routeClass = _routeClassOfPageExpr(pageExpr);
      if (routeClass == null) continue;
      final base = routeClass.endsWith('Route')
          ? routeClass.substring(0, routeClass.length - 'Route'.length)
          : routeClass;
      final id = _kebabCase(base);
      // Nur zuordnen, wenn der Screen tatsächlich existiert (kein Dangling).
      if (result.nodes.any((n) => n.id == id)) {
        result.pathToScreen.putIfAbsent(path, () => id);
      }
    }
  }

  return result;
}