call method
Performs the injection.
You can add locators on top of pre-existing ones. No overriding.
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());
}