Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/local-effect-provides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/language-service": patch
---

Ignore Effect v4 local `Effect.provide(..., { local: true })` calls when reporting chained provides with the `multipleEffectProvide` diagnostic.
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ multipleEffectProvide_skipNextLine from 819 to 853
multipleEffectProvide_skipFile from 819 to 853
multipleEffectProvide_fix from 949 to 983
multipleEffectProvide_skipNextLine from 949 to 983
multipleEffectProvide_skipFile from 949 to 983
multipleEffectProvide_skipFile from 949 to 983
multipleEffectProvide_fix from 1339 to 1373
multipleEffectProvide_skipNextLine from 1339 to 1373
multipleEffectProvide_skipFile from 1339 to 1373
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// code fix multipleEffectProvide_fix output for range 1339 - 1373
import { Context, Effect, Layer } from "effect"

class MyService1 extends Context.Service<MyService1>()("MyService1", {
make: Effect.succeed({ value: 1 })
}) {
static Default = Layer.effect(this, this.make)
}

class MyService2 extends Context.Service<MyService2>()("MyService2", {
make: Effect.succeed({ value: 2 })
}) {
static Default = Layer.effect(this, this.make)
}

class MyService3 extends Context.Service<MyService3>()("MyService3", {
make: Effect.succeed({ value: 3 })
}) {
static Default = Layer.effect(this, this.make)
}

export const shouldReport = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default)
)

export const shouldReportSeparately = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default),
Effect.ignore,
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default)
)

export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(Layer.mergeAll(MyService2.Default, MyService3.Default))
)
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ export const shouldReportSeparately = Effect.void.pipe(
export const shouldReportSingle = Effect.void.pipe(
Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default, MyService3.Default))
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ Effect.provide(MyService1.Default)
30:2 - 30:36 | 0 | This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers. effect(multipleEffectProvide)

Effect.provide(MyService1.Default)
35:2 - 35:36 | 0 | This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers. effect(multipleEffectProvide)
35:2 - 35:36 | 0 | This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers. effect(multipleEffectProvide)

Effect.provide(MyService2.Default)
47:2 - 47:36 | 0 | This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers. effect(multipleEffectProvide)
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,14 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldNotReportLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default, { local: true })
)

export const shouldReportAfterLocalProvide = Effect.void.pipe(
Effect.provide(MyService1.Default, { local: true }),
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)
18 changes: 18 additions & 0 deletions packages/language-service/src/diagnostics/multipleEffectProvide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const multipleEffectProvide = LSP.createDiagnostic({
const tsUtils = yield* Nano.service(TypeScriptUtils.TypeScriptUtils)
const typeCheckerUtils = yield* Nano.service(TypeCheckerUtils.TypeCheckerUtils)
const typeParser = yield* Nano.service(TypeParser.TypeParser)
const supportedEffect = typeParser.supportedEffect()

const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
sourceFile,
Expand Down Expand Up @@ -58,6 +59,23 @@ export const multipleEffectProvide = LSP.createDiagnostic({
)

if (Option.isSome(isProvideCall)) {
const options = transformation.args[1]
const isLocalProvide = supportedEffect === "v4" &&
options !== undefined &&
ts.isObjectLiteralExpression(options) &&
options.properties.some((property) =>
ts.isPropertyAssignment(property) &&
ts.isIdentifier(property.name) &&
ts.idText(property.name) === "local" &&
property.initializer.kind === ts.SyntaxKind.TrueKeyword
)

if (isLocalProvide) {
currentChunk++
previousLayers.push([])
continue
}

const layer = transformation.args[0]
const type = typeCheckerUtils.getTypeAtLocation(layer)
const node = ts.findAncestor(transformation.callee, ts.isCallExpression)
Expand Down
Loading