diff --git a/packages/effect/src/Effect.ts b/packages/effect/src/Effect.ts index 2c531a1ec54..6412ce812a0 100644 --- a/packages/effect/src/Effect.ts +++ b/packages/effect/src/Effect.ts @@ -6194,6 +6194,7 @@ export declare namespace Tag { key?: `property "key" is forbidden` stack?: `property "stack" is forbidden` name?: `property "name" is forbidden` + pipe?: `property "pipe" is forbidden` } /** @@ -6201,8 +6202,8 @@ export declare namespace Tag { * @category models */ export interface ProhibitedTypeLive extends ProhibitedType { - Live?: `property "Live" is forbidden` Layer?: `property "Layer" is forbidden` + _op_layer?: `property "_op_layer" is forbidden` } /** @@ -6245,8 +6246,14 @@ export declare namespace Tag { */ export type Maker = { effect: Effect, any, any> + } | { + effect: Effect, any, any> + dependencies: [Layer.Layer, ...Array>] } | { scoped: Effect, any, any> + } | { + scoped: Effect, any, any> + dependencies: [Layer.Layer, ...Array>] } | { sync: () => AllowedType } @@ -6257,19 +6264,41 @@ export declare namespace Tag { */ export type ReturnWithMaker = & {} - & Maker extends { scoped: Effect, infer E, infer R> } - ? Tag.Return & { - readonly Layer: Layer.Layer> - readonly Live: Layer.Layer> - } + & Maker extends { + scoped: Effect, infer E, infer R> + dependencies: infer Layers extends [Layer.Layer, ...Array>] + } ? + & Tag.Return + & Layer.Layer< + Self, + E | { [k in keyof Layers]: Layer.Layer.Error }[number], + | Exclude }[number]> + | { [k in keyof Layers]: Layer.Layer.Context }[number] + > + & { readonly Layer: Layer.Layer> } + : Maker extends { scoped: Effect, infer E, infer R> } + ? Tag.Return & Layer.Layer> & { + readonly Layer: Layer.Layer> + } + : Maker extends { + effect: Effect, infer E, infer R> + dependencies: infer Layers extends [Layer.Layer, ...Array>] + } ? + & Tag.Return + & Layer.Layer< + Self, + E | { [k in keyof Layers]: Layer.Layer.Error }[number], + | Exclude }[number]> + | { [k in keyof Layers]: Layer.Layer.Context }[number] + > + & { readonly Layer: Layer.Layer> } : Maker extends { effect: Effect, infer E, infer R> } - ? Tag.Return & { + ? Tag.Return & Layer.Layer & { readonly Layer: Layer.Layer - readonly Live: Layer.Layer } - : Maker extends { sync: () => infer Type extends AllowedType } ? Tag.Return & { + : Maker extends { sync: () => infer Type extends AllowedType } ? + Tag.Return & Layer.Layer & { readonly Layer: Layer.Layer - readonly Live: Layer.Layer } : never } @@ -6301,22 +6330,23 @@ export const Tag: { }) if (maker !== undefined) { if ("effect" in maker) { - // @ts-expect-error - TagClass["Live"] = layer.fromEffect(TagClass, maker["effect"]) // @ts-expect-error TagClass["Layer"] = layer.fromEffect(TagClass, maker["effect"]) + Object.assign(TagClass, TagClass["Layer"]) } if ("scoped" in maker) { - // @ts-expect-error - TagClass["Live"] = layer.scoped(TagClass, maker["scoped"]) // @ts-expect-error TagClass["Layer"] = layer.scoped(TagClass, maker["scoped"]) + let live = TagClass["Layer"] + if ("dependencies" in maker) { + live = live.pipe(layer.provide(layer.mergeAll(...maker["dependencies"]))) + } + Object.assign(TagClass, live) } if ("sync" in maker) { - // @ts-expect-error - TagClass["Live"] = layer.sync(TagClass, maker["sync"]) // @ts-expect-error TagClass["Layer"] = layer.sync(TagClass, maker["sync"]) + Object.assign(TagClass, TagClass["Layer"]) } } const cache = new Map() diff --git a/packages/effect/src/internal/layer.ts b/packages/effect/src/internal/layer.ts index ca60bd5414f..824bffb126a 100644 --- a/packages/effect/src/internal/layer.ts +++ b/packages/effect/src/internal/layer.ts @@ -79,7 +79,7 @@ export type Primitive = /** @internal */ export type Op = Layer.Layer & Body & { - readonly _tag: Tag + readonly _op_layer: Tag } /** @internal */ @@ -165,7 +165,7 @@ export const isLayer = (u: unknown): u is Layer.Layer /** @internal */ export const isFresh = (self: Layer.Layer): boolean => { - return (self as Primitive)._tag === OpCodes.OP_FRESH + return (self as Primitive)._op_layer === OpCodes.OP_FRESH } // ----------------------------------------------------------------------------- @@ -356,7 +356,7 @@ const makeBuilder = ( inMemoMap = false ): Effect.Effect<(memoMap: Layer.MemoMap) => Effect.Effect, E, RIn>> => { const op = self as Primitive - switch (op._tag) { + switch (op._op_layer) { case "Locally": { return core.sync(() => (memoMap: Layer.MemoMap) => op.f(memoMap.getOrElseMemoize(op.self, scope))) } @@ -487,7 +487,7 @@ export const extendScope = ( self: Layer.Layer ): Layer.Layer => { const extendScope = Object.create(proto) - extendScope._tag = OpCodes.OP_EXTEND_SCOPE + extendScope._op_layer = OpCodes.OP_EXTEND_SCOPE extendScope.layer = self return extendScope } @@ -533,7 +533,7 @@ export const flatten = dual< /** @internal */ export const fresh = (self: Layer.Layer): Layer.Layer => { const fresh = Object.create(proto) - fresh._tag = OpCodes.OP_FRESH + fresh._op_layer = OpCodes.OP_FRESH fresh.layer = self return fresh } @@ -565,7 +565,7 @@ export function fromEffectContext( effect: Effect.Effect, E, R> ): Layer.Layer { const fromEffect = Object.create(proto) - fromEffect._tag = OpCodes.OP_FROM_EFFECT + fromEffect._op_layer = OpCodes.OP_FROM_EFFECT fromEffect.effect = effect return fromEffect } @@ -587,7 +587,7 @@ export const locallyEffect = dual< ) => Layer.Layer >(2, (self, f) => { const locally = Object.create(proto) - locally._tag = "Locally" + locally._op_layer = "Locally" locally.self = self locally.f = f return locally @@ -658,7 +658,7 @@ export const matchCause = dual< ) => Layer.Layer >(2, (self, { onFailure, onSuccess }) => { const fold = Object.create(proto) - fold._tag = OpCodes.OP_FOLD + fold._op_layer = OpCodes.OP_FOLD fold.layer = self fold.failureK = onFailure fold.successK = onSuccess @@ -866,7 +866,7 @@ export const scopedContext = ( effect: Effect.Effect, E, R> ): Layer.Layer> => { const scoped = Object.create(proto) - scoped._tag = OpCodes.OP_SCOPED + scoped._op_layer = OpCodes.OP_SCOPED scoped.effect = effect return scoped } @@ -920,7 +920,7 @@ export const suspend = ( evaluate: LazyArg> ): Layer.Layer => { const suspend = Object.create(proto) - suspend._tag = OpCodes.OP_SUSPEND + suspend._op_layer = OpCodes.OP_SUSPEND suspend.evaluate = evaluate return suspend } @@ -1039,9 +1039,9 @@ export const provide = dual< ) => suspend(() => { const provideTo = Object.create(proto) - provideTo._tag = OpCodes.OP_PROVIDE + provideTo._op_layer = OpCodes.OP_PROVIDE provideTo.first = Object.create(proto, { - _tag: { value: OpCodes.OP_PROVIDE_MERGE, enumerable: true }, + _op_layer: { value: OpCodes.OP_PROVIDE_MERGE, enumerable: true }, first: { value: context>(), enumerable: true }, second: { value: self }, zipK: { value: (a: Context.Context, b: Context.Context) => pipe(a, Context.merge(b)) } @@ -1063,7 +1063,7 @@ export const provideMerge = dual< ) => Layer.Layer> >(2, (that: Layer.Layer, self: Layer.Layer) => { const zipWith = Object.create(proto) - zipWith._tag = OpCodes.OP_PROVIDE_MERGE + zipWith._op_layer = OpCodes.OP_PROVIDE_MERGE zipWith.first = self zipWith.second = provide(that, self) zipWith.zipK = (a: Context.Context, b: Context.Context): Context.Context => { @@ -1086,7 +1086,7 @@ export const zipWith = dual< >(3, (self, that, f) => suspend(() => { const zipWith = Object.create(proto) - zipWith._tag = OpCodes.OP_ZIP_WITH + zipWith._op_layer = OpCodes.OP_ZIP_WITH zipWith.first = self zipWith.second = that zipWith.zipK = f diff --git a/packages/effect/test/Effect/environment.test.ts b/packages/effect/test/Effect/environment.test.ts index 51c6f1ea7b5..83ed91c32ea 100644 --- a/packages/effect/test/Effect/environment.test.ts +++ b/packages/effect/test/Effect/environment.test.ts @@ -31,10 +31,9 @@ class DemoTag extends Effect.Tag("DemoTag")() { } -class DateTag extends Effect.Tag("DateTag")() { - static date = new Date(1970, 1, 1) - static Live = Layer.succeed(this, this.date) -} +class DateTag extends Effect.Tag("DateTag", { + sync: () => new Date(1970, 1, 1) +})() {} class MapTag extends Effect.Tag("MapTag", { effect: Effect.sync(() => new Map()) @@ -53,10 +52,9 @@ class ScopedTag extends Effect.Tag("ScopedTag", { yield* Effect.acquireRelease(Effect.sync(() => 100), () => Effect.void) yield* Dummy return 100 - }) -})() { - static Live = this.Layer.pipe(Layer.provide(Dummy.Live)) -} + }), + dependencies: [Dummy] +})() {} describe("Effect", () => { it.effect("provide runtime is additive", () => @@ -108,7 +106,7 @@ describe("Effect", () => { }))) it.effect("effect tag with primitives", () => Effect.gen(function*($) { - expect(yield* $(DateTag.getTime())).toEqual(DateTag.date.getTime()) + expect(yield* $(DateTag.getTime())).toEqual(new Date(1970, 1, 1).getTime()) expect(yield* $(NumberTag)).toEqual(100) expect(yield* $(ScopedTag)).toEqual(100) expect(Array.from(yield* $(MapTag.keys()))).toEqual([]) @@ -117,10 +115,10 @@ describe("Effect", () => { expect(yield* $(MapTag.get("foo"))).toEqual("bar") }).pipe( Effect.provide(Layer.mergeAll( - DateTag.Live, - NumberTag.Live, - MapTag.Live, - ScopedTag.Live + DateTag, + NumberTag, + MapTag, + ScopedTag )) )) it.effect("class tag", () =>