From 2397b5548b957b32acdb5baf091295babe5b36e9 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 10 Oct 2023 15:26:01 +1300 Subject: [PATCH] allow message property on Data.TaggedError (#1507) --- .changeset/eighty-islands-sell.md | 5 +++++ .changeset/wild-otters-rescue.md | 5 +++++ src/Data.ts | 34 ++++++++++++++++--------------- test/Effect/error.ts | 24 +++++++++++++++++++++- 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 .changeset/eighty-islands-sell.md create mode 100644 .changeset/wild-otters-rescue.md diff --git a/.changeset/eighty-islands-sell.md b/.changeset/eighty-islands-sell.md new file mode 100644 index 0000000000..4a3b49ae2b --- /dev/null +++ b/.changeset/eighty-islands-sell.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +allow message property on Data YieldableError diff --git a/.changeset/wild-otters-rescue.md b/.changeset/wild-otters-rescue.md new file mode 100644 index 0000000000..93f6866ec6 --- /dev/null +++ b/.changeset/wild-otters-rescue.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +add name getter to YieldableError diff --git a/src/Data.ts b/src/Data.ts index fdf91645df..32d6c8447f 100644 --- a/src/Data.ts +++ b/src/Data.ts @@ -5,7 +5,6 @@ import type * as Channel from "./Channel" import * as Effect from "./Effect" import * as Effectable from "./Effectable" import type * as Equal from "./Equal" -import type * as Inspectable from "./Inspectable" import * as internal from "./internal/Data" import { type Pipeable } from "./Pipeable" import type * as Sink from "./Sink" @@ -303,7 +302,7 @@ export const taggedEnum: { * @since 2.0.0 * @category models */ -export interface YieldableError extends Case, Pipeable, Inspectable.Inspectable { +export interface YieldableError extends Case, Pipeable, Error { readonly [Effectable.EffectTypeId]: Effect.Effect.VarianceStruct readonly [Effectable.StreamTypeId]: Effect.Effect.VarianceStruct readonly [Effectable.SinkTypeId]: Sink.Sink.VarianceStruct @@ -318,21 +317,23 @@ export interface YieldableError extends Case, Pipeable, Inspectable.Inspectable > } -const YieldableErrorProto = Object.setPrototypeOf( - { - ...Effectable.StructuralCommitPrototype, - toString() { - return `${this.name}: ${this.message}` - }, - get message() { - return JSON.stringify(this) - }, - commit() { - return Effect.fail(this) - } +const YieldableErrorMessage = Symbol.for("effect/Data/YieldableError/message") +const YieldableErrorProto = { + ...Effectable.StructuralCommitPrototype, + __proto__: globalThis.Error.prototype, + commit() { + return Effect.fail(this) + }, + toString(this: globalThis.Error) { + return `${this.name}: ${this.message}` + }, + get message() { + return (this as any)[YieldableErrorMessage] ?? JSON.stringify(this) }, - globalThis.Error.prototype -) + set message(value: string) { + ;(this as any)[YieldableErrorMessage] = value + } +} /** * Provides a constructor for a Case Class. @@ -363,5 +364,6 @@ export const TaggedError = (tag: Tag): new { readonly _tag = tag } + Base.prototype.name = tag return Base as any } diff --git a/test/Effect/error.ts b/test/Effect/error.ts index 672becc7a6..e6d640b54f 100644 --- a/test/Effect/error.ts +++ b/test/Effect/error.ts @@ -11,6 +11,7 @@ describe.concurrent("Effect", () => { Effect.gen(function*($) { const cause = yield* $(Effect.flip(Effect.sandbox(Effect.withSpan("A")(new TestError())))) const log = Cause.pretty(cause) + expect(log).includes("TestError: ") expect(log).includes("test/Effect/error.ts:12:78") expect(log).includes("at A") })) @@ -27,7 +28,28 @@ describe.concurrent("Effect", () => { Effect.flip ) const log = Cause.pretty(cause) - expect(log).includes("test/Effect/error.ts:23") + expect(log).includes("test/Effect/error.ts:24") + expect(log).includes("at A") + })) + + it.effect("allow message prop", () => + Effect.gen(function*($) { + class MessageError extends Data.TaggedError("MessageError")<{ + readonly name: string + readonly message: string + }> {} + const cause = yield* $( + Effect.tryPromise({ + try: () => Promise.reject("fail"), + catch: () => new MessageError({ name: "Failure", message: "some message" }) + }), + Effect.withSpan("A"), + Effect.sandbox, + Effect.flip + ) + const log = Cause.pretty(cause) + expect(log).includes("Failure: some message") + expect(log).includes("test/Effect/error.ts:44") expect(log).includes("at A") })) })