docs(observer): improve documentation, translate all comments to English, add usage examples

This commit is contained in:
Sergey Penkovsky
2025-08-11 23:47:17 +03:00
parent 12b97c9368
commit 125bccfa5a
2 changed files with 120 additions and 58 deletions

View File

@@ -1,55 +0,0 @@
//
// 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
// https://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.
//
/// Formats a log message string for CherryPick's logging system.
///
/// This function provides a unified structure for framework logs (info, warn, error, debug, etc.),
/// making it easier to parse and analyze events related to DI operations such as resolving bindings,
/// scope creation, module installation, etc.
///
/// All parameters except [name] and [params] are required.
///
/// Example:
/// ```dart
/// final msg = formatLogMessage(
/// type: 'Binding',
/// name: 'MyService',
/// params: {'parent': 'AppModule', 'lifecycle': 'singleton'},
/// description: 'created',
/// );
/// // Result: [Binding:MyService] parent=AppModule lifecycle=singleton created
/// ```
///
/// Parameters:
/// - [type]: The type of the log event subject (e.g., 'Binding', 'Scope', 'Module'). Required.
/// - [name]: Optional name of the subject (binding/scope/module) to disambiguate multiple instances/objects.
/// - [params]: Optional map for additional context (e.g., id, parent, lifecycle, named, etc.).
/// - [description]: Concise description of the event. Required.
///
/// Returns a structured string:
/// [type(:name)] param1=val1 param2=val2 ... description
String formatLogMessage({
required String type, // Binding, Scope, Module, ...
String? name, // Имя binding/scope/module
Map<String, Object?>? params, // Дополнительные параметры (id, parent, named и др.)
required String description, // Краткое описание события
}) {
final label = name != null ? '$type:$name' : type;
final paramsStr = (params != null && params.isNotEmpty)
? params.entries.map((e) => '${e.key}=${e.value}').join(' ')
: '';
return '[$label]'
'${paramsStr.isNotEmpty ? ' $paramsStr' : ''}'
' $description';
}

View File

@@ -1,31 +1,148 @@
/// Observer for DI container (CherryPick): lifecycle, cache, modules, errors, etc.
//
// 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
// https://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.
//
/// An abstract Observer for CherryPick DI container events.
///
/// Extend this class to react to and log various events inside the CherryPick Dependency Injection container.
/// Allows monitoring of registration, creation, disposal, module changes, cache hits/misses, cycles, and
/// errors/warnings for improved diagnostics and debugging.
///
/// All methods have detailed event information, including name, type, scope, and other arguments.
///
/// Example: Logging and debugging container events
/// ```dart
/// final CherryPickObserver observer = PrintCherryPickObserver();
/// // Pass observer to CherryPick during setup
/// CherryPick.openRootScope(observer: observer);
/// ```
abstract class CherryPickObserver {
// === Registration and instance lifecycle ===
/// Called when a binding is registered within the container (new dependency mapping).
///
/// Example:
/// ```dart
/// observer.onBindingRegistered('MyService', MyService, scopeName: 'root');
/// ```
void onBindingRegistered(String name, Type type, {String? scopeName});
/// Called when an instance is requested (before it is created or retrieved from cache).
///
/// Example:
/// ```dart
/// observer.onInstanceRequested('MyService', MyService, scopeName: 'root');
/// ```
void onInstanceRequested(String name, Type type, {String? scopeName});
/// Called when a new instance is successfully created.
///
/// Example:
/// ```dart
/// observer.onInstanceCreated('MyService', MyService, instance, scopeName: 'root');
/// ```
void onInstanceCreated(String name, Type type, Object instance, {String? scopeName});
/// Called when an instance is disposed (removed from cache and/or finalized).
///
/// Example:
/// ```dart
/// observer.onInstanceDisposed('MyService', MyService, instance, scopeName: 'root');
/// ```
void onInstanceDisposed(String name, Type type, Object instance, {String? scopeName});
// === Module events ===
/// Called when modules are installed into the container.
///
/// Example:
/// ```dart
/// observer.onModulesInstalled(['NetworkModule', 'RepositoryModule'], scopeName: 'root');
/// ```
void onModulesInstalled(List<String> moduleNames, {String? scopeName});
/// Called when modules are removed from the container.
///
/// Example:
/// ```dart
/// observer.onModulesRemoved(['RepositoryModule'], scopeName: 'root');
/// ```
void onModulesRemoved(List<String> moduleNames, {String? scopeName});
// === Scope lifecycle ===
/// Called when a new DI scope is opened (for example, starting a new feature or screen).
///
/// Example:
/// ```dart
/// observer.onScopeOpened('user-session');
/// ```
void onScopeOpened(String name);
/// Called when an existing DI scope is closed.
///
/// Example:
/// ```dart
/// observer.onScopeClosed('user-session');
/// ```
void onScopeClosed(String name);
// === Cycle detection ===
/// Called if a dependency cycle is detected during resolution.
///
/// Example:
/// ```dart
/// observer.onCycleDetected(['A', 'B', 'C', 'A'], scopeName: 'root');
/// ```
void onCycleDetected(List<String> chain, {String? scopeName});
// === Cache events ===
/// Called when an instance is found in the cache.
///
/// Example:
/// ```dart
/// observer.onCacheHit('MyService', MyService, scopeName: 'root');
/// ```
void onCacheHit(String name, Type type, {String? scopeName});
/// Called when an instance is not found in the cache and should be created.
///
/// Example:
/// ```dart
/// observer.onCacheMiss('MyService', MyService, scopeName: 'root');
/// ```
void onCacheMiss(String name, Type type, {String? scopeName});
// === Диагностика ===
// === Diagnostic ===
/// Used for custom diagnostic and debug messages.
///
/// Example:
/// ```dart
/// observer.onDiagnostic('Cache cleared', details: detailsObj);
/// ```
void onDiagnostic(String message, {Object? details});
// === Warnings & errors ===
/// Called on non-fatal, recoverable DI container warnings.
///
/// Example:
/// ```dart
/// observer.onWarning('Binding override', details: {...});
/// ```
void onWarning(String message, {Object? details});
/// Called on error (typically exceptions thrown during resolution, instantiation, or disposal).
///
/// Example:
/// ```dart
/// observer.onError('Failed to resolve dependency', errorObj, stackTraceObj);
/// ```
void onError(String message, Object? error, StackTrace? stackTrace);
}
@@ -86,7 +203,7 @@ class PrintCherryPickObserver implements CherryPickObserver {
}
}
/// Silent observer: игнорирует все события
/// Silent observer: ignores all events
class SilentCherryPickObserver implements CherryPickObserver {
@override
void onBindingRegistered(String name, Type type, {String? scopeName}) {}