REslava.Result.Flow β€” Native Companion Package

For projects using REslava.Result, the companion package REslava.Result.Flow adds two capabilities not possible in the library-agnostic package:

  • Typed error edges β€” scans each step's method body for new XxxError(...) constructions where XxxError implements IError; renders -->|DatabaseError| FAIL edges instead of generic fail arrows
  • IOperation chain walker β€” uses Roslyn's semantic model at the IInvocationOperation level, which makes the pipeline entry-point call (e.g. CreateUser()) visible as its own node
dotnet add package REslava.Result.Flow

Add using REslava.Result.Flow; β€” the attribute type is injected automatically by the generator, no separate assembly reference needed.

/*
```mermaid
flowchart LR
    N0_CreateUser["CreateUser<br/>User"]:::operation
    N0_CreateUser --> N1_EnsureAsync
    N1_EnsureAsync["EnsureAsync ⚑<br/>User"]:::gatekeeper
    N1_EnsureAsync -->|pass| N2_BindAsync
    N1_EnsureAsync -->|ValidationError| FAIL
    N2_BindAsync["BindAsync ⚑<br/>User"]:::transform
    N2_BindAsync -->|ok| N3_MapAsync
    N2_BindAsync -->|DatabaseError| FAIL
    N3_MapAsync["MapAsync ⚑<br/>User β†’ UserDto"]:::transform
    FAIL([fail]):::failure
    classDef gatekeeper fill:#e3e9fa,color:#3f5c9a
    classDef transform fill:#e3f0e8,color:#2f7a5c
    classDef failure fill:#f8e3e3,color:#b13e3e
    classDef operation fill:#e8f4f0,color:#1c7e6f
```*/
[ResultFlow]
public Task<Result<UserDto>> RegisterAsync(RegisterCommand cmd) =>
    CreateUser(cmd)
        .EnsureAsync(IsEmailValid, u => new ValidationError("email", "invalid"))
        .BindAsync(SaveUser)
        .MapAsync(ToUserDto);

Paste the comment into mermaid.live β€” CreateUser becomes the pipeline root, ValidationError and DatabaseError appear as typed failure edges on their respective steps. Here you can see the resulting diagram:

flowchart LR
    N0_CreateUser["CreateUser<br/>User"]:::operation
    N0_CreateUser --> N1_EnsureAsync
    N1_EnsureAsync["EnsureAsync ⚑<br/>User"]:::gatekeeper
    N1_EnsureAsync -->|pass| N2_BindAsync
    N1_EnsureAsync -->|ValidationError| FAIL
    N2_BindAsync["BindAsync ⚑<br/>User"]:::transform
    N2_BindAsync -->|ok| N3_MapAsync
    N2_BindAsync -->|DatabaseError| FAIL
    N3_MapAsync["MapAsync ⚑<br/>User β†’ UserDto"]:::transform
    FAIL([fail]):::failure
    classDef gatekeeper fill:#e3e9fa,color:#3f5c9a
    classDef transform fill:#e3f0e8,color:#2f7a5c
    classDef failure fill:#f8e3e3,color:#b13e3e
    classDef operation fill:#e8f4f0,color:#1c7e6f

Error scanning is best-effort β€” only scans methods in the same compilation; errors created but not returned may appear as false positives; helper methods are not recursively followed.

REslava.ResultFlow REslava.Result.Flow
Works with any library βœ… ❌ REslava.Result only
⚑ async annotation βœ… βœ…
Success type travel βœ… (first generic arg) βœ… (via IResultBase)
Typed error edges ❌ βœ… (IError body scan)
Entry-point call as node ❌ βœ… (IOperation walk)

Which package should I use? Using REslava.Result? β†’ use REslava.Result.Flow. It produces richer diagrams with typed error edges and deeper type travel.

Feature Comparison

Using FluentResults, ErrorOr, LanguageExt, or any other library? β†’ use REslava.ResultFlow. Zero configuration needed for Bind and Map (both are in the built-in convention dictionary).