Skip to content
Open
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/tidy-layers-provide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/language-service": minor
---

add `redundantLayerMergeAllInProvide` to replace direct `Layer.mergeAll` arguments to `Effect.provide` with layer arrays.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Some diagnostics are off by default or have a default severity of suggestion, bu
<tr><td><code>missedPipeableOpportunity</code></td><td>➖</td><td>🔧</td><td>Enforces the use of pipeable style for nested function calls</td><td>✓</td><td>✓</td></tr>
<tr><td><code>missingEffectServiceDependency</code></td><td>➖</td><td></td><td>Checks that Effect.Service dependencies satisfy all required layer inputs</td><td>✓</td><td></td></tr>
<tr><td><code>nestedEffectGenYield</code></td><td>➖</td><td></td><td>Warns when yielding a nested bare Effect.gen inside an existing Effect generator context</td><td>✓</td><td>✓</td></tr>
<tr><td><code>redundantLayerMergeAllInProvide</code></td><td>💡</td><td>🔧</td><td>Replaces direct Layer.mergeAll arguments to Effect.provide with an array of layers</td><td>✓</td><td>✓</td></tr>
<tr><td><code>redundantSchemaTagIdentifier</code></td><td>💡</td><td>🔧</td><td>Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest</td><td>✓</td><td>✓</td></tr>
<tr><td><code>schemaStructWithTag</code></td><td>💡</td><td>🔧</td><td>Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field</td><td>✓</td><td>✓</td></tr>
<tr><td><code>schemaUnionOfLiterals</code></td><td>➖</td><td>🔧</td><td>Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal</td><td>✓</td><td></td></tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ exports[`Completion effectDataClasses > effectDataClasses_directImportTaggedErro
exports[`Completion effectDiagnosticsComment > effectDiagnosticsComment.ts at 2:5 1`] = `
[
{
"insertText": "@effect-diagnostics \${1|anyUnknownInErrorContext,asyncFunction,catchAllToMapError,catchUnfailableEffect,classSelfMismatch,cryptoRandomUUID,cryptoRandomUUIDInEffect,deterministicKeys,duplicatePackage,effectDoNotation,effectFnIife,effectFnImplicitAny,effectFnOpportunity,effectGenUsesAdapter,effectInFailure,effectInVoidSuccess,effectMapFlatten,effectMapVoid,effectSucceedWithVoid,extendsNativeError,flatMapToMap,floatingEffect,genericEffectServices,globalConsole,globalConsoleInEffect,globalDate,globalDateInEffect,globalErrorInEffectCatch,globalErrorInEffectFailure,globalFetch,globalFetchInEffect,globalRandom,globalRandomInEffect,globalTimers,globalTimersInEffect,importFromBarrel,instanceOfSchema,layerMergeAllWithDependencies,lazyPromiseInEffectSync,leakingRequirements,missedPipeableOpportunity,missingEffectContext,missingEffectError,missingEffectServiceDependency,missingLayerContext,missingReturnYieldStar,missingStarInYieldEffectGen,multipleEffectProvide,nestedEffectGenYield,newPromise,nodeBuiltinImport,nonObjectEffectServiceType,outdatedApi,outdatedEffectCodegen,overriddenSchemaConstructor,preferSchemaOverJson,processEnv,processEnvInEffect,redundantSchemaTagIdentifier,returnEffectInGen,runEffectInsideEffect,schemaStructWithTag,schemaSyncInEffect,schemaUnionOfLiterals,scopeInLayerEffect,serviceNotAsClass,strictBooleanExpressions,strictEffectProvide,tryCatchInEffectGen,unknownInEffectCatch,unnecessaryArrowBlock,unnecessaryEffectGen,unnecessaryFailYieldableError,unnecessaryPipe,unnecessaryPipeChain,unsafeEffectTypeAssertion,unsupportedServiceAccessors|}:\${2|off,warning,error,message,suggestion|}$0",
"insertText": "@effect-diagnostics \${1|anyUnknownInErrorContext,asyncFunction,catchAllToMapError,catchUnfailableEffect,classSelfMismatch,cryptoRandomUUID,cryptoRandomUUIDInEffect,deterministicKeys,duplicatePackage,effectDoNotation,effectFnIife,effectFnImplicitAny,effectFnOpportunity,effectGenUsesAdapter,effectInFailure,effectInVoidSuccess,effectMapFlatten,effectMapVoid,effectSucceedWithVoid,extendsNativeError,flatMapToMap,floatingEffect,genericEffectServices,globalConsole,globalConsoleInEffect,globalDate,globalDateInEffect,globalErrorInEffectCatch,globalErrorInEffectFailure,globalFetch,globalFetchInEffect,globalRandom,globalRandomInEffect,globalTimers,globalTimersInEffect,importFromBarrel,instanceOfSchema,layerMergeAllWithDependencies,lazyPromiseInEffectSync,leakingRequirements,missedPipeableOpportunity,missingEffectContext,missingEffectError,missingEffectServiceDependency,missingLayerContext,missingReturnYieldStar,missingStarInYieldEffectGen,multipleEffectProvide,nestedEffectGenYield,newPromise,nodeBuiltinImport,nonObjectEffectServiceType,outdatedApi,outdatedEffectCodegen,overriddenSchemaConstructor,preferSchemaOverJson,processEnv,processEnvInEffect,redundantLayerMergeAllInProvide,redundantSchemaTagIdentifier,returnEffectInGen,runEffectInsideEffect,schemaStructWithTag,schemaSyncInEffect,schemaUnionOfLiterals,scopeInLayerEffect,serviceNotAsClass,strictBooleanExpressions,strictEffectProvide,tryCatchInEffectGen,unknownInEffectCatch,unnecessaryArrowBlock,unnecessaryEffectGen,unnecessaryFailYieldableError,unnecessaryPipe,unnecessaryPipeChain,unsafeEffectTypeAssertion,unsupportedServiceAccessors|}:\${2|off,warning,error,message,suggestion|}$0",
"isSnippet": true,
"kind": "string",
"name": "@effect-diagnostics",
Expand All @@ -259,7 +259,7 @@ exports[`Completion effectDiagnosticsComment > effectDiagnosticsComment.ts at 2:
"sortText": "11",
},
{
"insertText": "@effect-diagnostics-next-line \${1|anyUnknownInErrorContext,asyncFunction,catchAllToMapError,catchUnfailableEffect,classSelfMismatch,cryptoRandomUUID,cryptoRandomUUIDInEffect,deterministicKeys,duplicatePackage,effectDoNotation,effectFnIife,effectFnImplicitAny,effectFnOpportunity,effectGenUsesAdapter,effectInFailure,effectInVoidSuccess,effectMapFlatten,effectMapVoid,effectSucceedWithVoid,extendsNativeError,flatMapToMap,floatingEffect,genericEffectServices,globalConsole,globalConsoleInEffect,globalDate,globalDateInEffect,globalErrorInEffectCatch,globalErrorInEffectFailure,globalFetch,globalFetchInEffect,globalRandom,globalRandomInEffect,globalTimers,globalTimersInEffect,importFromBarrel,instanceOfSchema,layerMergeAllWithDependencies,lazyPromiseInEffectSync,leakingRequirements,missedPipeableOpportunity,missingEffectContext,missingEffectError,missingEffectServiceDependency,missingLayerContext,missingReturnYieldStar,missingStarInYieldEffectGen,multipleEffectProvide,nestedEffectGenYield,newPromise,nodeBuiltinImport,nonObjectEffectServiceType,outdatedApi,outdatedEffectCodegen,overriddenSchemaConstructor,preferSchemaOverJson,processEnv,processEnvInEffect,redundantSchemaTagIdentifier,returnEffectInGen,runEffectInsideEffect,schemaStructWithTag,schemaSyncInEffect,schemaUnionOfLiterals,scopeInLayerEffect,serviceNotAsClass,strictBooleanExpressions,strictEffectProvide,tryCatchInEffectGen,unknownInEffectCatch,unnecessaryArrowBlock,unnecessaryEffectGen,unnecessaryFailYieldableError,unnecessaryPipe,unnecessaryPipeChain,unsafeEffectTypeAssertion,unsupportedServiceAccessors|}:\${2|off,warning,error,message,suggestion|}$0",
"insertText": "@effect-diagnostics-next-line \${1|anyUnknownInErrorContext,asyncFunction,catchAllToMapError,catchUnfailableEffect,classSelfMismatch,cryptoRandomUUID,cryptoRandomUUIDInEffect,deterministicKeys,duplicatePackage,effectDoNotation,effectFnIife,effectFnImplicitAny,effectFnOpportunity,effectGenUsesAdapter,effectInFailure,effectInVoidSuccess,effectMapFlatten,effectMapVoid,effectSucceedWithVoid,extendsNativeError,flatMapToMap,floatingEffect,genericEffectServices,globalConsole,globalConsoleInEffect,globalDate,globalDateInEffect,globalErrorInEffectCatch,globalErrorInEffectFailure,globalFetch,globalFetchInEffect,globalRandom,globalRandomInEffect,globalTimers,globalTimersInEffect,importFromBarrel,instanceOfSchema,layerMergeAllWithDependencies,lazyPromiseInEffectSync,leakingRequirements,missedPipeableOpportunity,missingEffectContext,missingEffectError,missingEffectServiceDependency,missingLayerContext,missingReturnYieldStar,missingStarInYieldEffectGen,multipleEffectProvide,nestedEffectGenYield,newPromise,nodeBuiltinImport,nonObjectEffectServiceType,outdatedApi,outdatedEffectCodegen,overriddenSchemaConstructor,preferSchemaOverJson,processEnv,processEnvInEffect,redundantLayerMergeAllInProvide,redundantSchemaTagIdentifier,returnEffectInGen,runEffectInsideEffect,schemaStructWithTag,schemaSyncInEffect,schemaUnionOfLiterals,scopeInLayerEffect,serviceNotAsClass,strictBooleanExpressions,strictEffectProvide,tryCatchInEffectGen,unknownInEffectCatch,unnecessaryArrowBlock,unnecessaryEffectGen,unnecessaryFailYieldableError,unnecessaryPipe,unnecessaryPipeChain,unsafeEffectTypeAssertion,unsupportedServiceAccessors|}:\${2|off,warning,error,message,suggestion|}$0",
"isSnippet": true,
"kind": "string",
"name": "@effect-diagnostics-next-line",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
multipleEffectProvide_fix from 430 to 464
multipleEffectProvide_skipNextLine from 430 to 464
multipleEffectProvide_skipFile from 430 to 464
multipleEffectProvide_fix from 564 to 598
multipleEffectProvide_skipNextLine from 564 to 598
multipleEffectProvide_skipFile from 564 to 598
multipleEffectProvide_fix from 663 to 697
multipleEffectProvide_skipNextLine from 663 to 697
multipleEffectProvide_skipFile from 663 to 697
multipleEffectProvide_fix from 793 to 827
multipleEffectProvide_skipNextLine from 793 to 827
multipleEffectProvide_skipFile from 793 to 827
multipleEffectProvide_fix from 553 to 587
multipleEffectProvide_skipNextLine from 553 to 587
multipleEffectProvide_skipFile from 553 to 587
multipleEffectProvide_fix from 687 to 721
multipleEffectProvide_skipNextLine from 687 to 721
multipleEffectProvide_skipFile from 687 to 721
multipleEffectProvide_fix from 786 to 820
multipleEffectProvide_skipNextLine from 786 to 820
multipleEffectProvide_skipFile from 786 to 820
multipleEffectProvide_fix from 916 to 950
multipleEffectProvide_skipNextLine from 916 to 950
multipleEffectProvide_skipFile from 916 to 950
multipleEffectProvide_fix from 1095 to 1151
multipleEffectProvide_skipNextLine from 1095 to 1151
multipleEffectProvide_skipFile from 1095 to 1151
multipleEffectProvide_fix from 1380 to 1406
multipleEffectProvide_skipNextLine from 1380 to 1406
multipleEffectProvide_skipFile from 1380 to 1406
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// code fix multipleEffectProvide_fix output for range 1095 - 1151
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

class MyService1 extends Effect.Service<MyService1>()("MyService1", {
succeed: { value: 1 }
}) {}

class MyService2 extends Effect.Service<MyService2>()("MyService2", {
succeed: { value: 2 }
}) {}

class MyService3 extends Effect.Service<MyService3>()("MyService3", {
succeed: { value: 3 }
}) {}

const layerTuple: [typeof MyService1.Default, typeof MyService2.Default] = [
MyService1.Default,
MyService2.Default
]

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.ignoreLogged,
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 shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default, MyService3.Default))
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)

export const shouldReportAfterTupleRewrite = Effect.void.pipe(
Effect.provide(layerTuple),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleTuple = Effect.void.pipe(
Effect.provide(layerTuple)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// code fix multipleEffectProvide_fix output for range 1380 - 1406
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

class MyService1 extends Effect.Service<MyService1>()("MyService1", {
succeed: { value: 1 }
}) {}

class MyService2 extends Effect.Service<MyService2>()("MyService2", {
succeed: { value: 2 }
}) {}

class MyService3 extends Effect.Service<MyService3>()("MyService3", {
succeed: { value: 3 }
}) {}

const layerTuple: [typeof MyService1.Default, typeof MyService2.Default] = [
MyService1.Default,
MyService2.Default
]

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.ignoreLogged,
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 shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)

export const shouldReportAfterTupleRewrite = Effect.void.pipe(
Effect.provide(Layer.mergeAll(...layerTuple, MyService3.Default))
)

export const shouldNotReportSingleTuple = Effect.void.pipe(
Effect.provide(layerTuple)
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// code fix multipleEffectProvide_fix output for range 553 - 587
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

class MyService1 extends Effect.Service<MyService1>()("MyService1", {
succeed: { value: 1 }
}) {}

class MyService2 extends Effect.Service<MyService2>()("MyService2", {
succeed: { value: 2 }
}) {}

class MyService3 extends Effect.Service<MyService3>()("MyService3", {
succeed: { value: 3 }
}) {}

const layerTuple: [typeof MyService1.Default, typeof MyService2.Default] = [
MyService1.Default,
MyService2.Default
]

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

export const shouldReportSeparately = Effect.void.pipe(
Effect.provide(MyService1.Default),
Effect.provide(MyService2.Default),
Effect.ignoreLogged,
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 shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)

export const shouldReportAfterTupleRewrite = Effect.void.pipe(
Effect.provide(layerTuple),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleTuple = Effect.void.pipe(
Effect.provide(layerTuple)
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ export const shouldReportSingle = Effect.void.pipe(
Effect.provide(MyService2.Default),
Effect.provide(MyService3.Default)
)

export const shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// code fix multipleEffectProvide_fix output for range 687 - 721
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

class MyService1 extends Effect.Service<MyService1>()("MyService1", {
succeed: { value: 1 }
}) {}

class MyService2 extends Effect.Service<MyService2>()("MyService2", {
succeed: { value: 2 }
}) {}

class MyService3 extends Effect.Service<MyService3>()("MyService3", {
succeed: { value: 3 }
}) {}

const layerTuple: [typeof MyService1.Default, typeof MyService2.Default] = [
MyService1.Default,
MyService2.Default
]

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

export const shouldReportSeparately = Effect.void.pipe(
Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default)),
Effect.ignoreLogged,
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 shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)

export const shouldReportAfterTupleRewrite = Effect.void.pipe(
Effect.provide(layerTuple),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleTuple = Effect.void.pipe(
Effect.provide(layerTuple)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// code fix multipleEffectProvide_fix output for range 786 - 820
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"

class MyService1 extends Effect.Service<MyService1>()("MyService1", {
succeed: { value: 1 }
}) {}

class MyService2 extends Effect.Service<MyService2>()("MyService2", {
succeed: { value: 2 }
}) {}

class MyService3 extends Effect.Service<MyService3>()("MyService3", {
succeed: { value: 3 }
}) {}

const layerTuple: [typeof MyService1.Default, typeof MyService2.Default] = [
MyService1.Default,
MyService2.Default
]

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.ignoreLogged,
Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default))
)

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

export const shouldReportAfterArrayRewrite = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default]),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleArray = Effect.void.pipe(
Effect.provide([MyService1.Default, MyService2.Default])
)

export const shouldReportAfterTupleRewrite = Effect.void.pipe(
Effect.provide(layerTuple),
Effect.provide(MyService3.Default)
)

export const shouldNotReportSingleTuple = Effect.void.pipe(
Effect.provide(layerTuple)
)
Loading