of static method

The plan for fn on route. Throws a StateError when a parameter type is not known.

Implementation

static ControllerPlan of(Function fn, RouteData route) {
  String where = '${route.method} ${route.path}';
  List<String> types = ControllerTypes.parameters(fn, where);
  List<String> params = route.paramNames;
  List<ControllerArg> args = <ControllerArg>[];
  int paths = 0;
  bool hasDto = false;
  for (int i = 0; i < types.length; i++) {
    String type = types[i];
    bool nullable = type.endsWith('?');
    String name = nullable ? type.substring(0, type.length - 1) : type;
    if (name == 'DoxRequest' || name == 'IDoxRequest') {
      args.add(const ControllerArg(ArgKind.request));
      continue;
    }
    // an untyped first parameter `(req)` is the request
    if (name == 'dynamic' && i == 0 && !types.contains('DoxRequest')) {
      args.add(const ControllerArg(ArgKind.request));
      continue;
    }
    PathType? pathType = name == 'dynamic' || name == 'Object'
        ? PathType.string
        : _pathTypes[name];
    if (pathType != null) {
      if (paths >= params.length) {
        throw StateError(
          'Route $where: the controller has more path params than the '
          'route has {...} params (${params.length}).',
        );
      }
      args.add(
        ControllerArg(
          ArgKind.path,
          pathType: pathType,
          nullable: nullable || name == 'dynamic',
          param: params[paths++],
        ),
      );
      continue;
    }
    DtoSchema<Object>? dto = Dox().dtos.ofName(name);
    if (dto == null) {
      throw StateError(
        'Route $where: the controller parameter type $type is not known. '
        'Use DoxRequest, a @Dto class, or String, int, double, num, bool '
        'for path params. For a DTO: did you run '
        '`dart run build_runner build` and set `dtos: dtos` in AppConfig?',
      );
    }
    if (hasDto) {
      throw StateError('Route $where: a controller can have one @Dto only.');
    }
    hasDto = true;
    args.add(ControllerArg(ArgKind.dto, dto: dto));
  }
  return ControllerPlan(fn, args);
}