Skip to content

Commit

Permalink
ensure TagClass stack is set correctly (#2029)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart authored Feb 3, 2024
1 parent ee39ab3 commit 5cefd87
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
10 changes: 2 additions & 8 deletions packages/effect/src/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export declare namespace Tag {
* @since 2.0.0
* @category constructors
*/
export const Tag: <Identifier, Service = Identifier>(key: string) => Tag<Identifier, Service> = internal.makeTag
export const Tag: <Identifier, Service = Identifier>(key: string) => Tag<Identifier, Service> = internal.makeGenericTag

const TypeId: unique symbol = internal.TypeId as TypeId

Expand Down Expand Up @@ -387,10 +387,4 @@ export const omit: <Services, S extends Array<ValidTagsById<Services>>>(
* @since 2.0.0
* @category constructors
*/
export const TagClass = <const Id extends string>(id: Id) => <Self, Shape>(): TagClass<Self, Id, Shape> => {
function TagClass() {}
const original = Tag(id)
Object.assign(TagClass, original)
Object.setPrototypeOf(TagClass, Object.getPrototypeOf(original))
return TagClass as any
}
export const TagClass: <const Id extends string>(id: Id) => <Self, Shape>() => TagClass<Self, Id, Shape> = internal.Tag
21 changes: 19 additions & 2 deletions packages/effect/src/internal/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const TagProto: any = {
}

/** @internal */
export const makeTag = <Identifier, Service = Identifier>(key: string): C.Tag<Identifier, Service> => {
export const makeGenericTag = <Identifier, Service = Identifier>(key: string): C.Tag<Identifier, Service> => {
const limit = Error.stackTraceLimit
Error.stackTraceLimit = 2
const creationError = new Error()
Expand All @@ -71,6 +71,24 @@ export const makeTag = <Identifier, Service = Identifier>(key: string): C.Tag<Id
return tag
}

/** @internal */
export const Tag = <const Id extends string>(id: Id) => <Self, Shape>(): C.TagClass<Self, Id, Shape> => {
const limit = Error.stackTraceLimit
Error.stackTraceLimit = 2
const creationError = new Error()
Error.stackTraceLimit = limit

function TagClass() {}
Object.setPrototypeOf(TagClass, TagProto)
TagClass.key = id
Object.defineProperty(TagClass, "stack", {
get() {
return creationError.stack
}
})
return TagClass as any
}

/** @internal */
export const TypeId: C.TypeId = Symbol.for("effect/Context") as C.TypeId

Expand Down Expand Up @@ -180,7 +198,6 @@ export const unsafeGet = dual<
<Services, S, I>(self: C.Context<Services>, tag: C.Tag<I, S>) => S
>(2, (self, tag) => {
if (!self.unsafeMap.has(tag.key)) {
console.log(self.unsafeMap, tag.key)
throw serviceNotFoundError(tag as any)
}
return self.unsafeMap.get(tag.key)! as any
Expand Down
27 changes: 25 additions & 2 deletions packages/effect/test/Context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,20 @@ interface C {
}
const C = Context.Tag<C>("C")

class D extends Context.TagClass("D")<D, { readonly d: number }>() {}

describe("Context", () => {
it("Tag.toJson()", () => {
const json: any = A.toJSON()
expect(json["_id"]).toEqual("Tag")
expect(json["identifier"]).toEqual(undefined)
expect(json["key"]).toEqual("A")
expect(typeof json["stack"]).toEqual("string")
})

it("TagClass.toJson()", () => {
const json: any = D.toJSON()
expect(json["_id"]).toEqual("Tag")
expect(json["key"]).toEqual("D")
expect(typeof json["stack"]).toEqual("string")
})

Expand Down Expand Up @@ -51,7 +60,8 @@ describe("Context", () => {
it("adds and retrieve services", () => {
const Services = pipe(
Context.make(A, { a: 0 }),
Context.add(B, { b: 1 })
Context.add(B, { b: 1 }),
Context.add(D, { d: 2 })
)

expect(Context.get(Services, A)).toEqual({ a: 0 })
Expand All @@ -61,6 +71,11 @@ describe("Context", () => {
Context.getOption(B)
)).toEqual(O.some({ b: 1 }))

expect(pipe(
Services,
Context.get(D)
)).toEqual({ d: 2 })

expect(pipe(
Services,
Context.getOption(C)
Expand Down Expand Up @@ -211,6 +226,14 @@ describe("Context", () => {
new RegExp(/Error: Service not found: C \(defined at (.*)Context.test.ts:20:19\)/)
)
}
try {
Context.get(Context.empty(), D as never)
} catch (e) {
assert.match(
String(e),
new RegExp(/Error: Service not found: D \(defined at (.*)Context.test.ts:22:37\)/)
)
}
}
})

Expand Down

0 comments on commit 5cefd87

Please sign in to comment.