diff --git a/LICENSE b/LICENSE index ba75c69..ea3d386 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -TODO: Add your license here. +MIT License + +Copyright (c) 2022 Kek Tech + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/example/main.dart b/example/main.dart new file mode 100644 index 0000000..36cf80e --- /dev/null +++ b/example/main.dart @@ -0,0 +1,29 @@ +import 'dart:convert'; + +import 'package:flutter_dev_utils/flutter_dev_utils.dart'; +import 'package:logger/logger.dart'; + +void main() { + print( + 'Run with either `dart example/main.dart` or `dart --enable-asserts example/main.dart`.'); + Demo.run(); +} + +class Demo { + static void run() { + syncTryCatchHandler(tryFunction: () { + CallerLogger().i('It works!'); + return true; + }); + asyncTryCatchHandler(tryFunction: () async { + CallerLogger().i('It works!'); + return true; + }); + syncTryCatchHandler( + tryFunction: () => jsonDecode('notJson'), + ); + asyncTryCatchHandler( + tryFunction: () => jsonDecode('notJson'), + ); + } +} diff --git a/lib/flutter_dev_utils.dart b/lib/flutter_dev_utils.dart index b484d13..49fa675 100644 --- a/lib/flutter_dev_utils.dart +++ b/lib/flutter_dev_utils.dart @@ -1,7 +1,4 @@ library flutter_dev_utils; -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; -} +export 'src/try_catch_handler/sync_try_catch_handler.dart'; +export 'src/try_catch_handler/async_try_catch_handler.dart'; diff --git a/lib/src/logger.dart b/lib/src/logger.dart new file mode 100644 index 0000000..ef6f06c --- /dev/null +++ b/lib/src/logger.dart @@ -0,0 +1,13 @@ +import 'package:logger/logger.dart'; + +var utilsLogger = CallerLogger( + ignoreCallers: { + 'asyncTryCatchHandler', + 'syncTryCatchHandler', + }, + filter: TypeFilter( + ignoreTypes: {}, + ignoreLevel: Level.warning, + ), + level: Level.verbose, +); diff --git a/lib/src/try_catch_handler/async_try_catch_handler.dart b/lib/src/try_catch_handler/async_try_catch_handler.dart new file mode 100644 index 0000000..58eb006 --- /dev/null +++ b/lib/src/try_catch_handler/async_try_catch_handler.dart @@ -0,0 +1,45 @@ +import 'package:flutter_dev_utils/src/logger.dart'; +import 'package:flutter_dev_utils/src/try_catch_handler/catch_utils.dart'; + +/// Asynchronous try and catch handler to reduce boilerplate +/// +/// Should be called in a State file +Future asyncTryCatchHandler( + {required Future Function() tryFunction, + Map Function(Object e)>? catchKnownExceptions, + Future Function()? catchUnknownExceptions}) async { + //! Validate Catch Known + if (catchKnownExceptions != null) { + validateCatchKnownExceptions(catchKnownExceptions); + } + try { + //! Main Try + try { + return tryFunction.call(); + } catch (e, s) { + //! Handle Known Errors and Exceptions + + if (e is! Error || e is! Exception || catchKnownExceptions == null) { + rethrow; + } else { + Future Function(Object e)? callback; + catchKnownExceptions.forEach((key, value) { + if (key.runtimeType == e.runtimeType) { + callback = value; + } + }); + + if (callback != null) { + utilsLogger.w('Handling known exception', e, s); + return callback!.call(e); + } else { + rethrow; + } + } + } + } catch (e, s) { + //! Handle Unknown Errors and Exceptions + utilsLogger.e('Caught unknown exception', e, s); + return catchUnknownExceptions?.call(); + } +} diff --git a/lib/src/try_catch_handler/catch_utils.dart b/lib/src/try_catch_handler/catch_utils.dart new file mode 100644 index 0000000..b634da7 --- /dev/null +++ b/lib/src/try_catch_handler/catch_utils.dart @@ -0,0 +1,31 @@ +void validateCatchKnownExceptions( + Map catchKnownExceptions) { + /// Type check for catchKnownExceptions map: key should be error or exception + /// + /// Note that AssertionError.runtimeType returns Type, while + /// AssertionError().runtimeType returns Type + catchKnownExceptions.forEach((key, value) { + if (key is! Error && key is! Exception) { + throw ArgumentError( + '''Key passed to catchKnownExceptions should be of Error or Exception type, not ${key.runtimeType}. + \nTry using an instantiation of the error instead of the error, + e.g., AssertionError() instead of AssertionError. + This is necessary because AssertionError.runtimeType returns Type, while + AssertionError().runtimeType returns AssertionEror'''); + } + }); + + /// Duplicate check + /// + /// Since an instantiation of Error/Exception is passed instead of the type, + /// need to check for duplicate keys + Set keyTypes = {}; + catchKnownExceptions.forEach((key, value) { + if (!keyTypes.contains(key.runtimeType)) { + keyTypes.add(key.runtimeType); + } else { + throw ArgumentError( + '''Duplicate key passed to catchKnownExceptions: ${key.runtimeType}'''); + } + }); +} diff --git a/lib/src/try_catch_handler/sync_try_catch_handler.dart b/lib/src/try_catch_handler/sync_try_catch_handler.dart new file mode 100644 index 0000000..1df3480 --- /dev/null +++ b/lib/src/try_catch_handler/sync_try_catch_handler.dart @@ -0,0 +1,45 @@ +import 'package:flutter_dev_utils/src/logger.dart'; +import 'package:flutter_dev_utils/src/try_catch_handler/catch_utils.dart'; + +/// Synchronous try and catch handler to reduce boilerplate +/// +/// Should be called in a State file +dynamic syncTryCatchHandler( + {required dynamic Function() tryFunction, + Map? catchKnownExceptions, + dynamic Function()? catchUnknownExceptions}) { + //! Validate Catch Known + if (catchKnownExceptions != null) { + validateCatchKnownExceptions(catchKnownExceptions); + } + try { + //! Main Try + try { + return tryFunction.call(); + } catch (e, s) { + //! Handle Known Errors and Exceptions + + if (e is! Error || e is! Exception || catchKnownExceptions == null) { + rethrow; + } else { + dynamic Function(Object e)? callback; + catchKnownExceptions.forEach((key, value) { + if (key.runtimeType == e.runtimeType) { + callback = value; + } + }); + + if (callback != null) { + utilsLogger.w('Handling known exception', e, s); + return callback!.call(e); + } else { + rethrow; + } + } + } + } catch (e, s) { + //! Handle Unknown Errors and Exceptions + utilsLogger.e('Caught unknown exception', e, s); + return catchUnknownExceptions?.call(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index acd896c..5271865 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,9 @@ name: flutter_dev_utils description: A new Flutter package project. version: 0.0.1 -homepage: +homepage: https://github.com/Kek-Tech/flutter_dev_utils + +publish_to: none environment: sdk: '>=2.18.0-271.7.beta <3.0.0' @@ -10,6 +12,12 @@ environment: dependencies: flutter: sdk: flutter + logger: + git: + url: https://github.com/Kek-Tech/logger.git + ref: master + + dev_dependencies: flutter_test: diff --git a/test/flutter_dev_utils_test.dart b/test/flutter_dev_utils_test.dart index 515d74c..183f6fb 100644 --- a/test/flutter_dev_utils_test.dart +++ b/test/flutter_dev_utils_test.dart @@ -3,10 +3,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_dev_utils/flutter_dev_utils.dart'; void main() { - test('adds one to input values', () { - final calculator = Calculator(); - expect(calculator.addOne(2), 3); - expect(calculator.addOne(-7), -6); - expect(calculator.addOne(0), 1); + test('test_async_try_catch_handler', () { + expect('a', 'a'); + }); + test('test_sync_try_catch_handler', () { + expect('a', 'a'); }); }