> ## Documentation Index
> Fetch the complete documentation index at: https://ancplua.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# DiagnosticFlow

> Railway-oriented programming for source generator pipelines

Railway-oriented programming for source generator pipelines. Never lose a diagnostic.

## The Problem

Traditional generator code loses diagnostics:

```csharp theme={null}
// BAD: Diagnostics get lost
var model = ExtractModel(syntax);
if (model == null) return; // Where's the diagnostic?

var validated = Validate(model);
if (!validated.Success) return; // Lost again!
```

## The Solution

`DiagnosticFlow<T>` carries both value AND diagnostics through the pipeline:

```csharp theme={null}
// GOOD: Diagnostics flow through
symbol.ToFlow(nullDiag)
    .Then(ExtractModel)
    .Then(Validate)
    .Then(Generate)
    .ReportAndContinue(context);
```

## Creating Flows

```csharp theme={null}
// From value
var flow = DiagnosticFlow.Ok(value);

// From nullable (fails if null)
var flow = symbol.ToFlow(nullDiag);

// With initial diagnostics
var flow = DiagnosticFlow.Ok(value, warnings);

// Failed flow
var flow = DiagnosticFlow.Fail<T>(errorDiag);
```

## Chaining Operations

### Then - Transform Value

```csharp theme={null}
flow.Then(value => TransformValue(value))
    .Then(transformed => AnotherTransform(transformed));
```

### Select - Map Without Flow

```csharp theme={null}
flow.Select(value => value.Name)
    .Select(name => name.ToUpperInvariant());
```

### Where - Filter with Diagnostic

```csharp theme={null}
flow.Where(
    predicate: m => m.IsAsync,
    onFail: asyncRequiredDiag
);
```

### WarnIf - Conditional Warning

```csharp theme={null}
flow.WarnIf(
    predicate: m => m.IsObsolete,
    warning: obsoleteWarning
);
```

## Combining Flows

```csharp theme={null}
// Tuple of two flows (both must succeed)
var combined = DiagnosticFlow.Zip(flow1, flow2);
// Result: DiagnosticFlow<(T1, T2)>

// Collect all (all must succeed, diagnostics accumulated)
var all = DiagnosticFlow.Collect(flows);
// Result: DiagnosticFlow<ImmutableArray<T>>
```

## Result Handling

```csharp theme={null}
// Get value or default
var value = flow.ValueOrDefault(fallback);

// Pattern match
flow.Match(
    onSuccess: value => HandleSuccess(value),
    onFailure: diagnostics => HandleFailure(diagnostics)
);

// Execute side effect
flow.Do(value => LogValue(value));
```

## Pipeline Integration

Use with `IncrementalValuesProvider`:

```csharp theme={null}
var pipeline = context.SyntaxProvider
    .ForAttributeWithMetadataName("MyAttribute", ...)
    .SelectFlow(ctx => ExtractModel(ctx))
    .ThenFlow(model => Validate(model))
    .WarnIf(model => model.IsDeprecated, deprecatedWarn)
    .ReportAndContinue(context)
    .Select(model => GenerateCode(model));

context.RegisterSourceOutput(pipeline, (ctx, code) =>
    ctx.AddSource(code.Name, code.Content));
```

## Properties

| Property      | Description                           |
| ------------- | ------------------------------------- |
| `IsSuccess`   | True if no errors                     |
| `IsFailed`    | True if has errors                    |
| `HasErrors`   | True if any error-severity diagnostic |
| `Value`       | The wrapped value (throws if failed)  |
| `Diagnostics` | All accumulated diagnostics           |

## Null-Safety

`DiagnosticFlow<T>` uses `[MemberNotNullWhen]` to enable flow-dependent null analysis:

```csharp theme={null}
var flow = symbol.ToFlow(nullDiag);

// Compiler knows Value is non-null when IsSuccess is true
if (flow.IsSuccess)
{
    var name = flow.Value.Name;  // No null warning
}

// Pattern matching also works
if (flow is { IsSuccess: true, Value: var value })
{
    var name = value.Name;  // No null warning
}
```

<Tip>
  The `[MemberNotNullWhen(true, nameof(Value))]` attribute on `IsSuccess` tells
  the compiler that `Value` is guaranteed non-null when `IsSuccess` returns
  `true`.
</Tip>
