2021-04-28 09:30:32 +03:00
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
2021-04-21 08:05:38 +03:00
import ' dart:collection ' ;
2021-10-20 09:15:51 +03:00
import ' package:cherrypick/src/binding.dart ' ;
import ' package:cherrypick/src/module.dart ' ;
2021-04-21 08:05:38 +03:00
Scope openRootScope ( ) = > Scope ( null ) ;
class Scope {
final Scope ? _parentScope ;
2021-04-22 10:25:38 +03:00
/// RU: Метод возвращает родительский [Scope].
///
/// ENG: The method returns the parent [Scope].
///
/// return [Scope]
2021-04-21 08:05:38 +03:00
Scope ? get parentScope = > _parentScope ;
final Map < String , Scope > _scopeMap = HashMap ( ) ;
Scope ( this . _parentScope ) ;
final Set < Module > _modulesList = HashSet ( ) ;
2021-04-22 10:25:38 +03:00
/// RU: Метод открывает дочерний (дополнительный) [Scope].
///
/// ENG: The method opens child (additional) [Scope].
///
/// return [Scope]
2021-04-21 08:05:38 +03:00
Scope openSubScope ( String name ) {
if ( ! _scopeMap . containsKey ( name ) ) {
2021-04-23 10:34:33 +03:00
_scopeMap [ name ] = Scope ( this ) ;
2021-04-21 08:05:38 +03:00
}
return _scopeMap [ name ] ! ;
}
2021-04-22 10:25:38 +03:00
/// RU: Метод закрывает дочерний (дополнительный) [Scope].
///
/// ENG: The method closes child (additional) [Scope].
///
/// return [Scope]
2021-04-21 08:05:38 +03:00
void closeSubScope ( String name ) {
_scopeMap . remove ( name ) ;
}
2021-04-22 10:25:38 +03:00
/// RU: Метод инициализирует пользовательские модули в [Scope].
///
/// ENG: The method initializes custom modules in [Scope].
///
/// return [Scope]
2021-04-21 08:05:38 +03:00
Scope installModules ( List < Module > modules ) {
_modulesList . addAll ( modules ) ;
modules . forEach ( ( module ) = > module . builder ( this ) ) ;
return this ;
}
2021-04-22 10:25:38 +03:00
/// RU: Метод удаляет пользовательские модули из [Scope].
///
/// ENG: This method removes custom modules from [Scope].
///
/// return [Scope]
2021-04-21 08:05:38 +03:00
Scope dropModules ( ) {
2023-01-27 16:02:49 +03:00
// [AlexeyYuPopkov](https://github.com/AlexeyYuPopkov) Thank you for the [Removed exception "ConcurrentModificationError"](https://github.com/pese-git/cherrypick/pull/2)
_modulesList . clear ( ) ;
2021-04-21 08:05:38 +03:00
return this ;
}
2021-04-22 10:25:38 +03:00
/// RU: Возвращает найденную зависимость, определенную параметром типа [T].
/// Выдает [StateError], если зависимость не может быть разрешена.
/// Если вы хотите получить [null], если зависимость не может быть найдена,
/// то используйте вместо этого [tryResolve]
/// return - возвращает объект типа [T] или [StateError]
///
/// ENG: Returns the found dependency specified by the type parameter [T].
/// Throws [StateError] if the dependency cannot be resolved.
/// If you want to get [null] if the dependency cannot be found then use [tryResolve] instead
/// return - returns an object of type [T] or [StateError]
///
2023-01-04 11:03:29 +03:00
T resolve < T > ( { String ? named , dynamic params } ) {
var resolved = tryResolve < T > ( named: named , params: params ) ;
2021-04-21 08:05:38 +03:00
if ( resolved ! = null ) {
return resolved ;
} else {
throw StateError (
' Can \' t resolve dependency ` $ T `. Maybe you forget register it? ' ) ;
}
}
2021-04-22 10:25:38 +03:00
/// RU: Возвращает найденную зависимость типа [T] или null, если она не может быть найдена.
/// ENG: Returns found dependency of type [T] or null if it cannot be found.
///
2023-01-04 11:03:29 +03:00
T ? tryResolve < T > ( { String ? named , dynamic params } ) {
2021-04-21 08:05:38 +03:00
// 1 Поиск зависимости по всем модулям текущего скоупа
if ( _modulesList . isNotEmpty ) {
2021-04-29 10:02:32 +03:00
for ( var module in _modulesList ) {
for ( var binding in module . bindingSet ) {
2021-04-21 08:05:38 +03:00
if ( binding . key = = T & &
( ( ! binding . isNamed & & named = = null ) | |
( binding . isNamed & & named = = binding . name ) ) ) {
switch ( binding . mode ) {
case Mode . INSTANCE:
return binding . instance ;
case Mode . PROVIDER_INSTANCE:
2021-04-30 16:42:39 +03:00
return binding . provider ;
2022-08-10 17:23:54 +03:00
case Mode . PROVIDER_WITH_PARAMS_INSTANCE:
2023-01-04 11:03:29 +03:00
if ( params = = null ) {
throw StateError ( ' Param is null. Maybe you forget pass it ' ) ;
2022-08-10 17:23:54 +03:00
}
2023-01-04 11:03:29 +03:00
return binding . providerWithParams ( params ) ;
2021-04-21 08:05:38 +03:00
default :
return null ;
}
}
}
}
}
// 2 Поиск зависимостей в родительском скоупе
2021-04-21 08:25:55 +03:00
return _parentScope ! = null ? _parentScope ! . tryResolve ( named: named ) : null ;
2021-04-21 08:05:38 +03:00
}
}