Skip to content

A tiny-yet-complete functional error handling toolkit for Dart: Result, Option, Validation, AsyncResult, Stream helpers, and a minimal Loadable state.

License

Notifications You must be signed in to change notification settings

fluttercandies/resx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Resx ⚑️

pub package documentation license: MIT

A lightweight and complete functional error-handling toolkit for Dart, featuring Result, Option, Validation, AsyncResult, stream utilities, and a minimal Loadable state.

Tiny, complete, and functional.

English | δΈ­ζ–‡

Features ✨

πŸš€ High Performance - Optimized for speed and memory efficiency
πŸ”’ Type Safe - Full null safety and strong typing
πŸ”— Chainable - Fluent API with method chaining
πŸ“¦ Batch Operations - Process collections efficiently
🎯 Validation - Accumulate multiple errors elegantly
⚑ Async Support - First-class async/await integration
🧩 Extensions - Native Dart type integrations

Core Types 🧠

Result<T, E> - Error Handling βœ…/❌

Type-safe error handling inspired by Rust's Result type.

import 'package:resx/resx.dart';

// Create results
final success = Result.ok(42);
final failure = Result.err('Something went wrong');

// Chain operations
final result = Result.ok(5)
  .map((x) => x * 2)
  .flatMap((x) => x > 5 ? Result.ok(x) : Result.err('Too small'));

// Handle both cases
final message = result.fold(
  (value) => 'Success: $value',
  (error) => 'Error: $error',
);

// Exception catching
final parsed = Result.from(() => int.parse('42')); // Ok(42)
final failed = Result.from(() => int.parse('abc')); // Err(FormatException)

// Guards and swap
final guarded = Result.ok(10).ensure((v) => v > 5, 'Too small');
final swapped = Result.ok(1).swap(); // Err(1)

Option<T> - Nullable Values ❓

Safe nullable value handling with Some/None variants.

// Create options
final some = Option.some('Hello');
final none = Option<String>.none();

// Safe operations
final result = Option.some('world')
  .map((s) => s.toUpperCase())
  .filter((s) => s.length > 3)
  .unwrapOr('DEFAULT');

// From nullable
String? nullable = getValue();
final option = Option.fromNullable(nullable);

Validation<E, T> - Error Accumulation 🧰

Collect multiple validation errors instead of failing fast.

// Built-in validators
final emailValidation = Validators.email('[email protected]', 'Invalid email');
final rangeValidation = Validators.range(25, 18, 65, 'Age out of range');

// Accumulate errors
final userValidation = Validators.notEmpty('John', 'Name required')
  .and(Validators.email('invalid-email', 'Email invalid'))
  .and(Validators.range(150, 0, 120, 'Age invalid'));

// Result: Invalid(['Email invalid', 'Age invalid'])

AsyncResult<T, E> - Async Operations ⏱️

First-class async support for Result operations.

// Create async results
final asyncResult = AsyncResult.ok(42);
final fromFuture = AsyncResult.from(fetchData());

// Chain async operations
final result = await AsyncResult.ok(5)
  .map((x) => x * 2)
  .flatMap((x) => AsyncResult.ok(x + 1));

// Handle async errors safely
final safeResult = await AsyncResult.from(riskyOperation())
  .orElse((error) => AsyncResult.ok('fallback'));

// Guard async values
final ensured = await AsyncResult.ok<int, String>(10)
  .ensure((v) => v > 0, 'non-positive');

Dart Extensions 🧩

String Extensions πŸ”€

// Parsing with results
final number = '42'.parseInt(); // Ok(42)
final invalid = 'abc'.parseInt(); // Err(FormatException)

// Validation
final email = '[email protected]'.validateEmail(); // Valid(...)
final url = Validators.url('https://example.com'); // Valid(...)

List, Stream and Nullable Extensions

final numbers = [1, 2, 3, 4, 5];
final results = numbers.map((x) => x.isEven ? Result.ok(x) : Result.err('odd'));
final combined = Results.sequence(results); // Ok([...]) or first Err
final (oks, errs) = Results.partition(results);

// Stream helpers
final stream = Stream.fromIterable([1,2,3]);
final asResults = stream.toResultStream<Object>();
final collected = await stream.collectToResult<Object>();

Universal and Nullable Conversions πŸ”

String? nullable = getValue();
final option = nullable.toOption(); // Option<String>

final result = nullable.toResult('Value is null'); // Result<String, String>

// Universal: wrap any value fast
final r1 = 42.ok<String>();              // Result<int, String>::Ok(42)
final r2 = 'boom'.err<int>();             // Result<int, String>::Err('boom')
final o1 = 'hello'.some();                // Option<String>::Some('hello')

Batch Operations πŸ“¦

// Combine multiple results
final results = [Result.ok(1), Result.ok(2), Result.ok(3)];
final combined = Results.combine(results); // Ok([1, 2, 3])

// Partition successes and errors
final mixed = [Result.ok(1), Result.err('error'), Result.ok(3)];
final (values, errors) = Results.partition(mixed); // ([1, 3], ['error'])

// Applicative operations
final sum = Results.lift2(
  Result.ok(2),
  Result.ok(3),
  (a, b) => a + b,
); // Ok(5)

Advanced Usage πŸš€

Custom Validators

// Using built-in predicate helper
final validation = Validators.predicate<String, String>(
  'test',
  (v) => v.startsWith('prefix_'),
  'Must start with prefix_',
); // Invalid(['Must start with prefix_'])

Pattern Matching

final result = Result.ok(42);

final message = result.match(
  (value) => 'Got value: $value',
  (error) => 'Got error: $error',
);

Railway-Oriented Programming

final pipeline = (String input) => Result.ok(input)
  .flatMap(validateInput)
  .flatMap(processData)
  .flatMap(saveToDatabase)
  .map(formatResponse);

final result = pipeline('user input');

Performance

Focused API, minimal indirections, idiomatic Dart sealed classes and extension types. No magic.

Installation

Add to your pubspec.yaml:

dependencies:
  resx: any

Then run:

dart pub get

Examples

Check out the example directory for comprehensive usage examples:

API Documentation

Complete API documentation with examples is available at pub.dev.

Contributing

Contributions are welcome! Please read our contributing guidelines and feel free to submit issues and pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with πŸ’™ by FlutterCandies

About

A tiny-yet-complete functional error handling toolkit for Dart: Result, Option, Validation, AsyncResult, Stream helpers, and a minimal Loadable state.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors 2

  •  
  •  

Languages