Skip to content

Working With Results

Every pipeline in Jane ends the same way: with a JaneResult. This result object is the contract of the entire framework — the thing you inspect, log, return from APIs, and use to decide what happens next.

This chapter teaches you how to read a result, how to use it, and how to integrate it into real application code. You don’t need to know every subsystem yet — this is the practical, developer‑facing view.

Let’s walk through it step by step.

The Shape of a Result

When you run a pipeline:

const result = await jane.value(input).run();

You always get a structured object with the same shape:

  • ok: Whether the value is acceptable.
  • value: The final interpreted value (if accepted).
  • issues: Only the errors.
  • events: Everything that happened.
  • metadata: Structural and timing information.
  • Optional analysis fields (diff, explain, replay).

Even the simplest pipeline returns this structure.

ok: The Final Decision

This is the first thing you check:

if (result.ok) {
  // success
} else {
  // failure
}

ok is determined by policy, not by validators directly.

Validators emit events. Policy interprets them. This separation is what makes Jane predictable.

value: The Final Interpreted Value

If the pipeline is accepted, value contains the final value after:

  • Containment.
  • Normalization.
  • Parsing.

Example:

const result = await jane.value(" 42 ")
  .parse("numeric")
  .run();

console.log(result.value);
// 42

If the pipeline is rejected, value is omitted unless you explicitly configure the boundary to include rejected values. This keeps things safe by default.

issues: Only the Errors

If you only care about what went wrong, issues is the field you want:

if (!result.ok) {
  console.log(result.issues);
}

issues includes:

  • error events.
  • fatal events.

It does not include warnings or informational events. This makes it perfect for user‑facing error messages.

events: Everything That Happened

If you want the full story, use events:

console.log(result.events);

This includes:

  • Scan events
  • Normalization events
  • Parse events
  • Validation events

Each event has a:

  • Code
  • Message
  • Path
  • Severity

This is the complete record of the pipeline run.

metadata: Structural and Timing Information

Metadata gives you insight into the lifecycle of the value:

console.log(result.metadata);

It includes:

  • raw: The original input.
  • safe: After containment.
  • normalized: After normalization.
  • final: After parsing.
  • Structural types for each stage.
  • Timestamps.
  • Duration.
  • Optional input name.

This is the backbone of debugging, logging, and observability.

Optional Analysis Fields

If you enable analysis features, you’ll also get:

  • diff: Structural changes during normalization.
  • explain: A human‑readable narrative of the pipeline.
  • replay: Step‑by‑step reconstruction of the normalized value.

These are covered in later chapters, but it’s helpful to know they live on the result.

Practical Usage Patterns

Let’s look at how you’ll use results in real code.

Pattern 1: Simple Validation

const result = await jane.value(input)
  .parse("numeric")
  .positive()
  .run();

if (!result.ok) {
  return { error: result.issues[0].message };
}

return { value: result.value };

Clean, predictable, and explicit.

Pattern 2: Logging Everything

const result = await jane(input)
  .parse("email")
  .email()
  .run();

console.log(result.events);
console.log(result.metadata);

Perfect for debugging.

Pattern 3: Using User Messages

const result = await jane.value(input)
  .email()
  .userMessage("Please enter a valid email.")
  .run();

if (!result.ok) {
  return result.issues.map(i => i.message);
}

Great for UI error messages.

Pattern 4: Returning Results from an API

app.post("/register", async (req, res) => {
    const result = await jane.value(req.body.email)
        .parse("email")
        .email()
        .run();

    if (!result.ok) {
        return res.status(400).json({ errors: result.issues });
    }

    return res.json({ email: result.value });
});

JaneResult is API‑friendly by design.

What You’ve Learned

You now know how to:

  • Inspect the result.
  • Read the final value.
  • Handle errors cleanly.
  • Log events.
  • Use metadata.
  • Integrate Jane into real application code.

This is the practical foundation for using Jane in everyday development.

In the next chapter, we’ll explore modes — strict, moderate, and lax — and how they change the behavior of the pipeline. I know you're ready!

Choosing the right mode