call method

FutureOr<T> call([
  1. Map<String, dynamic>? parameters
])

Performs the injection.

You can add locators on top of pre-existing ones. No overriding.

  • Use locator to locate args by Param.
  • Use parameters to manually provide named args by Symbol.

Example:

final userInjector = Injector(User.new, parameters: userJson);
final user = userInjector({'id': 1, 'name': 'John'});

Implementation

FutureOr<T> call([Map<String, dynamic>? parameters]) {
  if (!hasParams) return this.create();

  if (this.parameters != null || parameters != null) {
    parameters = {...?this.parameters, ...?parameters};
  }

  final futures = <Future>[];

  locate(Param param) {
    try {
      return parameters?['${param.name ?? param.index}'] ??
          parameters?[param.type] ??
          locator?.call(param) ??
          defaultLocator?.call(param);
    } catch (e, s) {
      if (kDebugMode) {
        log('Throwed while locating $param',
            name: 'Injector', error: e, stackTrace: s);
      }
      if (e is TypeError && !param.hasDefaultValue) {
        throw InjectorError.from(e, this);
      }
      return null;
    }
  }

  final positionalArgs = [];

  for (final param in _positional) {
    final arg = locate(param);

    if (arg == null && param.hasDefaultValue) continue;

    if (arg is Future && !param.isFuture) {
      // we cant use `param.index` here because of optionals
      final index = (positionalArgs.length += 1) - 1;
      futures.add(Future(() async => positionalArgs[index] = await arg));
    } else {
      positionalArgs.add(arg);
    }
  }

  final namedArgs = <Symbol, dynamic>{};

  for (final param in _named) {
    final arg = locate(param);

    if (arg == null && param.hasDefaultValue) continue;

    if (arg is Future && !param.isFuture) {
      futures.add(Future(() async => namedArgs[param.symbol] = await arg));
    } else {
      namedArgs[param.symbol] = arg;
    }
  }

  FutureOr<T> create() {
    try {
      return Function.apply(this.create, positionalArgs, namedArgs);
    } on TypeError catch (e) {
      throw InjectorError.from(e, this);
    }
  }

  if (futures.isEmpty) return create();

  return Future.wait(futures).then((_) => create());
}