From 1bf4e3dcbc791e11d467721538b477db24e5411d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 10:02:43 +0000 Subject: [PATCH 1/5] chore: update generated/latest --- .changeset/catch-refail-tap-error.md | 5 + README.md | 1 + _packages/tsgo/src/metadata.json | 23 + docs/rules/catch-refail-to-tap-error.md | 68 + .../diagnostics/effectDiagnosticMessages.json | 4 + internal/rules/catch_refail_to_tap_error.go | 106 ++ internal/rules/rules.go | 1 + oxlint-presets/recommended.json | 1 + oxlint-presets/style.json | 1 + oxlint-schema.json | 3 + schema.json | 5 + shim/_backport/diagnostics/shim.go | 1 + shim/diagnostics/shim.go | 1 + .../catchRefailToTapError.errors.txt | 129 ++ ...pError.flows.catchRefailToTapError.mermaid | 692 ++++++++ .../effect-v4/catchRefailToTapError.flows.txt | 1 + .../catchRefailToTapError.layers.txt | 1 + .../catchRefailToTapError.pipings.txt | 1397 +++++++++++++++++ .../catchRefailToTapError.quickfixes.txt | 129 ++ .../catchRefailToTapError_preview.errors.txt | 21 + ...lows.catchRefailToTapError_preview.mermaid | 20 + .../catchRefailToTapError_preview.flows.txt | 1 + .../catchRefailToTapError_preview.layers.txt | 1 + .../catchRefailToTapError_preview.pipings.txt | 43 + ...tchRefailToTapError_preview.quickfixes.txt | 13 + .../tests/effect-v4/catchRefailToTapError.ts | 86 + .../catchRefailToTapError_preview.ts | 11 + 27 files changed, 2765 insertions(+) create mode 100644 .changeset/catch-refail-tap-error.md create mode 100644 docs/rules/catch-refail-to-tap-error.md create mode 100644 internal/rules/catch_refail_to_tap_error.go create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.errors.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.catchRefailToTapError.mermaid create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.layers.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.pipings.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError.quickfixes.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.errors.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.catchRefailToTapError_preview.mermaid create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.layers.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.pipings.txt create mode 100644 testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.quickfixes.txt create mode 100644 testdata/tests/effect-v4/catchRefailToTapError.ts create mode 100644 testdata/tests/effect-v4/catchRefailToTapError_preview.ts diff --git a/.changeset/catch-refail-tap-error.md b/.changeset/catch-refail-tap-error.md new file mode 100644 index 00000000..757c7cfd --- /dev/null +++ b/.changeset/catch-refail-tap-error.md @@ -0,0 +1,5 @@ +--- +"@effect/tsgo": minor +--- + +Add the v4-only `catchRefailToTapError` diagnostic. It suggests `Effect.tapError` when an `Effect.catch` handler sequences an effect with `Effect.andThen` or a zero-argument `Effect.flatMap` callback and then fails with the original, unmodified error. Generator handlers and selective catches are excluded. diff --git a/README.md b/README.md index db5e6543..658c6bcd 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ Some diagnostics are off by default or have a default severity of suggestion, bu catchConditionalRefailToCatchIfSuggests Effect.catchIf, Effect.catchCauseIf, or Effect.catchTag for conditional catch handlers that re-fail their untouched input catchDieToOrDieSuggests using Effect.orDie instead of Effect.catch or Effect.catchAll with an identity-forwarding Effect.die handler catchIfTagToCatchTagSuggests Effect.catchTag instead of Effect.catchIf with a direct _tag equality predicate + catchRefailToTapErrorSuggests Effect.tapError for catch handlers that sequence an effect and then re-fail the original error catchTagToCatchReasonSuggests Effect.catchReason or Effect.catchReasons for handlers that re-fail unmatched reason._tag branches catchToIgnoreSuggests using Effect.ignore or Effect.ignoreCause instead of Effect.catch/catchCause returning Effect.void catchToOrElseSucceedSuggests using Effect.orElseSucceed instead of Effect.catch + Effect.succeed diff --git a/_packages/tsgo/src/metadata.json b/_packages/tsgo/src/metadata.json index e9420a43..d00bbb9b 100644 --- a/_packages/tsgo/src/metadata.json +++ b/_packages/tsgo/src/metadata.json @@ -1771,6 +1771,29 @@ ] } }, + { + "name": "catchRefailToTapError", + "group": "style", + "description": "Suggests Effect.tapError for catch handlers that sequence an effect and then re-fail the original error", + "defaultSeverity": "suggestion", + "fixable": false, + "supportedEffect": [ + "v4" + ], + "codes": [ + 377133 + ], + "preview": { + "sourceText": "import { Effect } from \"effect\"\n\ndeclare const save: Effect.Effect\u003cvoid, Error\u003e\ndeclare const rollback: Effect.Effect\u003cvoid\u003e\n\nexport const program = save.pipe(\n Effect.catch(error =\u003e rollback.pipe(Effect.andThen(Effect.fail(error))))\n)\n", + "diagnostics": [ + { + "start": 161, + "end": 173, + "text": "Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError)" + } + ] + } + }, { "name": "catchTagToCatchReason", "group": "style", diff --git a/docs/rules/catch-refail-to-tap-error.md b/docs/rules/catch-refail-to-tap-error.md new file mode 100644 index 00000000..50c5c9b9 --- /dev/null +++ b/docs/rules/catch-refail-to-tap-error.md @@ -0,0 +1,68 @@ + + +# `catchRefailToTapError` + +Suggests Effect.tapError for catch handlers that sequence an effect and then re-fail the original error + +| Property | Value | +| --- | --- | +| Category | Style | +| Default severity | `suggestion` | +| Fixable | No | +| Effect versions | v4 | +| Diagnostic codes | `TS377133` | +| Language Service name | `catchRefailToTapError` | +| Oxlint name | `effecttsgo/catch-refail-to-tap-error` | + +## Preview + +```ts +import { Effect } from "effect" + +declare const save: Effect.Effect +declare const rollback: Effect.Effect + +export const program = save.pipe( + Effect.catch(error => rollback.pipe(Effect.andThen(Effect.fail(error)))) +/** + ^^^^^^^^^^^^ effecttsgo(catch-refail-to-tap-error): Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. +*/ +) +``` + +## Language Service Configuration + +See the [Language Service setup guide](../../README.md#installation) for installation instructions. + +```jsonc +{ + "$schema": "./node_modules/@effect/tsgo/schema.json", + "compilerOptions": { + "plugins": [ + { + "name": "@effect/language-service", + "diagnosticSeverity": { + "catchRefailToTapError": "warning" + } + } + ] + } +} +``` + +## Oxlint Configuration + +See the [Oxlint setup guide](../README.md#oxlint-setup) for installation and patching instructions. + +```json +{ + "$schema": "./node_modules/@effect/tsgo/oxlint-schema.json", + "options": { + "typeAware": true + }, + "plugins": ["effecttsgo"], + "rules": { + "effecttsgo/catch-refail-to-tap-error": "warn" + } +} +``` diff --git a/internal/diagnostics/effectDiagnosticMessages.json b/internal/diagnostics/effectDiagnosticMessages.json index 14c2b0b1..1db9e0fa 100644 --- a/internal/diagnostics/effectDiagnosticMessages.json +++ b/internal/diagnostics/effectDiagnosticMessages.json @@ -519,6 +519,10 @@ "category": "Suggestion", "code": 377130 }, + "Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError)": { + "category": "Suggestion", + "code": 377133 + }, "`Effect.andThen` expresses this sequencing more directly than `Effect.flatMap` with a zero-parameter callback. effect(flatMapIgnoredParamToAndThen)": { "category": "Suggestion", "code": 377132 diff --git a/internal/rules/catch_refail_to_tap_error.go b/internal/rules/catch_refail_to_tap_error.go new file mode 100644 index 00000000..152988d9 --- /dev/null +++ b/internal/rules/catch_refail_to_tap_error.go @@ -0,0 +1,106 @@ +package rules + +import ( + "github.com/effect-ts/tsgo/etscore" + "github.com/effect-ts/tsgo/internal/rule" + "github.com/effect-ts/tsgo/internal/typeparser" + "github.com/microsoft/TypeScript/tsc/shim/ast" + "github.com/microsoft/TypeScript/tsc/shim/checker" + tsdiag "github.com/microsoft/TypeScript/tsc/shim/diagnostics" + "github.com/microsoft/TypeScript/tsc/shim/scanner" +) + +// CatchRefailToTapError recognizes observation followed by an unchanged refail. +var CatchRefailToTapError = rule.Rule{ + Name: "catchRefailToTapError", + Group: "style", + Description: "Suggests Effect.tapError for catch handlers that sequence an effect and then re-fail the original error", + DefaultSeverity: etscore.SeveritySuggestion, + SupportedEffect: []string{"v4"}, + Codes: []int32{ + tsdiag.Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError.Code(), + }, + Run: func(ctx *rule.Context) []*ast.Diagnostic { + tp := ctx.TypeParser + if tp.SupportedEffectVersion() != typeparser.EffectMajorV4 { + return nil + } + var diagnostics []*ast.Diagnostic + for _, flow := range tp.PipingFlows(ctx.SourceFile, true) { + for i := range flow.Transformations { + step := &flow.Transformations[i] + if len(step.Args) != 1 || !tp.IsNodeReferenceToEffectModuleApi(step.Callee, "catch") { + continue + } + input := tp.StrictEffectType(flow.TransformationInputType(i)) + if input == nil || input.E == nil || input.E.Flags()&checker.TypeFlagsNever != 0 || + !catchHandlerRefailsOriginalError(tp, ctx.Checker, step.Args[0]) { + continue + } + diagnostics = append(diagnostics, ctx.NewDiagnostic( + ctx.SourceFile, + scanner.GetErrorRangeForNode(ctx.SourceFile, step.Callee), + tsdiag.Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError, + nil, + )) + } + } + return diagnostics + }, +} + +func catchHandlerRefailsOriginalError(tp *typeparser.TypeParser, c *checker.Checker, handler *ast.Node) bool { + lazy := typeparser.ParseLazyExpression(handler, typeparser.LazyExpressionNone) + if lazy == nil || len(lazy.Params) != 1 { + return false + } + parameter := lazy.Params[0].AsParameterDeclaration() + if parameter.Name() == nil || parameter.Name().Kind != ast.KindIdentifier || + parameter.Initializer != nil || parameter.DotDotDotToken != nil { + return false + } + errorSymbol := tp.GetSymbolAtLocation(parameter.Name()) + if errorSymbol == nil || checker.Checker_isSymbolAssigned(c, errorSymbol) { + return false + } + + flow := tp.LongestPipingFlowAt(lazy.Expression, false) + if flow == nil || len(flow.Transformations) == 0 { + return false + } + last := len(flow.Transformations) - 1 + step := &flow.Transformations[last] + if len(step.Args) != 1 || tp.StrictEffectType(flow.TransformationInputType(last)) == nil { + return false + } + + refail := step.Args[0] + switch { + case tp.IsNodeReferenceToEffectModuleApi(step.Callee, "andThen"): + // andThen accepts both an Effect and a callback. Only a zero-argument + // callback can be discarded without binding the preceding success value. + if thunk := typeparser.ParseLazyExpression(refail, typeparser.LazyExpressionThunk); thunk != nil { + refail = thunk.Expression + } + case tp.IsNodeReferenceToEffectModuleApi(step.Callee, "flatMap"): + thunk := typeparser.ParseLazyExpression(refail, typeparser.LazyExpressionThunk) + if thunk == nil { + return false + } + refail = thunk.Expression + default: + return false + } + + // Matching the whole inner flow excludes recovery or other work after fail, + // and excludes expressions which merely compute a different error value. + return tp.LongestPipingFlowAt(refail, false).MatchesExactly( + func(subject *typeparser.PipingFlowSubject) bool { + node := ast.SkipParentheses(subject.Node) + return node != nil && node.Kind == ast.KindIdentifier && tp.GetSymbolAtLocation(node) == errorSymbol + }, + func(step *typeparser.PipingFlowTransformation) bool { + return len(step.Args) == 0 && tp.IsNodeReferenceToEffectModuleApi(step.Callee, "fail") + }, + ) +} diff --git a/internal/rules/rules.go b/internal/rules/rules.go index 6b1eb7ed..7be76974 100644 --- a/internal/rules/rules.go +++ b/internal/rules/rules.go @@ -18,6 +18,7 @@ var All = []rule.Rule{ CatchDieToOrDie, TimeoutCatchTagToTimeoutOrElse, CatchAllToMapError, + CatchRefailToTapError, CatchAllTagDispatchToCatchTag, CatchIfTagToCatchTag, CatchConditionalRefailToCatchIf, diff --git a/oxlint-presets/recommended.json b/oxlint-presets/recommended.json index e6348861..f95a5ba7 100644 --- a/oxlint-presets/recommended.json +++ b/oxlint-presets/recommended.json @@ -16,6 +16,7 @@ "effecttsgo/catch-conditional-refail-to-catch-if": "warn", "effecttsgo/catch-die-to-or-die": "warn", "effecttsgo/catch-if-tag-to-catch-tag": "warn", + "effecttsgo/catch-refail-to-tap-error": "warn", "effecttsgo/catch-tag-to-catch-reason": "warn", "effecttsgo/catch-to-ignore": "warn", "effecttsgo/catch-to-or-else-succeed": "warn", diff --git a/oxlint-presets/style.json b/oxlint-presets/style.json index 720851ac..505518ed 100644 --- a/oxlint-presets/style.json +++ b/oxlint-presets/style.json @@ -14,6 +14,7 @@ "effecttsgo/catch-conditional-refail-to-catch-if": "warn", "effecttsgo/catch-die-to-or-die": "warn", "effecttsgo/catch-if-tag-to-catch-tag": "warn", + "effecttsgo/catch-refail-to-tap-error": "warn", "effecttsgo/catch-tag-to-catch-reason": "warn", "effecttsgo/catch-to-ignore": "warn", "effecttsgo/catch-to-or-else-succeed": "warn", diff --git a/oxlint-schema.json b/oxlint-schema.json index 4707987a..5cfe59d0 100644 --- a/oxlint-schema.json +++ b/oxlint-schema.json @@ -2266,6 +2266,9 @@ "effecttsgo/catch-if-tag-to-catch-tag": { "$ref": "#/definitions/RuleNoConfig" }, + "effecttsgo/catch-refail-to-tap-error": { + "$ref": "#/definitions/RuleNoConfig" + }, "effecttsgo/catch-tag-to-catch-reason": { "$ref": "#/definitions/RuleNoConfig" }, diff --git a/schema.json b/schema.json index 1dd8ebe8..1b8bb790 100644 --- a/schema.json +++ b/schema.json @@ -2342,6 +2342,11 @@ "default": "suggestion", "description": "Suggests Effect.catchTag instead of Effect.catchIf with a direct _tag equality predicate" }, + "catchRefailToTapError": { + "$ref": "#/definitions/effectLanguageServicePluginSeverityDefinition", + "default": "suggestion", + "description": "Suggests Effect.tapError for catch handlers that sequence an effect and then re-fail the original error" + }, "catchTagToCatchReason": { "$ref": "#/definitions/effectLanguageServicePluginSeverityDefinition", "default": "suggestion", diff --git a/shim/_backport/diagnostics/shim.go b/shim/_backport/diagnostics/shim.go index 2e9a7149..f8da8e92 100644 --- a/shim/_backport/diagnostics/shim.go +++ b/shim/_backport/diagnostics/shim.go @@ -2048,6 +2048,7 @@ var Updating_unchanged_output_timestamps_of_project_0 = diagnostics.Updating_unc var Use_0 = diagnostics.Use_0 var Use_0_instead = diagnostics.Use_0_instead var Use_Effect_0_to_handle_this_timeout_directly_effect_timeoutCatchTagToTimeoutOrElse = diagnostics.Use_Effect_0_to_handle_this_timeout_directly_effect_timeoutCatchTagToTimeoutOrElse +var Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError = diagnostics.Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError var Use_Number_isNaN_in_all_conditions = diagnostics.Use_Number_isNaN_in_all_conditions var Use_element_access_for_0 = diagnostics.Use_element_access_for_0 var Use_element_access_for_all_undeclared_properties = diagnostics.Use_element_access_for_all_undeclared_properties diff --git a/shim/diagnostics/shim.go b/shim/diagnostics/shim.go index f5a645ea..d12eedf6 100644 --- a/shim/diagnostics/shim.go +++ b/shim/diagnostics/shim.go @@ -2034,6 +2034,7 @@ var Updating_unchanged_output_timestamps_of_project_0 = diagnostics.Updating_unc var Use_0 = diagnostics.Use_0 var Use_0_instead = diagnostics.Use_0_instead var Use_Effect_0_to_handle_this_timeout_directly_effect_timeoutCatchTagToTimeoutOrElse = diagnostics.Use_Effect_0_to_handle_this_timeout_directly_effect_timeoutCatchTagToTimeoutOrElse +var Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError = diagnostics.Use_Effect_tapError_to_observe_the_error_and_preserve_the_original_failure_without_having_to_re_fail_it_effect_catchRefailToTapError var Use_Number_isNaN_in_all_conditions = diagnostics.Use_Number_isNaN_in_all_conditions var Use_element_access_for_0 = diagnostics.Use_element_access_for_0 var Use_element_access_for_all_undeclared_properties = diagnostics.Use_element_access_for_all_undeclared_properties diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.errors.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError.errors.txt new file mode 100644 index 00000000..069c7bd9 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.errors.txt @@ -0,0 +1,129 @@ +=== Metadata === +Effect version: 4.0.0 + +/.src/catchRefailToTapError.ts(14,33): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(15,39): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(16,39): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(17,26): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(18,33): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(19,42): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(20,24): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(21,33): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(24,35): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(25,39): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(29,38): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) +/.src/catchRefailToTapError.ts(30,42): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + + +==== /.src/catchRefailToTapError.ts (12 errors) ==== + // @effect-v4 + // @effect-diagnostics *:off + // @effect-diagnostics catchRefailToTapError:warning + import { Effect, pipe } from "effect" + import { catch as recover, andThen as sequence, fail as refail } from "effect/Effect" + + declare const task: Effect.Effect + declare const observe: Effect.Effect + declare const fallibleObserve: Effect.Effect + declare const otherError: Error + declare const condition: boolean + + // Supported: direct effects and zero-argument continuations, across call forms. + export const direct = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const andThenThunk = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(() => Effect.fail(error))))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const flatMapThunk = task.pipe(Effect.catch(error => observe.pipe(Effect.flatMap(() => Effect.fail(error))))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const dataFirst = Effect.catch(task, error => Effect.andThen(observe, Effect.fail(error))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const dataFirstFlatMap = Effect.catch(task, error => Effect.flatMap(observe, () => Effect.fail(error))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const standalonePipe = pipe(task, Effect.catch(error => pipe(observe, Effect.andThen(pipe(error, Effect.fail))))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const curried = Effect.catch(error => Effect.andThen(Effect.fail(error))(observe))(task) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const blocks = task.pipe(Effect.catch(function(error) { + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + return observe.pipe(Effect.flatMap(function() { return Effect.fail((error)) })) + })) + export const aliases = pipe(task, recover(error => sequence(refail(error))(observe))) + ~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const earlierSteps = task.pipe(Effect.catch(error => observe.pipe( + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Effect.andThen(observe), + Effect.andThen(Effect.fail(error)) + ))) + export const sideCanFail = task.pipe(Effect.catch(error => fallibleObserve.pipe(Effect.andThen(Effect.fail(error))))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + export const conditionalSide = task.pipe(Effect.catch(error => (condition ? observe : fallibleObserve).pipe( + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Effect.andThen(Effect.fail(error)) + ))) + + // Unsupported or unsafe: the original error must be re-failed unconditionally. + export const justRefail = task.pipe(Effect.catch(error => Effect.fail(error))) + export const mappedError = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(new Error(error.message)))))) + export const otherBinding = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(otherError))))) + export const property = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error.message))))) + export const conditionalRefail = task.pipe(Effect.catch(error => observe.pipe( + Effect.flatMap(() => condition ? Effect.fail(error) : Effect.void) + ))) + export const afterRefail = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(Effect.fail(error)), + Effect.catch(() => Effect.void) + ))) + export const innerRecovery = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(Effect.fail(error).pipe(Effect.catch(() => Effect.void))) + ))) + export const parameterizedFlatMap = task.pipe(Effect.catch(error => observe.pipe( + Effect.flatMap(_value => Effect.fail(error)) + ))) + export const parameterizedAndThen = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(_value => Effect.fail(error)) + ))) + export const shadowedError = task.pipe(Effect.catch(error => Effect.succeed(otherError).pipe( + Effect.flatMap(error => Effect.fail(error)) + ))) + export const assignedError = task.pipe(Effect.catch(error => Effect.sync(() => { + error = otherError + }).pipe(Effect.flatMap(() => Effect.fail(error))))) + export const defaultParameter = task.pipe(Effect.catch((error = otherError) => observe.pipe(Effect.andThen(Effect.fail(error))))) + export const destructured = task.pipe(Effect.catch(({ message }) => observe.pipe(Effect.andThen(Effect.fail(message))))) + export const statements = task.pipe(Effect.catch(error => { + const side = observe + return side.pipe(Effect.andThen(Effect.fail(error))) + })) + export const generator = task.pipe(Effect.catch(error => Effect.gen(function*() { + yield* observe + return yield* Effect.fail(error) + }))) + export const differentCombinator = task.pipe(Effect.catch(error => observe.pipe(Effect.as(Effect.fail(error))))) + export const failMappedSubject = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(pipe(error, e => new Error(e.message), Effect.fail)) + ))) + export const unfailable = Effect.void.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) + + declare const tagged: Effect.Effect + export const selective = tagged.pipe(Effect.catchTag("Oops", error => observe.pipe(Effect.andThen(Effect.fail(error))))) + + // A same-named local API must not be mistaken for the Effect module. + const custom = { + andThen: (next: Effect.Effect) => (_self: Effect.Effect) => next, + fail: (error: Error) => Effect.fail(error) + } + export const customAndThen = task.pipe(Effect.catch(error => custom.andThen(Effect.fail(error))(observe))) + export const customFail = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(custom.fail(error))))) + diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.catchRefailToTapError.mermaid b/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.catchRefailToTapError.mermaid new file mode 100644 index 00000000..94a8f5dd --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.catchRefailToTapError.mermaid @@ -0,0 +1,692 @@ +flowchart TB + 0[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 1["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 2[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 3[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 4[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 5["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 6[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 7[/"type: Error
node: error"/] + 8["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 9[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 10[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 11["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;#93;"] + 12[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 13[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;"]] + 14[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 15["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;#40;#41; =#gt; Effect.fail#40;error#41;#93;"] + 16[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 17[["type: #40;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;#41; =#gt; Effect.fail#40;error#41;"]] + 18[/"type: Error
node: error"/] + 19["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 20[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 21[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 22["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.flatMap#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;#93;"] + 23[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 24[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.flatMap#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;"]] + 25[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 26["type: Effect#lt;never, Error, never#gt;
callee: Effect.flatMap
args: #91;#40;#41; =#gt; Effect.fail#40;error#41;#93;"] + 27[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 28[["type: #40;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;#41; =#gt; Effect.fail#40;error#41;"]] + 29[/"type: Error
node: error"/] + 30["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 31[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 32[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 33["type: Effect#lt;number, Error, never#gt;
callee:
args: #91;#93;"] + 34[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 35[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.andThen#40;observe, Effect.fail#40;error#41;#41;"]] + 36[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 37["type: Effect#lt;never, Error, never#gt;
callee:
args: #91;#93;"] + 38[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 39[/"type: Error
node: error"/] + 40["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 41[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 42[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 43["type: Effect#lt;number, Error, never#gt;
callee:
args: #91;#93;"] + 44[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 45[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.flatMap#40;observe, #40;#41; =#gt; Effect.fail#40;error#41;#41;"]] + 46[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 47["type: Effect#lt;never, Error, never#gt;
callee:
args: #91;#93;"] + 48[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 49[["type: #40;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;#41; =#gt; Effect.fail#40;error#41;"]] + 50[/"type: Error
node: error"/] + 51["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 52[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 53[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 54["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; pipe#40;observe, Effect.andThen#40;pipe#40;error, Effect.fail#41;#41;#41;#93;"] + 55[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 56[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; pipe#40;observe, Effect.andThen#40;pipe#40;error, Effect.fail#41;#41;#41;"]] + 57[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 58["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;pipe#40;error, Effect.fail#41;#93;"] + 59[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 60[/"type: Error
node: error"/] + 61["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 62[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 63["type: Effect#lt;number, unknown, never#gt;
callee: Effect.catch
args: #91;error =#gt; Effect.andThen#40;Effect.fail#40;error#41;#41;#40;observe#41;#93;"] + 64[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 65[["type: #40;error: unknown#41; =#gt; Effect#lt;never, unknown, never#gt;
node: error =#gt; Effect.andThen#40;Effect.fail#40;error#41;#41;#40;observe#41;"]] + 66[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 67["type: Effect#lt;never, unknown, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 68[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 69[/"type: unknown
node: error"/] + 70["type: Effect#lt;never, unknown, never#gt;
callee: Effect.fail
args: #91;#93;"] + 71[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 72[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 73["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;function#40;error#41; #123;#92;n return observe.pipe#40;Effect.flatMap#40;function#40;#41; #123; return Effect.fail#40;#40;error#41;#41; #125;#41;#41;#92;n#125;#93;"] + 74[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 75[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: function#40;error#41; #123;#92;n return observe.pipe#40;Effect.flatMap#40;function#40;#41; #123; return Effect.fail#40;#40;error#41;#41; #125;#41;#41;#92;n#125;"]] + 76[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 77["type: Effect#lt;never, Error, never#gt;
callee: Effect.flatMap
args: #91;function#40;#41; #123; return Effect.fail#40;#40;error#41;#41; #125;#93;"] + 78[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 79[["type: #40;#41; =#gt; Effect#lt;never, Error, never#gt;
node: function#40;#41; #123; return Effect.fail#40;#40;error#41;#41; #125;"]] + 80[/"type: Error
node: #40;error#41;"/] + 81["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 82[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 83[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 84["type: Effect#lt;number, Error, never#gt;
callee: recover
args: #91;error =#gt; sequence#40;refail#40;error#41;#41;#40;observe#41;#93;"] + 85[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: recover"/] + 86[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; sequence#40;refail#40;error#41;#41;#40;observe#41;"]] + 87[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 88["type: Effect#lt;never, Error, never#gt;
callee: sequence
args: #91;refail#40;error#41;#93;"] + 89[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: sequence"/] + 90[/"type: Error
node: error"/] + 91["type: Effect#lt;never, Error, never#gt;
callee: refail
args: #91;#93;"] + 92[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: refail"/] + 93[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 94["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.andThen#40;observe#41;,#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;#92;n#41;#93;"] + 95[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 96[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.andThen#40;observe#41;,#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;#92;n#41;"]] + 97[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 98["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;observe#93;"] + 99[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 100[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 101["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 102[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 103[/"type: Error
node: error"/] + 104["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 105[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 106[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 107["type: Effect#lt;number, string #124; Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; fallibleObserve.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 108[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 109[["type: #40;error: Error#41; =#gt; Effect#lt;never, string #124; Error, never#gt;
node: error =#gt; fallibleObserve.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 110[/"type: Effect#lt;void, string, never#gt;
node: fallibleObserve"/] + 111["type: Effect#lt;never, string #124; Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 112[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 113[/"type: Error
node: error"/] + 114["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 115[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 116[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 117["type: Effect#lt;number, string #124; Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; #40;condition ? observe : fallibleObserve#41;.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;#92;n#41;#93;"] + 118[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 119[["type: #40;error: Error#41; =#gt; Effect#lt;never, string #124; Error, never#gt;
node: error =#gt; #40;condition ? observe : fallibleObserve#41;.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;#92;n#41;"]] + 120[/"type: Effect#lt;void, string, never#gt;
node: #40;condition ? observe : fallibleObserve#41;"/] + 121["type: Effect#lt;never, string #124; Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 122[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 123[/"type: Error
node: error"/] + 124["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 125[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 126[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 127["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; Effect.fail#40;error#41;#93;"] + 128[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 129[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.fail#40;error#41;"]] + 130[/"type: Error
node: error"/] + 131["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 132[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 133[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 134["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;new Error#40;error.message#41;#41;#41;#41;#93;"] + 135[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 136[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;new Error#40;error.message#41;#41;#41;#41;"]] + 137[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 138["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;new Error#40;error.message#41;#41;#93;"] + 139[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 140[/"type: Error
node: new Error#40;error.message#41;"/] + 141["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 142[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 143[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 144["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;otherError#41;#41;#41;#93;"] + 145[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 146[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;otherError#41;#41;#41;"]] + 147[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 148["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;otherError#41;#93;"] + 149[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 150[/"type: Error
node: otherError"/] + 151["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 152[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 153[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 154["type: Effect#lt;number, string, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error.message#41;#41;#41;#93;"] + 155[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 156[["type: #40;error: Error#41; =#gt; Effect#lt;never, string, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error.message#41;#41;#41;"]] + 157[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 158["type: Effect#lt;never, string, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error.message#41;#93;"] + 159[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 160[/"type: string
node: error.message"/] + 161["type: Effect#lt;never, string, never#gt;
callee: Effect.fail
args: #91;#93;"] + 162[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 163[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 164["type: Effect#lt;void #124; number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.flatMap#40;#40;#41; =#gt; condition ? Effect.fail#40;error#41; : Effect.void#41;#92;n#41;#93;"] + 165[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 166[["type: #40;error: Error#41; =#gt; Effect#lt;void, Error, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.flatMap#40;#40;#41; =#gt; condition ? Effect.fail#40;error#41; : Effect.void#41;#92;n#41;"]] + 167[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 168["type: Effect#lt;void, Error, never#gt;
callee: Effect.flatMap
args: #91;#40;#41; =#gt; condition ? Effect.fail#40;error#41; : Effect.void#93;"] + 169[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 170[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt; #124; Effect#lt;never, Error, never#gt;
node: #40;#41; =#gt; condition ? Effect.fail#40;error#41; : Effect.void"]] + 171[/"type: Effect#lt;void, never, never#gt; #124; Effect#lt;never, Error, never#gt;
node: condition ? Effect.fail#40;error#41; : Effect.void"/] + 172[/"type: Error
node: error"/] + 173["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 174[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 175[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 176["type: Effect#lt;void #124; number, never, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;,#92;n Effect.catch#40;#40;#41; =#gt; Effect.void#41;#92;n#41;#93;"] + 177[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 178[["type: #40;error: Error#41; =#gt; Effect#lt;void, never, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;#41;,#92;n Effect.catch#40;#40;#41; =#gt; Effect.void#41;#92;n#41;"]] + 179[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 180["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 181[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 182[/"type: Error
node: error"/] + 183["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 184[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 185["type: Effect#lt;void, never, never#gt;
callee: Effect.catch
args: #91;#40;#41; =#gt; Effect.void#93;"] + 186[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 187[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;#41; =#gt; Effect.void"]] + 188[/"type: Effect#lt;void, never, never#gt;
node: Effect.void"/] + 189[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 190["type: Effect#lt;void #124; number, never, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;.pipe#40;Effect.catch#40;#40;#41; =#gt; Effect.void#41;#41;#41;#92;n#41;#93;"] + 191[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 192[["type: #40;error: Error#41; =#gt; Effect#lt;void, never, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.andThen#40;Effect.fail#40;error#41;.pipe#40;Effect.catch#40;#40;#41; =#gt; Effect.void#41;#41;#41;#92;n#41;"]] + 193[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 194["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;.pipe#40;Effect.catch#40;#40;#41; =#gt; Effect.void#41;#41;#93;"] + 195[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 196[/"type: Error
node: error"/] + 197["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 198[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 199["type: Effect#lt;void, never, never#gt;
callee: Effect.catch
args: #91;#40;#41; =#gt; Effect.void#93;"] + 200[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 201[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;#41; =#gt; Effect.void"]] + 202[/"type: Effect#lt;void, never, never#gt;
node: Effect.void"/] + 203[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 204["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.flatMap#40;_value =#gt; Effect.fail#40;error#41;#41;#92;n#41;#93;"] + 205[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 206[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.flatMap#40;_value =#gt; Effect.fail#40;error#41;#41;#92;n#41;"]] + 207[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 208["type: Effect#lt;never, Error, never#gt;
callee: Effect.flatMap
args: #91;_value =#gt; Effect.fail#40;error#41;#93;"] + 209[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 210[["type: #40;_value: void#41; =#gt; Effect#lt;never, Error, never#gt;
node: _value =#gt; Effect.fail#40;error#41;"]] + 211[/"type: Error
node: error"/] + 212["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 213[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 214[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 215["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.andThen#40;_value =#gt; Effect.fail#40;error#41;#41;#92;n#41;#93;"] + 216[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 217[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.andThen#40;_value =#gt; Effect.fail#40;error#41;#41;#92;n#41;"]] + 218[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 219["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;_value =#gt; Effect.fail#40;error#41;#93;"] + 220[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 221[["type: #40;_value: void#41; =#gt; Effect#lt;never, Error, never#gt;
node: _value =#gt; Effect.fail#40;error#41;"]] + 222[/"type: Error
node: error"/] + 223["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 224[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 225[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 226["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; Effect.succeed#40;otherError#41;.pipe#40;#92;n Effect.flatMap#40;error =#gt; Effect.fail#40;error#41;#41;#92;n#41;#93;"] + 227[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 228[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.succeed#40;otherError#41;.pipe#40;#92;n Effect.flatMap#40;error =#gt; Effect.fail#40;error#41;#41;#92;n#41;"]] + 229[/"type: Error
node: otherError"/] + 230["type: Effect#lt;Error, never, never#gt;
callee: Effect.succeed
args: #91;#93;"] + 231[/"type: #lt;A#gt;#40;value: A#41; =#gt; Effect#lt;A, never, never#gt;
node: Effect.succeed"/] + 232["type: Effect#lt;never, Error, never#gt;
callee: Effect.flatMap
args: #91;error =#gt; Effect.fail#40;error#41;#93;"] + 233[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 234[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.fail#40;error#41;"]] + 235[/"type: Error
node: error"/] + 236["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 237[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 238[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 239["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; Effect.sync#40;#40;#41; =#gt; #123;#92;n error = otherError#92;n#125;#41;.pipe#40;Effect.flatMap#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;#93;"] + 240[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 241[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.sync#40;#40;#41; =#gt; #123;#92;n error = otherError#92;n#125;#41;.pipe#40;Effect.flatMap#40;#40;#41; =#gt; Effect.fail#40;error#41;#41;#41;"]] + 242[["type: #40;#41; =#gt; void
node: #40;#41; =#gt; #123;#92;n error = otherError#92;n#125;"]] + 243["type: Effect#lt;void, never, never#gt;
callee: Effect.sync
args: #91;#93;"] + 244[/"type: #lt;A#gt;#40;thunk: LazyArg#lt;A#gt;#41; =#gt; Effect#lt;A, never, never#gt;
node: Effect.sync"/] + 245["type: Effect#lt;never, Error, never#gt;
callee: Effect.flatMap
args: #91;#40;#41; =#gt; Effect.fail#40;error#41;#93;"] + 246[/"type: #123; #lt;A, B, E1, R1#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E1, R #124; R1#gt;; #lt;A, E, R, B, E1, R1#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E1, R1#gt;#41;: Effect#lt;B, E #124; E1, R #124; R1#gt;; #125;
node: Effect.flatMap"/] + 247[["type: #40;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;#41; =#gt; Effect.fail#40;error#41;"]] + 248[/"type: Error
node: error"/] + 249["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 250[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 251[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 252["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;#40;error = otherError#41; =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 253[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 254[["type: #40;error?: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;error = otherError#41; =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 255[/"type: Error
node: otherError"/] + 256[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 257["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 258[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 259[/"type: Error
node: error"/] + 260["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 261[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 262[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 263["type: Effect#lt;number, string, never#gt;
callee: Effect.catch
args: #91;#40;#123; message #125;#41; =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;message#41;#41;#41;#93;"] + 264[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 265[["type: #40;#123; message #125;: Error#41; =#gt; Effect#lt;never, string, never#gt;
node: #40;#123; message #125;#41; =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;message#41;#41;#41;"]] + 266[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 267["type: Effect#lt;never, string, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;message#41;#93;"] + 268[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 269[/"type: string
node: message"/] + 270["type: Effect#lt;never, string, never#gt;
callee: Effect.fail
args: #91;#93;"] + 271[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 272[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 273["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; #123;#92;n const side = observe#92;n return side.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#92;n#125;#93;"] + 274[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 275[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; #123;#92;n const side = observe#92;n return side.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#92;n#125;"]] + 276[/"type: Effect#lt;void, never, never#gt;
node: side"/] + 277["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 278[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 279[/"type: Error
node: error"/] + 280["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 281[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 282[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 283["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; Effect.gen#40;function*#40;#41; #123;#92;n yield* observe#92;n return yield* Effect.fail#40;error#41;#92;n#125;#41;#93;"] + 284[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 285[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; Effect.gen#40;function*#40;#41; #123;#92;n yield* observe#92;n return yield* Effect.fail#40;error#41;#92;n#125;#41;"]] + 286((("type: Effect#lt;never, Error, never#gt;
node: Effect.gen#40;function*#40;#41; #123;#92;n yield* observe#92;n return yield* Effect.fail#40;error#41;#92;n#125;#41;"))) + 287[/"type: never
node: yield* Effect.fail#40;error#41;"/] + 288[/"type: Error
node: error"/] + 289["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 290[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 291[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 292[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 293["type: Effect#lt;number #124; Effect#lt;never, Error, never#gt;, never, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.as#40;Effect.fail#40;error#41;#41;#41;#93;"] + 294[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 295[["type: #40;error: Error#41; =#gt; Effect#lt;Effect#lt;never, Error, never#gt;, never, never#gt;
node: error =#gt; observe.pipe#40;Effect.as#40;Effect.fail#40;error#41;#41;#41;"]] + 296[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 297["type: Effect#lt;Effect#lt;never, Error, never#gt;, never, never#gt;
callee: Effect.as
args: #91;Effect.fail#40;error#41;#93;"] + 298[/"type: #123; #lt;B#gt;#40;value: B#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E, R#gt;; #lt;A, E, R, B#gt;#40;self: Effect#lt;A, E, R#gt;, value: B#41;: Effect#lt;B, E, R#gt;; #125;
node: Effect.as"/] + 299[/"type: Error
node: error"/] + 300["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 301[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 302[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 303["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;#92;n Effect.andThen#40;pipe#40;error, e =#gt; new Error#40;e.message#41;, Effect.fail#41;#41;#92;n#41;#93;"] + 304[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 305[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;#92;n Effect.andThen#40;pipe#40;error, e =#gt; new Error#40;e.message#41;, Effect.fail#41;#41;#92;n#41;"]] + 306[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 307["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;pipe#40;error, e =#gt; new Error#40;e.message#41;, Effect.fail#41;#93;"] + 308[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 309[/"type: Error
node: error"/] + 310["type: Error
callee: e =#gt; new Error#40;e.message#41;
args: #91;#93;"] + 311["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 312[/"type: Effect#lt;void, never, never#gt;
node: Effect.void"/] + 313["type: Effect#lt;void, never, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 314[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 315[["type: #40;error: never#41; =#gt; Effect#lt;never, never, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 316[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 317["type: Effect#lt;never, never, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 318[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 319[/"type: never
node: error"/] + 320["type: Effect#lt;never, never, never#gt;
callee: Effect.fail
args: #91;#93;"] + 321[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 322[/"type: Effect#lt;number, #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;, never#gt;
node: tagged"/] + 323["type: Effect#lt;number, #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;, never#gt;
callee: Effect.catchTag
args: #91;#quot;Oops#quot;, error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 324[/"type: #123; #lt;const K extends Tags#lt;E#gt; #124; Arr.NonEmptyReadonlyArray#lt;Tags#lt;E#gt;#gt;, E, A1, E1, R1, A2 = unassigned, E2 = never, R2 = never#gt;#40;k: K, f: #40;e: ExtractTag#lt;NoInfer#lt;E#gt;, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt;#41; =#gt; Effect#lt;A1, E1, R1#gt;, orElse?: #40;#40;e: ExcludeTag#lt;E, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt;#41; =#gt; Effect#lt;A2, E2, R2#gt;#41; #124; undefined#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A1 #124; Exclude#lt;A2, unassigned#gt;, E1 #124; E2 #124; #40;A2 extends unassigned ? ExcludeTag#lt;E, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt; : never#41;, R #124; R1 #124; R2#gt;; #lt;A, E, R, const K extends Tags#lt;E#gt; #124; Arr.NonEmptyReadonlyArray#lt;Tags#lt;E#gt;#gt;, R1, E1, A1, A2 = unassigned, E2 = never, R2 = never#gt;#40;self: Effect#lt;A, E, R#gt;, k: K, f: #40;e: ExtractTag#lt;E, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt;#41; =#gt; Effect#lt;A1, E1, R1#gt;, orElse?: #40;#40;e: ExcludeTag#lt;E, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt;#41; =#gt; Effect#lt;A2, E2, R2#gt;#41; #124; undefined#41;: Effect#lt;A #124; A1 #124; Exclude#lt;A2, unassigned#gt;, E1 #124; E2 #124; #40;A2 extends unassigned ? ExcludeTag#lt;E, K extends readonly #91;string, ...string#91;#93;#93; ? K#91;number#93; : K#gt; : never#41;, R #124; R1 #124; R2#gt;; #125;
node: Effect.catchTag"/] + 325[/"type: #quot;Oops#quot;
node: #quot;Oops#quot;"/] + 326[["type: #40;error: #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;#41; =#gt; Effect#lt;never, #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 327[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 328["type: Effect#lt;never, #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 329[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 330[/"type: #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;
node: error"/] + 331["type: Effect#lt;never, #123; readonly _tag: #quot;Oops#quot;; readonly message: string; #125;, never#gt;
callee: Effect.fail
args: #91;#93;"] + 332[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 333[/"type: #123; andThen: #40;next: Effect#lt;never, Error, never#gt;#41; =#gt; #40;_self: Effect#lt;void, never, never#gt;#41; =#gt; Effect#lt;never, Error, never#gt;; fail: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;; #125;
node: #123;#92;n andThen: #40;next: Effect.Effect#lt;never, Error#gt;#41; =#gt; #40;_self: Effect.Effect#lt;void#gt;#41; =#gt; next,#92;n fail: #40;error: Error#41; =#gt; Effect.fail#40;error#41;#92;n#125;"/] + 334[["type: #40;next: Effect#lt;never, Error, never#gt;#41; =#gt; #40;_self: Effect#lt;void, never, never#gt;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;next: Effect.Effect#lt;never, Error#gt;#41; =#gt; #40;_self: Effect.Effect#lt;void#gt;#41; =#gt; next"]] + 335[["type: #40;_self: Effect#lt;void, never, never#gt;#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;_self: Effect.Effect#lt;void#gt;#41; =#gt; next"]] + 336[/"type: Effect#lt;never, Error, never#gt;
node: next"/] + 337[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: #40;error: Error#41; =#gt; Effect.fail#40;error#41;"]] + 338[/"type: Error
node: error"/] + 339["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 340[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 341[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 342["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; custom.andThen#40;Effect.fail#40;error#41;#41;#40;observe#41;#93;"] + 343[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 344[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; custom.andThen#40;Effect.fail#40;error#41;#41;#40;observe#41;"]] + 345[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 346["type: Effect#lt;never, Error, never#gt;
callee: custom.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 347[/"type: #40;next: Effect#lt;never, Error, never#gt;#41; =#gt; #40;_self: Effect#lt;void, never, never#gt;#41; =#gt; Effect#lt;never, Error, never#gt;
node: custom.andThen"/] + 348[/"type: Error
node: error"/] + 349["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 350[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 351[/"type: Effect#lt;number, Error, never#gt;
node: task"/] + 352["type: Effect#lt;number, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; observe.pipe#40;Effect.andThen#40;custom.fail#40;error#41;#41;#41;#93;"] + 353[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 354[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; observe.pipe#40;Effect.andThen#40;custom.fail#40;error#41;#41;#41;"]] + 355[/"type: Effect#lt;void, never, never#gt;
node: observe"/] + 356["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;custom.fail#40;error#41;#93;"] + 357[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 358[/"type: Error
node: error"/] + 359["type: Effect#lt;never, Error, never#gt;
callee: custom.fail
args: #91;#93;"] + 360[/"type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: custom.fail"/] + 2 -->|"kind: transformCallee"| 1 + 6 -->|"kind: transformCallee"| 5 + 7 -->|"kind: pipe"| 8 + 9 -->|"kind: transformCallee"| 8 + 8 -->|"kind: transformArg"| 5 + 4 -->|"kind: pipe"| 5 + 5 -->|"kind: potentialReturn"| 3 + 3 -->|"kind: transformArg"| 1 + 0 -->|"kind: pipe"| 1 + 12 -->|"kind: transformCallee"| 11 + 16 -->|"kind: transformCallee"| 15 + 18 -->|"kind: pipe"| 19 + 20 -->|"kind: transformCallee"| 19 + 19 -->|"kind: potentialReturn"| 17 + 17 -->|"kind: transformArg"| 15 + 14 -->|"kind: pipe"| 15 + 15 -->|"kind: potentialReturn"| 13 + 13 -->|"kind: transformArg"| 11 + 10 -->|"kind: pipe"| 11 + 23 -->|"kind: transformCallee"| 22 + 27 -->|"kind: transformCallee"| 26 + 29 -->|"kind: pipe"| 30 + 31 -->|"kind: transformCallee"| 30 + 30 -->|"kind: potentialReturn"| 28 + 28 -->|"kind: transformArg"| 26 + 25 -->|"kind: pipe"| 26 + 26 -->|"kind: potentialReturn"| 24 + 24 -->|"kind: transformArg"| 22 + 21 -->|"kind: pipe"| 22 + 32 -->|"kind: pipe"| 33 + 34 -->|"kind: transformCallee"| 32 + 36 -->|"kind: pipe"| 37 + 38 -->|"kind: transformCallee"| 36 + 39 -->|"kind: pipe"| 40 + 41 -->|"kind: transformCallee"| 40 + 40 -->|"kind: transformArg"| 36 + 37 -->|"kind: potentialReturn"| 35 + 35 -->|"kind: transformArg"| 32 + 42 -->|"kind: pipe"| 43 + 44 -->|"kind: transformCallee"| 42 + 46 -->|"kind: pipe"| 47 + 48 -->|"kind: transformCallee"| 46 + 50 -->|"kind: pipe"| 51 + 52 -->|"kind: transformCallee"| 51 + 51 -->|"kind: potentialReturn"| 49 + 49 -->|"kind: transformArg"| 46 + 47 -->|"kind: potentialReturn"| 45 + 45 -->|"kind: transformArg"| 42 + 55 -->|"kind: transformCallee"| 54 + 59 -->|"kind: transformCallee"| 58 + 60 -->|"kind: pipe"| 61 + 61 -->|"kind: transformArg"| 58 + 57 -->|"kind: pipe"| 58 + 58 -->|"kind: potentialReturn"| 56 + 56 -->|"kind: transformArg"| 54 + 53 -->|"kind: pipe"| 54 + 62 -->|"kind: pipe"| 63 + 64 -->|"kind: transformCallee"| 63 + 66 -->|"kind: pipe"| 67 + 68 -->|"kind: transformCallee"| 67 + 69 -->|"kind: pipe"| 70 + 71 -->|"kind: transformCallee"| 70 + 70 -->|"kind: transformArg"| 67 + 67 -->|"kind: potentialReturn"| 65 + 65 -->|"kind: transformArg"| 63 + 74 -->|"kind: transformCallee"| 73 + 78 -->|"kind: transformCallee"| 77 + 80 -->|"kind: pipe"| 81 + 82 -->|"kind: transformCallee"| 81 + 81 -->|"kind: potentialReturn"| 79 + 81 -->|"kind: usedBy"| 79 + 79 -->|"kind: transformArg"| 77 + 76 -->|"kind: pipe"| 77 + 77 -->|"kind: potentialReturn"| 75 + 77 -->|"kind: usedBy"| 75 + 75 -->|"kind: transformArg"| 73 + 72 -->|"kind: pipe"| 73 + 85 -->|"kind: transformCallee"| 84 + 87 -->|"kind: pipe"| 88 + 89 -->|"kind: transformCallee"| 88 + 90 -->|"kind: pipe"| 91 + 92 -->|"kind: transformCallee"| 91 + 91 -->|"kind: transformArg"| 88 + 88 -->|"kind: potentialReturn"| 86 + 86 -->|"kind: transformArg"| 84 + 83 -->|"kind: pipe"| 84 + 95 -->|"kind: transformCallee"| 94 + 99 -->|"kind: transformCallee"| 98 + 100 -->|"kind: transformArg"| 98 + 97 -->|"kind: pipe"| 98 + 102 -->|"kind: transformCallee"| 101 + 103 -->|"kind: pipe"| 104 + 105 -->|"kind: transformCallee"| 104 + 104 -->|"kind: transformArg"| 101 + 98 -->|"kind: pipe"| 101 + 101 -->|"kind: potentialReturn"| 96 + 96 -->|"kind: transformArg"| 94 + 93 -->|"kind: pipe"| 94 + 108 -->|"kind: transformCallee"| 107 + 112 -->|"kind: transformCallee"| 111 + 113 -->|"kind: pipe"| 114 + 115 -->|"kind: transformCallee"| 114 + 114 -->|"kind: transformArg"| 111 + 110 -->|"kind: pipe"| 111 + 111 -->|"kind: potentialReturn"| 109 + 109 -->|"kind: transformArg"| 107 + 106 -->|"kind: pipe"| 107 + 118 -->|"kind: transformCallee"| 117 + 122 -->|"kind: transformCallee"| 121 + 123 -->|"kind: pipe"| 124 + 125 -->|"kind: transformCallee"| 124 + 124 -->|"kind: transformArg"| 121 + 120 -->|"kind: pipe"| 121 + 121 -->|"kind: potentialReturn"| 119 + 119 -->|"kind: transformArg"| 117 + 116 -->|"kind: pipe"| 117 + 128 -->|"kind: transformCallee"| 127 + 130 -->|"kind: pipe"| 131 + 132 -->|"kind: transformCallee"| 131 + 131 -->|"kind: potentialReturn"| 129 + 129 -->|"kind: transformArg"| 127 + 126 -->|"kind: pipe"| 127 + 135 -->|"kind: transformCallee"| 134 + 139 -->|"kind: transformCallee"| 138 + 140 -->|"kind: pipe"| 141 + 142 -->|"kind: transformCallee"| 141 + 141 -->|"kind: transformArg"| 138 + 137 -->|"kind: pipe"| 138 + 138 -->|"kind: potentialReturn"| 136 + 136 -->|"kind: transformArg"| 134 + 133 -->|"kind: pipe"| 134 + 145 -->|"kind: transformCallee"| 144 + 149 -->|"kind: transformCallee"| 148 + 150 -->|"kind: pipe"| 151 + 152 -->|"kind: transformCallee"| 151 + 151 -->|"kind: transformArg"| 148 + 147 -->|"kind: pipe"| 148 + 148 -->|"kind: potentialReturn"| 146 + 146 -->|"kind: transformArg"| 144 + 143 -->|"kind: pipe"| 144 + 155 -->|"kind: transformCallee"| 154 + 159 -->|"kind: transformCallee"| 158 + 160 -->|"kind: pipe"| 161 + 162 -->|"kind: transformCallee"| 161 + 161 -->|"kind: transformArg"| 158 + 157 -->|"kind: pipe"| 158 + 158 -->|"kind: potentialReturn"| 156 + 156 -->|"kind: transformArg"| 154 + 153 -->|"kind: pipe"| 154 + 165 -->|"kind: transformCallee"| 164 + 169 -->|"kind: transformCallee"| 168 + 172 -->|"kind: pipe"| 173 + 174 -->|"kind: transformCallee"| 173 + 173 -->|"kind: usedBy"| 171 + 171 -->|"kind: potentialReturn"| 170 + 170 -->|"kind: transformArg"| 168 + 167 -->|"kind: pipe"| 168 + 168 -->|"kind: potentialReturn"| 166 + 166 -->|"kind: transformArg"| 164 + 163 -->|"kind: pipe"| 164 + 177 -->|"kind: transformCallee"| 176 + 181 -->|"kind: transformCallee"| 180 + 182 -->|"kind: pipe"| 183 + 184 -->|"kind: transformCallee"| 183 + 183 -->|"kind: transformArg"| 180 + 179 -->|"kind: pipe"| 180 + 186 -->|"kind: transformCallee"| 185 + 188 -->|"kind: potentialReturn"| 187 + 187 -->|"kind: transformArg"| 185 + 180 -->|"kind: pipe"| 185 + 185 -->|"kind: potentialReturn"| 178 + 178 -->|"kind: transformArg"| 176 + 175 -->|"kind: pipe"| 176 + 191 -->|"kind: transformCallee"| 190 + 195 -->|"kind: transformCallee"| 194 + 196 -->|"kind: pipe"| 197 + 198 -->|"kind: transformCallee"| 197 + 200 -->|"kind: transformCallee"| 199 + 202 -->|"kind: potentialReturn"| 201 + 201 -->|"kind: transformArg"| 199 + 197 -->|"kind: pipe"| 199 + 199 -->|"kind: transformArg"| 194 + 193 -->|"kind: pipe"| 194 + 194 -->|"kind: potentialReturn"| 192 + 192 -->|"kind: transformArg"| 190 + 189 -->|"kind: pipe"| 190 + 205 -->|"kind: transformCallee"| 204 + 209 -->|"kind: transformCallee"| 208 + 211 -->|"kind: pipe"| 212 + 213 -->|"kind: transformCallee"| 212 + 212 -->|"kind: potentialReturn"| 210 + 210 -->|"kind: transformArg"| 208 + 207 -->|"kind: pipe"| 208 + 208 -->|"kind: potentialReturn"| 206 + 206 -->|"kind: transformArg"| 204 + 203 -->|"kind: pipe"| 204 + 216 -->|"kind: transformCallee"| 215 + 220 -->|"kind: transformCallee"| 219 + 222 -->|"kind: pipe"| 223 + 224 -->|"kind: transformCallee"| 223 + 223 -->|"kind: potentialReturn"| 221 + 221 -->|"kind: transformArg"| 219 + 218 -->|"kind: pipe"| 219 + 219 -->|"kind: potentialReturn"| 217 + 217 -->|"kind: transformArg"| 215 + 214 -->|"kind: pipe"| 215 + 227 -->|"kind: transformCallee"| 226 + 229 -->|"kind: pipe"| 230 + 231 -->|"kind: transformCallee"| 230 + 233 -->|"kind: transformCallee"| 232 + 235 -->|"kind: pipe"| 236 + 237 -->|"kind: transformCallee"| 236 + 236 -->|"kind: potentialReturn"| 234 + 234 -->|"kind: transformArg"| 232 + 230 -->|"kind: pipe"| 232 + 232 -->|"kind: potentialReturn"| 228 + 228 -->|"kind: transformArg"| 226 + 225 -->|"kind: pipe"| 226 + 240 -->|"kind: transformCallee"| 239 + 242 -->|"kind: pipe"| 243 + 244 -->|"kind: transformCallee"| 243 + 246 -->|"kind: transformCallee"| 245 + 248 -->|"kind: pipe"| 249 + 250 -->|"kind: transformCallee"| 249 + 249 -->|"kind: potentialReturn"| 247 + 247 -->|"kind: transformArg"| 245 + 243 -->|"kind: pipe"| 245 + 245 -->|"kind: potentialReturn"| 241 + 241 -->|"kind: transformArg"| 239 + 238 -->|"kind: pipe"| 239 + 253 -->|"kind: transformCallee"| 252 + 258 -->|"kind: transformCallee"| 257 + 259 -->|"kind: pipe"| 260 + 261 -->|"kind: transformCallee"| 260 + 260 -->|"kind: transformArg"| 257 + 256 -->|"kind: pipe"| 257 + 257 -->|"kind: potentialReturn"| 254 + 254 -->|"kind: transformArg"| 252 + 251 -->|"kind: pipe"| 252 + 264 -->|"kind: transformCallee"| 263 + 268 -->|"kind: transformCallee"| 267 + 269 -->|"kind: pipe"| 270 + 271 -->|"kind: transformCallee"| 270 + 270 -->|"kind: transformArg"| 267 + 266 -->|"kind: pipe"| 267 + 267 -->|"kind: potentialReturn"| 265 + 265 -->|"kind: transformArg"| 263 + 262 -->|"kind: pipe"| 263 + 274 -->|"kind: transformCallee"| 273 + 278 -->|"kind: transformCallee"| 277 + 279 -->|"kind: pipe"| 280 + 281 -->|"kind: transformCallee"| 280 + 280 -->|"kind: transformArg"| 277 + 276 -->|"kind: pipe"| 277 + 277 -->|"kind: potentialReturn"| 275 + 277 -->|"kind: usedBy"| 275 + 275 -->|"kind: transformArg"| 273 + 272 -->|"kind: pipe"| 273 + 284 -->|"kind: transformCallee"| 283 + 288 -->|"kind: pipe"| 289 + 290 -->|"kind: transformCallee"| 289 + 289 -->|"kind: usedBy"| 287 + 287 -->|"kind: potentialReturn"| 286 + 291 -->|"kind: yieldable"| 286 + 289 -->|"kind: yieldable"| 286 + 286 -->|"kind: potentialReturn"| 285 + 285 -->|"kind: transformArg"| 283 + 282 -->|"kind: pipe"| 283 + 294 -->|"kind: transformCallee"| 293 + 298 -->|"kind: transformCallee"| 297 + 299 -->|"kind: pipe"| 300 + 301 -->|"kind: transformCallee"| 300 + 300 -->|"kind: transformArg"| 297 + 296 -->|"kind: pipe"| 297 + 297 -->|"kind: potentialReturn"| 295 + 295 -->|"kind: transformArg"| 293 + 292 -->|"kind: pipe"| 293 + 304 -->|"kind: transformCallee"| 303 + 308 -->|"kind: transformCallee"| 307 + 309 -->|"kind: pipe"| 310 + 310 -->|"kind: pipe"| 311 + 311 -->|"kind: transformArg"| 307 + 306 -->|"kind: pipe"| 307 + 307 -->|"kind: potentialReturn"| 305 + 305 -->|"kind: transformArg"| 303 + 302 -->|"kind: pipe"| 303 + 314 -->|"kind: transformCallee"| 313 + 318 -->|"kind: transformCallee"| 317 + 319 -->|"kind: pipe"| 320 + 321 -->|"kind: transformCallee"| 320 + 320 -->|"kind: transformArg"| 317 + 316 -->|"kind: pipe"| 317 + 317 -->|"kind: potentialReturn"| 315 + 315 -->|"kind: transformArg"| 313 + 312 -->|"kind: pipe"| 313 + 324 -->|"kind: transformCallee"| 323 + 325 -->|"kind: transformArg"| 323 + 329 -->|"kind: transformCallee"| 328 + 330 -->|"kind: pipe"| 331 + 332 -->|"kind: transformCallee"| 331 + 331 -->|"kind: transformArg"| 328 + 327 -->|"kind: pipe"| 328 + 328 -->|"kind: potentialReturn"| 326 + 326 -->|"kind: transformArg"| 323 + 322 -->|"kind: pipe"| 323 + 336 -->|"kind: potentialReturn"| 335 + 335 -->|"kind: potentialReturn"| 334 + 334 -->|"kind: usedBy"| 333 + 338 -->|"kind: pipe"| 339 + 340 -->|"kind: transformCallee"| 339 + 339 -->|"kind: potentialReturn"| 337 + 337 -->|"kind: usedBy"| 333 + 343 -->|"kind: transformCallee"| 342 + 345 -->|"kind: pipe"| 346 + 347 -->|"kind: transformCallee"| 346 + 348 -->|"kind: pipe"| 349 + 350 -->|"kind: transformCallee"| 349 + 349 -->|"kind: transformArg"| 346 + 346 -->|"kind: potentialReturn"| 344 + 344 -->|"kind: transformArg"| 342 + 341 -->|"kind: pipe"| 342 + 353 -->|"kind: transformCallee"| 352 + 357 -->|"kind: transformCallee"| 356 + 358 -->|"kind: pipe"| 359 + 360 -->|"kind: transformCallee"| 359 + 359 -->|"kind: transformArg"| 356 + 355 -->|"kind: pipe"| 356 + 356 -->|"kind: potentialReturn"| 354 + 354 -->|"kind: transformArg"| 352 + 351 -->|"kind: pipe"| 352 \ No newline at end of file diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.txt new file mode 100644 index 00000000..5cb2df9a --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.flows.txt @@ -0,0 +1 @@ +/.src/catchRefailToTapError.ts -> catchRefailToTapError.flows.catchRefailToTapError.mermaid diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.layers.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError.layers.txt new file mode 100644 index 00000000..97c516f7 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.layers.txt @@ -0,0 +1 @@ +==== /.src/catchRefailToTapError.ts (0 layer exports) ==== diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.pipings.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError.pipings.txt new file mode 100644 index 00000000..bd486f8d --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.pipings.txt @@ -0,0 +1,1397 @@ +==== /.src/catchRefailToTapError.ts (98 flows) ==== + +=== Piping Flow === +Location: 14:22 - 14:105 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 14:54 - 14:103 +Node: observe.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 14:83 - 14:101 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 15:28 - 15:117 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(() => Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(() => Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 15:60 - 15:115 +Node: observe.pipe(Effect.andThen(() => Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [() => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 15:94 - 15:113 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 16:28 - 16:117 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.flatMap(() => Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.flatMap(() => Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 16:60 - 16:115 +Node: observe.pipe(Effect.flatMap(() => Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.flatMap + args: [() => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 16:94 - 16:113 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 17:25 - 17:98 +Node: Effect.catch(task, error => Effect.andThen(observe, Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.catch + args: [error => Effect.andThen(observe, Effect.fail(error))] + outType: Effect + +=== Piping Flow === +Location: 17:53 - 17:97 +Node: Effect.andThen(observe, Effect.fail(error)) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 18:32 - 18:111 +Node: Effect.catch(task, error => Effect.flatMap(observe, () => Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.catch + args: [error => Effect.flatMap(observe, () => Effect.fail(error))] + outType: Effect + +=== Piping Flow === +Location: 18:60 - 18:110 +Node: Effect.flatMap(observe, () => Effect.fail(error)) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.flatMap + args: [() => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 18:90 - 18:109 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 19:30 - 19:121 +Node: pipe(task, Effect.catch(error => pipe(observe, Effect.andThen(pipe(error, Effect.fail))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipe + callee: Effect.catch + args: [error => pipe(observe, Effect.andThen(pipe(error, Effect.fail)))] + outType: Effect + +=== Piping Flow === +Location: 19:63 - 19:119 +Node: pipe(observe, Effect.andThen(pipe(error, Effect.fail))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipe + callee: Effect.andThen + args: [pipe(error, Effect.fail)] + outType: Effect + +=== Piping Flow === +Location: 19:93 - 19:117 +Node: pipe(error, Effect.fail) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: pipe + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 20:23 - 20:96 +Node: Effect.catch(error => Effect.andThen(Effect.fail(error))(observe))(task) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: call + callee: Effect.catch + args: [error => Effect.andThen(Effect.fail(error))(observe)] + outType: Effect + +=== Piping Flow === +Location: 20:45 - 20:89 +Node: Effect.andThen(Effect.fail(error))(observe) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: call + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 20:61 - 20:79 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: unknown + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 21:22 - 23:4 +Node: task.pipe(Effect.catch(function(error) {\n return observe.pipe(Effect.flatMap(function() { return Effect.fail((error)) }))\n})) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [function(error) {\n return observe.pipe(Effect.flatMap(function() { return Effect.fail((error)) }))\n}] + outType: Effect + +=== Piping Flow === +Location: 22:9 - 22:82 +Node: observe.pipe(Effect.flatMap(function() { return Effect.fail((error)) })) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.flatMap + args: [function() { return Effect.fail((error)) }] + outType: Effect + +=== Piping Flow === +Location: 22:57 - 22:78 +Node: Effect.fail((error)) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 24:23 - 24:86 +Node: pipe(task, recover(error => sequence(refail(error))(observe))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipe + callee: recover + args: [error => sequence(refail(error))(observe)] + outType: Effect + +=== Piping Flow === +Location: 24:51 - 24:84 +Node: sequence(refail(error))(observe) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: call + callee: sequence + args: [refail(error)] + outType: Effect + +=== Piping Flow === +Location: 24:61 - 24:74 +Node: refail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: refail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 25:28 - 28:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.andThen(observe),\n Effect.andThen(Effect.fail(error))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.andThen(observe),\n Effect.andThen(Effect.fail(error))\n)] + outType: Effect + +=== Piping Flow === +Location: 25:60 - 28:2 +Node: observe.pipe(\n Effect.andThen(observe),\n Effect.andThen(Effect.fail(error))\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (2): + [0] kind: pipeable + callee: Effect.andThen + args: [observe] + outType: Effect + [1] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 27:18 - 27:36 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 29:27 - 29:118 +Node: task.pipe(Effect.catch(error => fallibleObserve.pipe(Effect.andThen(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => fallibleObserve.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 29:59 - 29:116 +Node: fallibleObserve.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: fallibleObserve +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 29:96 - 29:114 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 30:31 - 32:4 +Node: task.pipe(Effect.catch(error => (condition ? observe : fallibleObserve).pipe(\n Effect.andThen(Effect.fail(error))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => (condition ? observe : fallibleObserve).pipe(\n Effect.andThen(Effect.fail(error))\n)] + outType: Effect + +=== Piping Flow === +Location: 30:63 - 32:2 +Node: (condition ? observe : fallibleObserve).pipe(\n Effect.andThen(Effect.fail(error))\n) +Node Kind: KindCallExpression + +Subject: condition ? observe : fallibleObserve +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 31:18 - 31:36 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 35:26 - 35:79 +Node: task.pipe(Effect.catch(error => Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 35:58 - 35:77 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 36:27 - 36:129 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(new Error(error.message)))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(Effect.fail(new Error(error.message))))] + outType: Effect + +=== Piping Flow === +Location: 36:59 - 36:127 +Node: observe.pipe(Effect.andThen(Effect.fail(new Error(error.message)))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(new Error(error.message))] + outType: Effect + +=== Piping Flow === +Location: 36:88 - 36:125 +Node: Effect.fail(new Error(error.message)) +Node Kind: KindCallExpression + +Subject: new Error(error.message) +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 37:28 - 37:116 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(otherError))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(Effect.fail(otherError)))] + outType: Effect + +=== Piping Flow === +Location: 37:60 - 37:114 +Node: observe.pipe(Effect.andThen(Effect.fail(otherError))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(otherError)] + outType: Effect + +=== Piping Flow === +Location: 37:89 - 37:112 +Node: Effect.fail(otherError) +Node Kind: KindCallExpression + +Subject: otherError +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 38:24 - 38:115 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error.message))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(Effect.fail(error.message)))] + outType: Effect + +=== Piping Flow === +Location: 38:56 - 38:113 +Node: observe.pipe(Effect.andThen(Effect.fail(error.message))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error.message)] + outType: Effect + +=== Piping Flow === +Location: 38:85 - 38:111 +Node: Effect.fail(error.message) +Node Kind: KindCallExpression + +Subject: error.message +Subject Type: string + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 39:33 - 41:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.flatMap(() => condition ? Effect.fail(error) : Effect.void)\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.flatMap(() => condition ? Effect.fail(error) : Effect.void)\n)] + outType: Effect + +=== Piping Flow === +Location: 39:65 - 41:2 +Node: observe.pipe(\n Effect.flatMap(() => condition ? Effect.fail(error) : Effect.void)\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.flatMap + args: [() => condition ? Effect.fail(error) : Effect.void] + outType: Effect + +=== Piping Flow === +Location: 40:35 - 40:54 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 42:27 - 45:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.andThen(Effect.fail(error)),\n Effect.catch(() => Effect.void)\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.andThen(Effect.fail(error)),\n Effect.catch(() => Effect.void)\n)] + outType: Effect + +=== Piping Flow === +Location: 42:59 - 45:2 +Node: observe.pipe(\n Effect.andThen(Effect.fail(error)),\n Effect.catch(() => Effect.void)\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (2): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + [1] kind: pipeable + callee: Effect.catch + args: [() => Effect.void] + outType: Effect + +=== Piping Flow === +Location: 43:18 - 43:36 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 46:29 - 48:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.andThen(Effect.fail(error).pipe(Effect.catch(() => Effect.void)))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.andThen(Effect.fail(error).pipe(Effect.catch(() => Effect.void)))\n)] + outType: Effect + +=== Piping Flow === +Location: 46:61 - 48:2 +Node: observe.pipe(\n Effect.andThen(Effect.fail(error).pipe(Effect.catch(() => Effect.void)))\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error).pipe(Effect.catch(() => Effect.void))] + outType: Effect + +=== Piping Flow === +Location: 47:18 - 47:74 +Node: Effect.fail(error).pipe(Effect.catch(() => Effect.void)) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (2): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.catch + args: [() => Effect.void] + outType: Effect + +=== Piping Flow === +Location: 49:36 - 51:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.flatMap(_value => Effect.fail(error))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.flatMap(_value => Effect.fail(error))\n)] + outType: Effect + +=== Piping Flow === +Location: 49:68 - 51:2 +Node: observe.pipe(\n Effect.flatMap(_value => Effect.fail(error))\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.flatMap + args: [_value => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 50:27 - 50:46 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 52:36 - 54:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.andThen(_value => Effect.fail(error))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.andThen(_value => Effect.fail(error))\n)] + outType: Effect + +=== Piping Flow === +Location: 52:68 - 54:2 +Node: observe.pipe(\n Effect.andThen(_value => Effect.fail(error))\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [_value => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 53:27 - 53:46 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 55:29 - 57:4 +Node: task.pipe(Effect.catch(error => Effect.succeed(otherError).pipe(\n Effect.flatMap(error => Effect.fail(error))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => Effect.succeed(otherError).pipe(\n Effect.flatMap(error => Effect.fail(error))\n)] + outType: Effect + +=== Piping Flow === +Location: 55:61 - 57:2 +Node: Effect.succeed(otherError).pipe(\n Effect.flatMap(error => Effect.fail(error))\n) +Node Kind: KindCallExpression + +Subject: otherError +Subject Type: Error + +Transformations (2): + [0] kind: call + callee: Effect.succeed + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [error => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 56:26 - 56:45 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 58:29 - 60:52 +Node: task.pipe(Effect.catch(error => Effect.sync(() => {\n error = otherError\n}).pipe(Effect.flatMap(() => Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => Effect.sync(() => {\n error = otherError\n}).pipe(Effect.flatMap(() => Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 58:61 - 60:50 +Node: Effect.sync(() => {\n error = otherError\n}).pipe(Effect.flatMap(() => Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: () => {\n error = otherError\n} +Subject Type: () => void + +Transformations (2): + [0] kind: call + callee: Effect.sync + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [() => Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 60:29 - 60:48 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 61:32 - 61:130 +Node: task.pipe(Effect.catch((error = otherError) => observe.pipe(Effect.andThen(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [(error = otherError) => observe.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 61:79 - 61:128 +Node: observe.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 61:108 - 61:126 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 62:28 - 62:121 +Node: task.pipe(Effect.catch(({ message }) => observe.pipe(Effect.andThen(Effect.fail(message))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [({ message }) => observe.pipe(Effect.andThen(Effect.fail(message)))] + outType: Effect + +=== Piping Flow === +Location: 62:68 - 62:119 +Node: observe.pipe(Effect.andThen(Effect.fail(message))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(message)] + outType: Effect + +=== Piping Flow === +Location: 62:97 - 62:117 +Node: Effect.fail(message) +Node Kind: KindCallExpression + +Subject: message +Subject Type: string + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 63:26 - 66:4 +Node: task.pipe(Effect.catch(error => {\n const side = observe\n return side.pipe(Effect.andThen(Effect.fail(error)))\n})) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => {\n const side = observe\n return side.pipe(Effect.andThen(Effect.fail(error)))\n}] + outType: Effect + +=== Piping Flow === +Location: 65:9 - 65:55 +Node: side.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: side +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 65:35 - 65:53 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 67:25 - 70:5 +Node: task.pipe(Effect.catch(error => Effect.gen(function*() {\n yield* observe\n return yield* Effect.fail(error)\n}))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => Effect.gen(function*() {\n yield* observe\n return yield* Effect.fail(error)\n})] + outType: Effect + +=== Piping Flow === +Location: 67:57 - 70:3 +Node: Effect.gen(function*() {\n yield* observe\n return yield* Effect.fail(error)\n}) +Node Kind: KindCallExpression + +Subject: function*() {\n yield* observe\n return yield* Effect.fail(error)\n} +Subject Type: () => Generator | Effect, never, any> + +Transformations (1): + [0] kind: call + callee: Effect.gen + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 69:16 - 69:35 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 71:35 - 71:113 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.as(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.as(Effect.fail(error)))] + outType: Effect, never, never> + +=== Piping Flow === +Location: 71:67 - 71:111 +Node: observe.pipe(Effect.as(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.as + args: [Effect.fail(error)] + outType: Effect, never, never> + +=== Piping Flow === +Location: 71:91 - 71:109 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 72:33 - 74:4 +Node: task.pipe(Effect.catch(error => observe.pipe(\n Effect.andThen(pipe(error, e => new Error(e.message), Effect.fail))\n))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(\n Effect.andThen(pipe(error, e => new Error(e.message), Effect.fail))\n)] + outType: Effect + +=== Piping Flow === +Location: 72:65 - 74:2 +Node: observe.pipe(\n Effect.andThen(pipe(error, e => new Error(e.message), Effect.fail))\n) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [pipe(error, e => new Error(e.message), Effect.fail)] + outType: Effect + +=== Piping Flow === +Location: 73:18 - 73:69 +Node: pipe(error, e => new Error(e.message), Effect.fail) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (2): + [0] kind: pipe + callee: e => new Error(e.message) + args: (constant) + outType: Error + [1] kind: pipe + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 75:26 - 75:116 +Node: Effect.void.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: Effect.void +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 75:65 - 75:114 +Node: observe.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 75:94 - 75:112 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: never + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 78:25 - 78:121 +Node: tagged.pipe(Effect.catchTag("Oops", error => observe.pipe(Effect.andThen(Effect.fail(error))))) +Node Kind: KindCallExpression + +Subject: tagged +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catchTag + args: ["Oops", error => observe.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 78:70 - 78:119 +Node: observe.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 78:99 - 78:117 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: { readonly _tag: "Oops"; readonly message: string; } + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 83:26 - 83:45 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 85:29 - 85:107 +Node: task.pipe(Effect.catch(error => custom.andThen(Effect.fail(error))(observe))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => custom.andThen(Effect.fail(error))(observe)] + outType: Effect + +=== Piping Flow === +Location: 85:61 - 85:105 +Node: custom.andThen(Effect.fail(error))(observe) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: call + callee: custom.andThen(Effect.fail(error)) + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 85:77 - 85:95 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 86:26 - 86:109 +Node: task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(custom.fail(error))))) +Node Kind: KindCallExpression + +Subject: task +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => observe.pipe(Effect.andThen(custom.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 86:58 - 86:107 +Node: observe.pipe(Effect.andThen(custom.fail(error))) +Node Kind: KindCallExpression + +Subject: observe +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [custom.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 86:87 - 86:105 +Node: custom.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: custom.fail + args: (constant) + outType: Effect diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError.quickfixes.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError.quickfixes.txt new file mode 100644 index 00000000..3cbf6bd9 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError.quickfixes.txt @@ -0,0 +1,129 @@ +=== Quick Fix Inventory === + +[D1] (14:33-14:45) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D2] (15:39-15:51) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D3] (16:39-16:51) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D4] (17:26-17:38) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D5] (18:33-18:45) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D6] (19:42-19:54) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D7] (20:24-20:36) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D8] (21:33-21:45) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D9] (24:35-24:42) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D10] (25:39-25:51) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D11] (29:38-29:50) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D12] (30:42-30:54) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +[D13] (37:52-37:57) TS6133: 'error' is declared but its value is never read. + (no quick fixes) + +[D14] (55:53-55:58) TS6133: 'error' is declared but its value is never read. + (no quick fixes) + +=== Quick Fix Application Results === + +=== [D1] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D1] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D2] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D2] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D3] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D3] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D4] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D4] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D5] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D5] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D6] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D6] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D7] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D7] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D8] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D8] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D9] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D9] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D10] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D10] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D11] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D11] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default + +=== [D12] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D12] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.errors.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.errors.txt new file mode 100644 index 00000000..ba8943d0 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.errors.txt @@ -0,0 +1,21 @@ +=== Metadata === +Effect version: 4.0.0 + +/.src/catchRefailToTapError_preview.ts(10,3): warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + + +==== /.src/catchRefailToTapError_preview.ts (1 errors) ==== + // @effect-v4 + // @effect-diagnostics *:off + // @effect-diagnostics catchRefailToTapError:warning + import { Effect } from "effect" + + declare const save: Effect.Effect + declare const rollback: Effect.Effect + + export const program = save.pipe( + Effect.catch(error => rollback.pipe(Effect.andThen(Effect.fail(error)))) + ~~~~~~~~~~~~ +!!! warning TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + ) + diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.catchRefailToTapError_preview.mermaid b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.catchRefailToTapError_preview.mermaid new file mode 100644 index 00000000..9615ce0e --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.catchRefailToTapError_preview.mermaid @@ -0,0 +1,20 @@ +flowchart TB + 0[/"type: Effect#lt;void, Error, never#gt;
node: save"/] + 1["type: Effect#lt;void, Error, never#gt;
callee: Effect.catch
args: #91;error =#gt; rollback.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;#93;"] + 2[/"type: #123; #lt;E, A2, E2, R2#gt;#40;f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: #lt;A, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A #124; A2, E2, R #124; R2#gt;; #lt;A, E, R, A2, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;e: E#41; =#gt; Effect#lt;A2, E2, R2#gt;#41;: Effect#lt;A #124; A2, E2, R #124; R2#gt;; #125;
node: Effect.catch"/] + 3[["type: #40;error: Error#41; =#gt; Effect#lt;never, Error, never#gt;
node: error =#gt; rollback.pipe#40;Effect.andThen#40;Effect.fail#40;error#41;#41;#41;"]] + 4[/"type: Effect#lt;void, never, never#gt;
node: rollback"/] + 5["type: Effect#lt;never, Error, never#gt;
callee: Effect.andThen
args: #91;Effect.fail#40;error#41;#93;"] + 6[/"type: #123; #lt;A, B, E2, R2#gt;#40;f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: #lt;E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;B, E2, R2#gt;#40;f: Effect#lt;B, E2, R2#gt;#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: #40;a: A#41; =#gt; Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #lt;A, E, R, B, E2, R2#gt;#40;self: Effect#lt;A, E, R#gt;, f: Effect#lt;B, E2, R2#gt;#41;: Effect#lt;B, E #124; E2, R #124; R2#gt;; #125;
node: Effect.andThen"/] + 7[/"type: Error
node: error"/] + 8["type: Effect#lt;never, Error, never#gt;
callee: Effect.fail
args: #91;#93;"] + 9[/"type: #lt;E#gt;#40;error: E#41; =#gt; Effect#lt;never, E, never#gt;
node: Effect.fail"/] + 2 -->|"kind: transformCallee"| 1 + 6 -->|"kind: transformCallee"| 5 + 7 -->|"kind: pipe"| 8 + 9 -->|"kind: transformCallee"| 8 + 8 -->|"kind: transformArg"| 5 + 4 -->|"kind: pipe"| 5 + 5 -->|"kind: potentialReturn"| 3 + 3 -->|"kind: transformArg"| 1 + 0 -->|"kind: pipe"| 1 \ No newline at end of file diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.txt new file mode 100644 index 00000000..7f33d152 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.flows.txt @@ -0,0 +1 @@ +/.src/catchRefailToTapError_preview.ts -> catchRefailToTapError_preview.flows.catchRefailToTapError_preview.mermaid diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.layers.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.layers.txt new file mode 100644 index 00000000..fb9dbaed --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.layers.txt @@ -0,0 +1 @@ +==== /.src/catchRefailToTapError_preview.ts (0 layer exports) ==== diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.pipings.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.pipings.txt new file mode 100644 index 00000000..a1f72fc9 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.pipings.txt @@ -0,0 +1,43 @@ +==== /.src/catchRefailToTapError_preview.ts (3 flows) ==== + +=== Piping Flow === +Location: 9:23 - 11:2 +Node: save.pipe(\n Effect.catch(error => rollback.pipe(Effect.andThen(Effect.fail(error))))\n) +Node Kind: KindCallExpression + +Subject: save +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.catch + args: [error => rollback.pipe(Effect.andThen(Effect.fail(error)))] + outType: Effect + +=== Piping Flow === +Location: 10:24 - 10:74 +Node: rollback.pipe(Effect.andThen(Effect.fail(error))) +Node Kind: KindCallExpression + +Subject: rollback +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.andThen + args: [Effect.fail(error)] + outType: Effect + +=== Piping Flow === +Location: 10:54 - 10:72 +Node: Effect.fail(error) +Node Kind: KindCallExpression + +Subject: error +Subject Type: Error + +Transformations (1): + [0] kind: call + callee: Effect.fail + args: (constant) + outType: Effect diff --git a/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.quickfixes.txt b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.quickfixes.txt new file mode 100644 index 00000000..51fc1f5b --- /dev/null +++ b/testdata/baselines/reference/effect-v4/catchRefailToTapError_preview.quickfixes.txt @@ -0,0 +1,13 @@ +=== Quick Fix Inventory === + +[D1] (10:3-10:15) TS377133: Use Effect.tapError to observe the error and preserve the original failure without having to re-fail it. effect(catchRefailToTapError) + Fix 0: "Disable catchRefailToTapError for this line" + Fix 1: "Disable catchRefailToTapError for entire file" + +=== Quick Fix Application Results === + +=== [D1] Fix 0: "Disable catchRefailToTapError for this line" === +skipped by default + +=== [D1] Fix 1: "Disable catchRefailToTapError for entire file" === +skipped by default diff --git a/testdata/tests/effect-v4/catchRefailToTapError.ts b/testdata/tests/effect-v4/catchRefailToTapError.ts new file mode 100644 index 00000000..989f5608 --- /dev/null +++ b/testdata/tests/effect-v4/catchRefailToTapError.ts @@ -0,0 +1,86 @@ +// @effect-v4 +// @effect-diagnostics *:off +// @effect-diagnostics catchRefailToTapError:warning +import { Effect, pipe } from "effect" +import { catch as recover, andThen as sequence, fail as refail } from "effect/Effect" + +declare const task: Effect.Effect +declare const observe: Effect.Effect +declare const fallibleObserve: Effect.Effect +declare const otherError: Error +declare const condition: boolean + +// Supported: direct effects and zero-argument continuations, across call forms. +export const direct = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) +export const andThenThunk = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(() => Effect.fail(error))))) +export const flatMapThunk = task.pipe(Effect.catch(error => observe.pipe(Effect.flatMap(() => Effect.fail(error))))) +export const dataFirst = Effect.catch(task, error => Effect.andThen(observe, Effect.fail(error))) +export const dataFirstFlatMap = Effect.catch(task, error => Effect.flatMap(observe, () => Effect.fail(error))) +export const standalonePipe = pipe(task, Effect.catch(error => pipe(observe, Effect.andThen(pipe(error, Effect.fail))))) +export const curried = Effect.catch(error => Effect.andThen(Effect.fail(error))(observe))(task) +export const blocks = task.pipe(Effect.catch(function(error) { + return observe.pipe(Effect.flatMap(function() { return Effect.fail((error)) })) +})) +export const aliases = pipe(task, recover(error => sequence(refail(error))(observe))) +export const earlierSteps = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(observe), + Effect.andThen(Effect.fail(error)) +))) +export const sideCanFail = task.pipe(Effect.catch(error => fallibleObserve.pipe(Effect.andThen(Effect.fail(error))))) +export const conditionalSide = task.pipe(Effect.catch(error => (condition ? observe : fallibleObserve).pipe( + Effect.andThen(Effect.fail(error)) +))) + +// Unsupported or unsafe: the original error must be re-failed unconditionally. +export const justRefail = task.pipe(Effect.catch(error => Effect.fail(error))) +export const mappedError = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(new Error(error.message)))))) +export const otherBinding = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(otherError))))) +export const property = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error.message))))) +export const conditionalRefail = task.pipe(Effect.catch(error => observe.pipe( + Effect.flatMap(() => condition ? Effect.fail(error) : Effect.void) +))) +export const afterRefail = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(Effect.fail(error)), + Effect.catch(() => Effect.void) +))) +export const innerRecovery = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(Effect.fail(error).pipe(Effect.catch(() => Effect.void))) +))) +export const parameterizedFlatMap = task.pipe(Effect.catch(error => observe.pipe( + Effect.flatMap(_value => Effect.fail(error)) +))) +export const parameterizedAndThen = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(_value => Effect.fail(error)) +))) +export const shadowedError = task.pipe(Effect.catch(error => Effect.succeed(otherError).pipe( + Effect.flatMap(error => Effect.fail(error)) +))) +export const assignedError = task.pipe(Effect.catch(error => Effect.sync(() => { + error = otherError +}).pipe(Effect.flatMap(() => Effect.fail(error))))) +export const defaultParameter = task.pipe(Effect.catch((error = otherError) => observe.pipe(Effect.andThen(Effect.fail(error))))) +export const destructured = task.pipe(Effect.catch(({ message }) => observe.pipe(Effect.andThen(Effect.fail(message))))) +export const statements = task.pipe(Effect.catch(error => { + const side = observe + return side.pipe(Effect.andThen(Effect.fail(error))) +})) +export const generator = task.pipe(Effect.catch(error => Effect.gen(function*() { + yield* observe + return yield* Effect.fail(error) +}))) +export const differentCombinator = task.pipe(Effect.catch(error => observe.pipe(Effect.as(Effect.fail(error))))) +export const failMappedSubject = task.pipe(Effect.catch(error => observe.pipe( + Effect.andThen(pipe(error, e => new Error(e.message), Effect.fail)) +))) +export const unfailable = Effect.void.pipe(Effect.catch(error => observe.pipe(Effect.andThen(Effect.fail(error))))) + +declare const tagged: Effect.Effect +export const selective = tagged.pipe(Effect.catchTag("Oops", error => observe.pipe(Effect.andThen(Effect.fail(error))))) + +// A same-named local API must not be mistaken for the Effect module. +const custom = { + andThen: (next: Effect.Effect) => (_self: Effect.Effect) => next, + fail: (error: Error) => Effect.fail(error) +} +export const customAndThen = task.pipe(Effect.catch(error => custom.andThen(Effect.fail(error))(observe))) +export const customFail = task.pipe(Effect.catch(error => observe.pipe(Effect.andThen(custom.fail(error))))) diff --git a/testdata/tests/effect-v4/catchRefailToTapError_preview.ts b/testdata/tests/effect-v4/catchRefailToTapError_preview.ts new file mode 100644 index 00000000..e63bfc2b --- /dev/null +++ b/testdata/tests/effect-v4/catchRefailToTapError_preview.ts @@ -0,0 +1,11 @@ +// @effect-v4 +// @effect-diagnostics *:off +// @effect-diagnostics catchRefailToTapError:warning +import { Effect } from "effect" + +declare const save: Effect.Effect +declare const rollback: Effect.Effect + +export const program = save.pipe( + Effect.catch(error => rollback.pipe(Effect.andThen(Effect.fail(error)))) +) From ca94a4497a71ceed01c2af1aab9a053471e2c13c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 06:12:42 +0000 Subject: [PATCH 2/5] chore: update generated/latest --- _packages/tsgo/upstream.json | 37 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/_packages/tsgo/upstream.json b/_packages/tsgo/upstream.json index 0c1df7ee..c7457f13 100644 --- a/_packages/tsgo/upstream.json +++ b/_packages/tsgo/upstream.json @@ -6,7 +6,7 @@ "next": "7.1.0-dev.20260913.1" }, "oxlint": { - "latest": "1.82.0" + "latest": "1.83.0" }, "oxlint-tsgolint": { "latest": "7.0.2001" @@ -32,29 +32,34 @@ } }, "oxlint": { - "1.77.0": { - "gitHead": "9a423f2f485b79c2353c49442c0c7f60f900261d" - }, "1.79.0": { "gitHead": "0db127cc16d28b97d84bac4ebeb302caf1a78c7e" }, - "1.80.0": { - "gitHead": "97e99b85483776a72928d675cc05b1cfc1130ba0" - }, "1.81.0": { "gitHead": "0b4e2e67f4193e7ebfcc64982275eb583ae82c83" }, "1.82.0": { "gitHead": "b4da00b621ec2f6f67ed218f5366c45ed325331b" + }, + "1.83.0": { + "gitHead": "7bf68f70c20f5329251f19be95076f6eab4fe396" } } }, "profiles": [ { "name": "vite-plus", - "description": "Vite+ 0.3.1 compatibility runtime", + "description": "Vite+ 0.3.2 compatibility runtime", "dependencies": { - "oxlint": "1.81.0", + "oxlint": "1.82.0", + "oxlint-tsgolint": "7.0.2001" + } + }, + { + "name": "oxlint@1.83.0", + "description": "Oxlint 1.83.0 compatibility runtime", + "dependencies": { + "oxlint": "1.83.0", "oxlint-tsgolint": "7.0.2001" } }, @@ -75,10 +80,10 @@ } }, { - "name": "oxlint@1.80.0", - "description": "Oxlint 1.80.0 compatibility runtime", + "name": "vite-plus@0.3.2", + "description": "Vite+ 0.3.2 compatibility runtime", "dependencies": { - "oxlint": "1.80.0", + "oxlint": "1.82.0", "oxlint-tsgolint": "7.0.2001" } }, @@ -97,14 +102,6 @@ "oxlint": "1.79.0", "oxlint-tsgolint": "7.0.2001" } - }, - { - "name": "vite-plus@0.2.9", - "description": "Vite+ 0.2.9 compatibility runtime", - "dependencies": { - "oxlint": "1.77.0", - "oxlint-tsgolint": "7.0.2001" - } } ] } From 6f3d716770bca02a4a974e1f9527d9ff69d3e1a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 09:52:04 +0000 Subject: [PATCH 3/5] chore: update generated/latest --- .changeset/update-upstreams.md | 2 +- _packages/tsgo/upstream.json | 6 +++--- flake.lock | 8 ++++---- flake.nix | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.changeset/update-upstreams.md b/.changeset/update-upstreams.md index a04adeaf..6be58494 100644 --- a/.changeset/update-upstreams.md +++ b/.changeset/update-upstreams.md @@ -2,4 +2,4 @@ "@effect/tsgo": patch --- -Update the TypeScript next tag to [`typescript@next`](https://www.npmjs.com/package/typescript/v/7.1.0-dev.20260913.1), which ships [`typescript-go`](https://github.com/microsoft/typescript-go/commit/879f9867ac455404e75759dd1739281cf6aa7f85) commit `879f9867ac455404e75759dd1739281cf6aa7f85`, and update the TypeScript latest tag to [`typescript@latest`](https://www.npmjs.com/package/typescript/v/7.0.2). +Update the TypeScript next tag to [`typescript@next`](https://www.npmjs.com/package/typescript/v/7.1.0-dev.20260915.1), which ships [`typescript-go`](https://github.com/microsoft/typescript-go/commit/57d9528db25b8dc8375e18468a870ec3f4277d62) commit `57d9528db25b8dc8375e18468a870ec3f4277d62`, and update the TypeScript latest tag to [`typescript@latest`](https://www.npmjs.com/package/typescript/v/7.0.2). diff --git a/_packages/tsgo/upstream.json b/_packages/tsgo/upstream.json index c7457f13..1ee34dbe 100644 --- a/_packages/tsgo/upstream.json +++ b/_packages/tsgo/upstream.json @@ -3,7 +3,7 @@ "tags": { "typescript": { "latest": "7.0.2", - "next": "7.1.0-dev.20260913.1" + "next": "7.1.0-dev.20260915.1" }, "oxlint": { "latest": "1.83.0" @@ -18,8 +18,8 @@ "gitHead": "2bd066d87f5bafd315be9f40889d0a60b9e58e0b", "provider": "typescript-go" }, - "7.1.0-dev.20260913.1": { - "gitHead": "879f9867ac455404e75759dd1739281cf6aa7f85", + "7.1.0-dev.20260915.1": { + "gitHead": "57d9528db25b8dc8375e18468a870ec3f4277d62", "provider": "typescript" } }, diff --git a/flake.lock b/flake.lock index 540e54ce..ff38c5a5 100644 --- a/flake.lock +++ b/flake.lock @@ -42,17 +42,17 @@ "typescript-src": { "flake": false, "locked": { - "lastModified": 1789157459, - "narHash": "sha256-YhSxez5zZ/ZNkM7hK6BqqT8pJKIMSsBJwXF5Q6CufLE=", + "lastModified": 1789427885, + "narHash": "sha256-jmanZXjQAa6tOrbMMQ/mQnxN8mUelpJqL2sQrcCfQu0=", "owner": "microsoft", "repo": "TypeScript", - "rev": "879f9867ac455404e75759dd1739281cf6aa7f85", + "rev": "57d9528db25b8dc8375e18468a870ec3f4277d62", "type": "github" }, "original": { "owner": "microsoft", "repo": "TypeScript", - "rev": "879f9867ac455404e75759dd1739281cf6aa7f85", + "rev": "57d9528db25b8dc8375e18468a870ec3f4277d62", "type": "github" } } diff --git a/flake.nix b/flake.nix index af2911bd..7161c6d6 100644 --- a/flake.nix +++ b/flake.nix @@ -6,7 +6,7 @@ nixpkgsUnstable.url = "github:NixOS/nixpkgs/nixos-unstable"; /* Source of truth: the next profile in `_packages/tsgo/upstream.json`. */ typescript-src = { - url = "github:microsoft/TypeScript/879f9867ac455404e75759dd1739281cf6aa7f85"; + url = "github:microsoft/TypeScript/57d9528db25b8dc8375e18468a870ec3f4277d62"; flake = false; }; }; From 6b0040e0d6a3a4e433e30753e291c43751278485 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Sep 2026 07:48:02 +0000 Subject: [PATCH 4/5] chore: update generated/latest --- .changeset/strict-diagnostic-preset.md | 5 + .changeset/update-upstreams.md | 2 +- _packages/tsgo/src/cli/presets.ts | 2 +- _packages/tsgo/src/cli/setup/rule-info.ts | 2 +- _packages/tsgo/src/metadata.json | 284 ++++++++++++++++++ _packages/tsgo/test/presets.test.ts | 25 ++ _packages/tsgo/upstream.json | 6 +- docs/README.md | 4 +- etscore/oxlint_schema_test.go | 37 +-- flake.lock | 8 +- flake.nix | 2 +- internal/rules/metadata.go | 55 +++- internal/rules/metadata_test.go | 97 ++++++ oxlint-presets/recommended.json | 21 -- oxlint-presets/strict.json | 90 ++++++ .../.oxlintrc-recommended-override.json | 2 +- testdata/tests/oxlint/global-date.ts | 1 - testdata/tests/oxlint/smoke.mjs | 17 +- 18 files changed, 584 insertions(+), 76 deletions(-) create mode 100644 .changeset/strict-diagnostic-preset.md create mode 100644 internal/rules/metadata_test.go create mode 100644 oxlint-presets/strict.json delete mode 100644 testdata/tests/oxlint/global-date.ts diff --git a/.changeset/strict-diagnostic-preset.md b/.changeset/strict-diagnostic-preset.md new file mode 100644 index 00000000..4aa5167f --- /dev/null +++ b/.changeset/strict-diagnostic-preset.md @@ -0,0 +1,5 @@ +--- +"@effect/tsgo": minor +--- + +Add a `strict` diagnostic preset that promotes every default-enabled diagnostic to an error. Expose the complete preset catalog consistently through TypeScript setup and the generated Oxlint presets. diff --git a/.changeset/update-upstreams.md b/.changeset/update-upstreams.md index 6be58494..5db621de 100644 --- a/.changeset/update-upstreams.md +++ b/.changeset/update-upstreams.md @@ -2,4 +2,4 @@ "@effect/tsgo": patch --- -Update the TypeScript next tag to [`typescript@next`](https://www.npmjs.com/package/typescript/v/7.1.0-dev.20260915.1), which ships [`typescript-go`](https://github.com/microsoft/typescript-go/commit/57d9528db25b8dc8375e18468a870ec3f4277d62) commit `57d9528db25b8dc8375e18468a870ec3f4277d62`, and update the TypeScript latest tag to [`typescript@latest`](https://www.npmjs.com/package/typescript/v/7.0.2). +Update the TypeScript next tag to [`typescript@next`](https://www.npmjs.com/package/typescript/v/7.1.0-dev.20260916.1), which ships [`typescript-go`](https://github.com/microsoft/typescript-go/commit/d2b20b35034bd902bdda5974f522ff00352895e9) commit `d2b20b35034bd902bdda5974f522ff00352895e9`, and update the TypeScript latest tag to [`typescript@latest`](https://www.npmjs.com/package/typescript/v/7.0.2). diff --git a/_packages/tsgo/src/cli/presets.ts b/_packages/tsgo/src/cli/presets.ts index 992ade98..73c7ad69 100644 --- a/_packages/tsgo/src/cli/presets.ts +++ b/_packages/tsgo/src/cli/presets.ts @@ -18,7 +18,7 @@ interface MetadataDocument { readonly presets: ReadonlyArray } -const metadata = metadataJson as MetadataDocument +const metadata = metadataJson as unknown as MetadataDocument const severityRank: Record = { off: 0, diff --git a/_packages/tsgo/src/cli/setup/rule-info.ts b/_packages/tsgo/src/cli/setup/rule-info.ts index ae2502e7..c684ce34 100644 --- a/_packages/tsgo/src/cli/setup/rule-info.ts +++ b/_packages/tsgo/src/cli/setup/rule-info.ts @@ -39,7 +39,7 @@ export function getAllGroups(): ReadonlyArray { } export function getAllPresets(): ReadonlyArray { - return (metadataJson as { presets?: ReadonlyArray }).presets ?? [] + return (metadataJson as unknown as { presets?: ReadonlyArray }).presets ?? [] } export function cycleSeverity( diff --git a/_packages/tsgo/src/metadata.json b/_packages/tsgo/src/metadata.json index d00bbb9b..76b87cf5 100644 --- a/_packages/tsgo/src/metadata.json +++ b/_packages/tsgo/src/metadata.json @@ -22,6 +22,231 @@ } ], "presets": [ + { + "name": "recommended", + "description": "Enable diagnostics at their default severities.", + "diagnosticSeverity": { + "abortControllerInEffect": "suggestion", + "acquireReleaseDisposable": "suggestion", + "allOfMapToForEach": "suggestion", + "catchAllTagDispatchToCatchTag": "suggestion", + "catchAllToMapError": "suggestion", + "catchChainToFirstSuccessOf": "suggestion", + "catchConditionalRefailToCatchIf": "suggestion", + "catchDieToOrDie": "suggestion", + "catchIfTagToCatchTag": "suggestion", + "catchRefailToTapError": "suggestion", + "catchTagToCatchReason": "suggestion", + "catchToIgnore": "suggestion", + "catchToOrElseSucceed": "suggestion", + "catchUnfailableEffect": "suggestion", + "classSelfMismatch": "error", + "duplicatePackage": "warning", + "effectFnIife": "warning", + "effectFnImplicitAny": "error", + "effectFnOpportunity": "suggestion", + "effectGenUsesAdapter": "warning", + "effectInFailure": "warning", + "effectInVoidSuccess": "warning", + "effectMapFlatten": "suggestion", + "effectMapVoid": "suggestion", + "effectSucceedWithVoid": "suggestion", + "flatMapConditionalToFilterOrFail": "suggestion", + "flatMapIgnoredParamToAndThen": "suggestion", + "flatMapToMap": "suggestion", + "floatingEffect": "error", + "floatingEffectInVitest": "error", + "genericEffectServices": "warning", + "globalErrorInEffectCatch": "warning", + "globalErrorInEffectFailure": "warning", + "layerMergeAllWithDependencies": "warning", + "lazyEffect": "suggestion", + "lazyPromiseInEffectSync": "warning", + "leakingRequirements": "suggestion", + "mapSomeToAsSome": "suggestion", + "matchEffectToMapBoth": "suggestion", + "matchEffectToMatch": "suggestion", + "missingEffectContext": "error", + "missingEffectError": "error", + "missingLayerContext": "error", + "missingReturnYieldStar": "error", + "missingStarInYieldEffectGen": "error", + "multipleCatchTag": "suggestion", + "multipleEffectProvide": "warning", + "nonObjectEffectServiceType": "error", + "obsoleteMatchImport": "warning", + "obsoleteSchemaImport": "warning", + "optionMatchToFromOption": "suggestion", + "outdatedApi": "warning", + "overriddenSchemaConstructor": "error", + "preferSucceedSomeOrNone": "suggestion", + "preferTypedSchemaDecoder": "suggestion", + "preferUnsafeConstructor": "suggestion", + "promiseInEffectSuccess": "warning", + "provideLayerSucceedToProvideService": "suggestion", + "raceFirstWithSleepToTimeout": "suggestion", + "redundantMapError": "suggestion", + "redundantOrDie": "suggestion", + "redundantSchemaTagIdentifier": "suggestion", + "returnEffectInGen": "suggestion", + "runEffectInsideEffect": "suggestion", + "runOfExitToRunExit": "suggestion", + "schemaLiteralNonFinite": "error", + "schemaNumber": "suggestion", + "schemaOpaqueInstanceMember": "error", + "schemaStructWithTag": "suggestion", + "schemaSyncInEffect": "suggestion", + "scopeInLayerEffect": "warning", + "syncToSucceed": "suggestion", + "timeoutCatchTagToTimeoutOrElse": "suggestion", + "tryCatchInEffectGen": "suggestion", + "unknownInEffectCatch": "warning", + "unnecessaryEffectGen": "suggestion", + "unnecessaryFailYieldableError": "suggestion", + "unnecessaryPipe": "suggestion", + "unnecessaryPipeChain": "suggestion", + "unnecessaryTypeofType": "suggestion" + } + }, + { + "name": "strict", + "description": "Treat every diagnostic enabled by default as an error.", + "diagnosticSeverity": { + "abortControllerInEffect": "error", + "acquireReleaseDisposable": "error", + "allOfMapToForEach": "error", + "catchAllTagDispatchToCatchTag": "error", + "catchAllToMapError": "error", + "catchChainToFirstSuccessOf": "error", + "catchConditionalRefailToCatchIf": "error", + "catchDieToOrDie": "error", + "catchIfTagToCatchTag": "error", + "catchRefailToTapError": "error", + "catchTagToCatchReason": "error", + "catchToIgnore": "error", + "catchToOrElseSucceed": "error", + "catchUnfailableEffect": "error", + "classSelfMismatch": "error", + "duplicatePackage": "error", + "effectFnIife": "error", + "effectFnImplicitAny": "error", + "effectFnOpportunity": "error", + "effectGenUsesAdapter": "error", + "effectInFailure": "error", + "effectInVoidSuccess": "error", + "effectMapFlatten": "error", + "effectMapVoid": "error", + "effectSucceedWithVoid": "error", + "flatMapConditionalToFilterOrFail": "error", + "flatMapIgnoredParamToAndThen": "error", + "flatMapToMap": "error", + "floatingEffect": "error", + "floatingEffectInVitest": "error", + "genericEffectServices": "error", + "globalErrorInEffectCatch": "error", + "globalErrorInEffectFailure": "error", + "layerMergeAllWithDependencies": "error", + "lazyEffect": "error", + "lazyPromiseInEffectSync": "error", + "leakingRequirements": "error", + "mapSomeToAsSome": "error", + "matchEffectToMapBoth": "error", + "matchEffectToMatch": "error", + "missingEffectContext": "error", + "missingEffectError": "error", + "missingLayerContext": "error", + "missingReturnYieldStar": "error", + "missingStarInYieldEffectGen": "error", + "multipleCatchTag": "error", + "multipleEffectProvide": "error", + "nonObjectEffectServiceType": "error", + "obsoleteMatchImport": "error", + "obsoleteSchemaImport": "error", + "optionMatchToFromOption": "error", + "outdatedApi": "error", + "overriddenSchemaConstructor": "error", + "preferSucceedSomeOrNone": "error", + "preferTypedSchemaDecoder": "error", + "preferUnsafeConstructor": "error", + "promiseInEffectSuccess": "error", + "provideLayerSucceedToProvideService": "error", + "raceFirstWithSleepToTimeout": "error", + "redundantMapError": "error", + "redundantOrDie": "error", + "redundantSchemaTagIdentifier": "error", + "returnEffectInGen": "error", + "runEffectInsideEffect": "error", + "runOfExitToRunExit": "error", + "schemaLiteralNonFinite": "error", + "schemaNumber": "error", + "schemaOpaqueInstanceMember": "error", + "schemaStructWithTag": "error", + "schemaSyncInEffect": "error", + "scopeInLayerEffect": "error", + "syncToSucceed": "error", + "timeoutCatchTagToTimeoutOrElse": "error", + "tryCatchInEffectGen": "error", + "unknownInEffectCatch": "error", + "unnecessaryEffectGen": "error", + "unnecessaryFailYieldableError": "error", + "unnecessaryPipe": "error", + "unnecessaryPipeChain": "error", + "unnecessaryTypeofType": "error" + } + }, + { + "name": "correctness", + "description": "Enable all correctness diagnostics at warning level.", + "diagnosticSeverity": { + "anyUnknownInErrorContext": "warning", + "classSelfMismatch": "warning", + "duplicatePackage": "warning", + "effectFnImplicitAny": "warning", + "floatingEffect": "warning", + "floatingEffectInVitest": "warning", + "genericEffectServices": "warning", + "missingEffectContext": "warning", + "missingEffectError": "warning", + "missingLayerContext": "warning", + "missingReturnYieldStar": "warning", + "missingStarInYieldEffectGen": "warning", + "nonObjectEffectServiceType": "warning", + "obsoleteMatchImport": "warning", + "obsoleteSchemaImport": "warning", + "outdatedApi": "warning", + "overriddenSchemaConstructor": "warning", + "promiseInEffectSuccess": "warning", + "schemaLiteralNonFinite": "warning", + "schemaOpaqueInstanceMember": "warning", + "unsafeEffectTypeAssertion": "warning" + } + }, + { + "name": "antipattern", + "description": "Enable all anti-pattern diagnostics at warning level.", + "diagnosticSeverity": { + "catchUnfailableEffect": "warning", + "effectFnIife": "warning", + "effectGenUsesAdapter": "warning", + "effectInFailure": "warning", + "effectInVoidSuccess": "warning", + "globalErrorInEffectCatch": "warning", + "globalErrorInEffectFailure": "warning", + "layerMergeAllWithDependencies": "warning", + "lazyEffect": "warning", + "lazyPromiseInEffectSync": "warning", + "leakingRequirements": "warning", + "multipleEffectProvide": "warning", + "preferUnsafeConstructor": "warning", + "returnEffectInGen": "warning", + "runEffectInsideEffect": "warning", + "schemaSyncInEffect": "warning", + "scopeInLayerEffect": "warning", + "strictEffectProvide": "warning", + "tryCatchInEffectGen": "warning", + "unknownInEffectCatch": "warning" + } + }, { "name": "effect-native", "description": "Enable all Effect-native diagnostics at warning level.", @@ -49,6 +274,65 @@ "processEnvInEffect": "warning", "schemaSync": "warning" } + }, + { + "name": "style", + "description": "Enable all style diagnostics at warning level.", + "diagnosticSeverity": { + "acquireReleaseDisposable": "warning", + "allOfMapToForEach": "warning", + "catchAllTagDispatchToCatchTag": "warning", + "catchAllToMapError": "warning", + "catchChainToFirstSuccessOf": "warning", + "catchConditionalRefailToCatchIf": "warning", + "catchDieToOrDie": "warning", + "catchIfTagToCatchTag": "warning", + "catchRefailToTapError": "warning", + "catchTagToCatchReason": "warning", + "catchToIgnore": "warning", + "catchToOrElseSucceed": "warning", + "deterministicKeys": "warning", + "effectDoNotation": "warning", + "effectFnOpportunity": "warning", + "effectMapFlatten": "warning", + "effectMapVoid": "warning", + "effectSucceedWithVoid": "warning", + "flatMapConditionalToFilterOrFail": "warning", + "flatMapIgnoredParamToAndThen": "warning", + "flatMapToMap": "warning", + "mapSomeToAsSome": "warning", + "matchEffectToMapBoth": "warning", + "matchEffectToMatch": "warning", + "missedPipeableOpportunity": "warning", + "missingEffectServiceDependency": "warning", + "missingPipeableSignature": "warning", + "multipleCatchTag": "warning", + "nestedEffectGenYield": "warning", + "newSchemaClass": "warning", + "optionMatchToFromOption": "warning", + "preferSchemaTypeProperty": "warning", + "preferSucceedSomeOrNone": "warning", + "preferTypedSchemaDecoder": "warning", + "provideLayerSucceedToProvideService": "warning", + "raceFirstWithSleepToTimeout": "warning", + "redundantMapError": "warning", + "redundantOrDie": "warning", + "redundantSchemaTagIdentifier": "warning", + "runOfExitToRunExit": "warning", + "schemaNumber": "warning", + "schemaStructWithTag": "warning", + "schemaUnionOfLiterals": "warning", + "serviceNotAsClass": "warning", + "strictBooleanExpressions": "warning", + "syncToSucceed": "warning", + "timeoutCatchTagToTimeoutOrElse": "warning", + "unnecessaryArrowBlock": "warning", + "unnecessaryEffectGen": "warning", + "unnecessaryFailYieldableError": "warning", + "unnecessaryPipe": "warning", + "unnecessaryPipeChain": "warning", + "unnecessaryTypeofType": "warning" + } } ], "rules": [ diff --git a/_packages/tsgo/test/presets.test.ts b/_packages/tsgo/test/presets.test.ts index f85297c0..1b27ace5 100644 --- a/_packages/tsgo/test/presets.test.ts +++ b/_packages/tsgo/test/presets.test.ts @@ -8,6 +8,31 @@ import { } from "../src/cli/presets.js" describe("diagnostic presets", () => { + it("exposes the complete preset catalog", () => { + expect(presets.map((preset) => preset.name)).toEqual([ + "recommended", + "strict", + "correctness", + "antipattern", + "effect-native", + "style" + ]) + }) + + it("makes every diagnostic enabled by default an error in strict mode", () => { + const strict = presets.find((preset) => preset.name === "strict")! + + expect(strict.diagnosticSeverity).not.toEqual({}) + expect(Object.values(strict.diagnosticSeverity).every((severity) => severity === "error")).toBe(true) + }) + + it("uses only default-enabled diagnostics in the recommended preset", () => { + const recommended = presets.find((preset) => preset.name === "recommended")! + + expect(recommended.diagnosticSeverity.floatingEffect).toBe("error") + expect(recommended.diagnosticSeverity.globalDate).toBeUndefined() + }) + it("merges the selected preset severities", () => { expect(mergePresetDiagnosticSeverities(["effect-native"])).toEqual( presets.find((preset) => preset.name === "effect-native")!.diagnosticSeverity diff --git a/_packages/tsgo/upstream.json b/_packages/tsgo/upstream.json index 1ee34dbe..cdb32f9f 100644 --- a/_packages/tsgo/upstream.json +++ b/_packages/tsgo/upstream.json @@ -3,7 +3,7 @@ "tags": { "typescript": { "latest": "7.0.2", - "next": "7.1.0-dev.20260915.1" + "next": "7.1.0-dev.20260916.1" }, "oxlint": { "latest": "1.83.0" @@ -18,8 +18,8 @@ "gitHead": "2bd066d87f5bafd315be9f40889d0a60b9e58e0b", "provider": "typescript-go" }, - "7.1.0-dev.20260915.1": { - "gitHead": "57d9528db25b8dc8375e18468a870ec3f4277d62", + "7.1.0-dev.20260916.1": { + "gitHead": "d2b20b35034bd902bdda5974f522ff00352895e9", "provider": "typescript" } }, diff --git a/docs/README.md b/docs/README.md index cc7cc401..38c56cb2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,7 +41,7 @@ Run pnpm install to install the dependencies and run the prepare script to patch pnpm install ``` -Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The recommended preset enables both and configures the recommended Effect rules. Use the schema shipped with `@effect/tsgo` for validation and completions: +Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The recommended preset enables both and configures every default-enabled Effect rule. Use the schema shipped with `@effect/tsgo` for validation and completions: ```json { @@ -52,7 +52,7 @@ Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The r } ``` -The package also provides presets for each diagnostic category: `correctness`, `antipattern`, `effect-native`, and `style`. Extended configurations are applied in order, and rules in the project configuration take precedence, so categories can be combined and individual rules can be adjusted: +The package also provides presets for each diagnostic category: `correctness`, `antipattern`, `effect-native`, and `style`. The `strict` preset promotes every diagnostic enabled by default to an error. Extended configurations are applied in order, and rules in the project configuration take precedence, so presets can be combined and individual rules can be adjusted: ```json { diff --git a/etscore/oxlint_schema_test.go b/etscore/oxlint_schema_test.go index 14d31236..a0e5ed22 100644 --- a/etscore/oxlint_schema_test.go +++ b/etscore/oxlint_schema_test.go @@ -112,35 +112,16 @@ type oxlintPresetOptions struct { } func generateOxlintPresets() (map[string][]byte, error) { - groups := rules.MetadataGroups() - generated := make(map[string][]byte, len(groups)+1) - - recommendedSeverities := make(map[string]string) - for _, current := range rules.All { - if severity := oxlintSeverity(current.DefaultSeverity); severity != "off" { - recommendedSeverities[oxlintRuleName(current.Name)] = severity - } - } - for _, preset := range rules.MetadataPresets() { - for name, severity := range preset.DiagnosticSeverity { - oxlintName := oxlintRuleName(name) - if current, next := recommendedSeverities[oxlintName], oxlintSeverity(severity); current != "error" && next != "off" { - recommendedSeverities[oxlintName] = next - } - } - } - if err := addOxlintPreset(generated, "recommended.json", recommendedSeverities); err != nil { - return nil, err - } - - for _, group := range groups { - severities := make(map[string]string) - for _, current := range rules.All { - if current.Group == group.ID { - severities[oxlintRuleName(current.Name)] = "warn" - } + diagnosticPresets := rules.MetadataPresets() + generated := make(map[string][]byte, len(diagnosticPresets)) + + for _, preset := range diagnosticPresets { + name := oxlintRuleName(preset.Name) + ".json" + severities := make(map[string]string, len(preset.DiagnosticSeverity)) + for ruleName, severity := range preset.DiagnosticSeverity { + severities[oxlintRuleName(ruleName)] = oxlintSeverity(severity) } - if err := addOxlintPreset(generated, oxlintRuleName(group.ID)+".json", severities); err != nil { + if err := addOxlintPreset(generated, name, severities); err != nil { return nil, err } } diff --git a/flake.lock b/flake.lock index ff38c5a5..b2db940c 100644 --- a/flake.lock +++ b/flake.lock @@ -42,17 +42,17 @@ "typescript-src": { "flake": false, "locked": { - "lastModified": 1789427885, - "narHash": "sha256-jmanZXjQAa6tOrbMMQ/mQnxN8mUelpJqL2sQrcCfQu0=", + "lastModified": 1789505560, + "narHash": "sha256-IoETNpBUJ7crjhjBYJHo22Hg9QmBSvBWGfrdRxWrMxQ=", "owner": "microsoft", "repo": "TypeScript", - "rev": "57d9528db25b8dc8375e18468a870ec3f4277d62", + "rev": "d2b20b35034bd902bdda5974f522ff00352895e9", "type": "github" }, "original": { "owner": "microsoft", "repo": "TypeScript", - "rev": "57d9528db25b8dc8375e18468a870ec3f4277d62", + "rev": "d2b20b35034bd902bdda5974f522ff00352895e9", "type": "github" } } diff --git a/flake.nix b/flake.nix index 7161c6d6..72f7f1e8 100644 --- a/flake.nix +++ b/flake.nix @@ -6,7 +6,7 @@ nixpkgsUnstable.url = "github:NixOS/nixpkgs/nixos-unstable"; /* Source of truth: the next profile in `_packages/tsgo/upstream.json`. */ typescript-src = { - url = "github:microsoft/TypeScript/57d9528db25b8dc8375e18468a870ec3f4277d62"; + url = "github:microsoft/TypeScript/d2b20b35034bd902bdda5974f522ff00352895e9"; flake = false; }; }; diff --git a/internal/rules/metadata.go b/internal/rules/metadata.go index dfb3f82d..1cdb56ea 100644 --- a/internal/rules/metadata.go +++ b/internal/rules/metadata.go @@ -19,11 +19,38 @@ func MetadataGroups() []rule.MetadataGroup { } func MetadataPresets() []rule.MetadataPreset { - return []rule.MetadataPreset{{ - Name: "effect-native", - Description: "Enable all Effect-native diagnostics at warning level.", - DiagnosticSeverity: buildGroupPreset("effectNative", etscore.SeverityWarning), - }} + return []rule.MetadataPreset{ + { + Name: "recommended", + Description: "Enable diagnostics at their default severities.", + DiagnosticSeverity: buildDefaultPreset(), + }, + { + Name: "strict", + Description: "Treat every diagnostic enabled by default as an error.", + DiagnosticSeverity: buildStrictPreset(), + }, + { + Name: "correctness", + Description: "Enable all correctness diagnostics at warning level.", + DiagnosticSeverity: buildGroupPreset("correctness", etscore.SeverityWarning), + }, + { + Name: "antipattern", + Description: "Enable all anti-pattern diagnostics at warning level.", + DiagnosticSeverity: buildGroupPreset("antipattern", etscore.SeverityWarning), + }, + { + Name: "effect-native", + Description: "Enable all Effect-native diagnostics at warning level.", + DiagnosticSeverity: buildGroupPreset("effectNative", etscore.SeverityWarning), + }, + { + Name: "style", + Description: "Enable all style diagnostics at warning level.", + DiagnosticSeverity: buildGroupPreset("style", etscore.SeverityWarning), + }, + } } func buildGroupPreset(group string, severity etscore.Severity) map[string]etscore.Severity { @@ -35,3 +62,21 @@ func buildGroupPreset(group string, severity etscore.Severity) map[string]etscor } return preset } + +func buildStrictPreset() map[string]etscore.Severity { + preset := buildDefaultPreset() + for name := range preset { + preset[name] = etscore.SeverityError + } + return preset +} + +func buildDefaultPreset() map[string]etscore.Severity { + preset := make(map[string]etscore.Severity) + for _, current := range All { + if !current.DefaultSeverity.IsOff() { + preset[current.Name] = current.DefaultSeverity + } + } + return preset +} diff --git a/internal/rules/metadata_test.go b/internal/rules/metadata_test.go new file mode 100644 index 00000000..17aa5180 --- /dev/null +++ b/internal/rules/metadata_test.go @@ -0,0 +1,97 @@ +package rules + +import ( + "slices" + "testing" + + "github.com/effect-ts/tsgo/etscore" +) + +func TestStrictPreset(t *testing.T) { + t.Parallel() + + strict := metadataPresetByName(t, "strict") + + for _, current := range All { + severity, included := strict[current.Name] + if current.DefaultSeverity == etscore.SeverityOff { + if included { + t.Errorf("off-by-default diagnostic %q is included", current.Name) + } + continue + } + if !included { + t.Errorf("enabled-by-default diagnostic %q is missing", current.Name) + } else if severity != etscore.SeverityError { + t.Errorf("diagnostic %q has severity %q, want error", current.Name, severity) + } + } +} + +func TestRecommendedPreset(t *testing.T) { + t.Parallel() + + recommended := metadataPresetByName(t, "recommended") + for _, current := range All { + severity, included := recommended[current.Name] + switch { + case current.DefaultSeverity.IsOff(): + if included { + t.Errorf("off-by-default diagnostic %q is included", current.Name) + } + case !included: + t.Errorf("enabled-by-default diagnostic %q is missing", current.Name) + case severity != current.DefaultSeverity: + t.Errorf("diagnostic %q has severity %q, want default %q", current.Name, severity, current.DefaultSeverity) + } + } +} + +func TestMetadataPresetCatalog(t *testing.T) { + t.Parallel() + + presets := MetadataPresets() + names := make([]string, len(presets)) + for index, preset := range presets { + names[index] = preset.Name + } + want := []string{"recommended", "strict", "correctness", "antipattern", "effect-native", "style"} + if !slices.Equal(names, want) { + t.Fatalf("preset names = %v, want %v", names, want) + } + + groups := map[string]string{ + "correctness": "correctness", + "antipattern": "antipattern", + "effect-native": "effectNative", + "style": "style", + } + for presetName, group := range groups { + preset := metadataPresetByName(t, presetName) + for _, current := range All { + severity, included := preset[current.Name] + if current.Group != group { + if included { + t.Errorf("preset %q includes diagnostic %q from group %q", presetName, current.Name, current.Group) + } + continue + } + if !included { + t.Errorf("preset %q is missing diagnostic %q", presetName, current.Name) + } else if severity != etscore.SeverityWarning { + t.Errorf("preset %q diagnostic %q has severity %q, want warning", presetName, current.Name, severity) + } + } + } +} + +func metadataPresetByName(t *testing.T, name string) map[string]etscore.Severity { + t.Helper() + for _, preset := range MetadataPresets() { + if preset.Name == name { + return preset.DiagnosticSeverity + } + } + t.Fatalf("preset %q not found", name) + return nil +} diff --git a/oxlint-presets/recommended.json b/oxlint-presets/recommended.json index f95a5ba7..e77da26c 100644 --- a/oxlint-presets/recommended.json +++ b/oxlint-presets/recommended.json @@ -9,7 +9,6 @@ "effecttsgo/abort-controller-in-effect": "warn", "effecttsgo/acquire-release-disposable": "warn", "effecttsgo/all-of-map-to-for-each": "warn", - "effecttsgo/async-function": "warn", "effecttsgo/catch-all-tag-dispatch-to-catch-tag": "warn", "effecttsgo/catch-all-to-map-error": "warn", "effecttsgo/catch-chain-to-first-success-of": "warn", @@ -22,8 +21,6 @@ "effecttsgo/catch-to-or-else-succeed": "warn", "effecttsgo/catch-unfailable-effect": "warn", "effecttsgo/class-self-mismatch": "error", - "effecttsgo/crypto-random-uuid": "warn", - "effecttsgo/crypto-random-uuid-in-effect": "warn", "effecttsgo/duplicate-package": "warn", "effecttsgo/effect-fn-iife": "warn", "effecttsgo/effect-fn-implicit-any": "error", @@ -34,26 +31,14 @@ "effecttsgo/effect-map-flatten": "warn", "effecttsgo/effect-map-void": "warn", "effecttsgo/effect-succeed-with-void": "warn", - "effecttsgo/extends-native-error": "warn", "effecttsgo/flat-map-conditional-to-filter-or-fail": "warn", "effecttsgo/flat-map-ignored-param-to-and-then": "warn", "effecttsgo/flat-map-to-map": "warn", "effecttsgo/floating-effect": "error", "effecttsgo/floating-effect-in-vitest": "error", "effecttsgo/generic-effect-services": "warn", - "effecttsgo/global-console": "warn", - "effecttsgo/global-console-in-effect": "warn", - "effecttsgo/global-date": "warn", - "effecttsgo/global-date-in-effect": "warn", "effecttsgo/global-error-in-effect-catch": "warn", "effecttsgo/global-error-in-effect-failure": "warn", - "effecttsgo/global-fetch": "warn", - "effecttsgo/global-fetch-in-effect": "warn", - "effecttsgo/global-random": "warn", - "effecttsgo/global-random-in-effect": "warn", - "effecttsgo/global-timers": "warn", - "effecttsgo/global-timers-in-effect": "warn", - "effecttsgo/instance-of-schema": "warn", "effecttsgo/layer-merge-all-with-dependencies": "warn", "effecttsgo/lazy-effect": "warn", "effecttsgo/lazy-promise-in-effect-sync": "warn", @@ -68,20 +53,15 @@ "effecttsgo/missing-star-in-yield-effect-gen": "error", "effecttsgo/multiple-catch-tag": "warn", "effecttsgo/multiple-effect-provide": "warn", - "effecttsgo/new-promise": "warn", - "effecttsgo/node-builtin-import": "warn", "effecttsgo/non-object-effect-service-type": "error", "effecttsgo/obsolete-match-import": "warn", "effecttsgo/obsolete-schema-import": "warn", "effecttsgo/option-match-to-from-option": "warn", "effecttsgo/outdated-api": "warn", "effecttsgo/overridden-schema-constructor": "error", - "effecttsgo/prefer-schema-over-json": "warn", "effecttsgo/prefer-succeed-some-or-none": "warn", "effecttsgo/prefer-typed-schema-decoder": "warn", "effecttsgo/prefer-unsafe-constructor": "warn", - "effecttsgo/process-env": "warn", - "effecttsgo/process-env-in-effect": "warn", "effecttsgo/promise-in-effect-success": "warn", "effecttsgo/provide-layer-succeed-to-provide-service": "warn", "effecttsgo/race-first-with-sleep-to-timeout": "warn", @@ -95,7 +75,6 @@ "effecttsgo/schema-number": "warn", "effecttsgo/schema-opaque-instance-member": "error", "effecttsgo/schema-struct-with-tag": "warn", - "effecttsgo/schema-sync": "warn", "effecttsgo/schema-sync-in-effect": "warn", "effecttsgo/scope-in-layer-effect": "warn", "effecttsgo/sync-to-succeed": "warn", diff --git a/oxlint-presets/strict.json b/oxlint-presets/strict.json new file mode 100644 index 00000000..8ce88c77 --- /dev/null +++ b/oxlint-presets/strict.json @@ -0,0 +1,90 @@ +{ + "options": { + "typeAware": true + }, + "plugins": [ + "effecttsgo" + ], + "rules": { + "effecttsgo/abort-controller-in-effect": "error", + "effecttsgo/acquire-release-disposable": "error", + "effecttsgo/all-of-map-to-for-each": "error", + "effecttsgo/catch-all-tag-dispatch-to-catch-tag": "error", + "effecttsgo/catch-all-to-map-error": "error", + "effecttsgo/catch-chain-to-first-success-of": "error", + "effecttsgo/catch-conditional-refail-to-catch-if": "error", + "effecttsgo/catch-die-to-or-die": "error", + "effecttsgo/catch-if-tag-to-catch-tag": "error", + "effecttsgo/catch-refail-to-tap-error": "error", + "effecttsgo/catch-tag-to-catch-reason": "error", + "effecttsgo/catch-to-ignore": "error", + "effecttsgo/catch-to-or-else-succeed": "error", + "effecttsgo/catch-unfailable-effect": "error", + "effecttsgo/class-self-mismatch": "error", + "effecttsgo/duplicate-package": "error", + "effecttsgo/effect-fn-iife": "error", + "effecttsgo/effect-fn-implicit-any": "error", + "effecttsgo/effect-fn-opportunity": "error", + "effecttsgo/effect-gen-uses-adapter": "error", + "effecttsgo/effect-in-failure": "error", + "effecttsgo/effect-in-void-success": "error", + "effecttsgo/effect-map-flatten": "error", + "effecttsgo/effect-map-void": "error", + "effecttsgo/effect-succeed-with-void": "error", + "effecttsgo/flat-map-conditional-to-filter-or-fail": "error", + "effecttsgo/flat-map-ignored-param-to-and-then": "error", + "effecttsgo/flat-map-to-map": "error", + "effecttsgo/floating-effect": "error", + "effecttsgo/floating-effect-in-vitest": "error", + "effecttsgo/generic-effect-services": "error", + "effecttsgo/global-error-in-effect-catch": "error", + "effecttsgo/global-error-in-effect-failure": "error", + "effecttsgo/layer-merge-all-with-dependencies": "error", + "effecttsgo/lazy-effect": "error", + "effecttsgo/lazy-promise-in-effect-sync": "error", + "effecttsgo/leaking-requirements": "error", + "effecttsgo/map-some-to-as-some": "error", + "effecttsgo/match-effect-to-map-both": "error", + "effecttsgo/match-effect-to-match": "error", + "effecttsgo/missing-effect-context": "error", + "effecttsgo/missing-effect-error": "error", + "effecttsgo/missing-layer-context": "error", + "effecttsgo/missing-return-yield-star": "error", + "effecttsgo/missing-star-in-yield-effect-gen": "error", + "effecttsgo/multiple-catch-tag": "error", + "effecttsgo/multiple-effect-provide": "error", + "effecttsgo/non-object-effect-service-type": "error", + "effecttsgo/obsolete-match-import": "error", + "effecttsgo/obsolete-schema-import": "error", + "effecttsgo/option-match-to-from-option": "error", + "effecttsgo/outdated-api": "error", + "effecttsgo/overridden-schema-constructor": "error", + "effecttsgo/prefer-succeed-some-or-none": "error", + "effecttsgo/prefer-typed-schema-decoder": "error", + "effecttsgo/prefer-unsafe-constructor": "error", + "effecttsgo/promise-in-effect-success": "error", + "effecttsgo/provide-layer-succeed-to-provide-service": "error", + "effecttsgo/race-first-with-sleep-to-timeout": "error", + "effecttsgo/redundant-map-error": "error", + "effecttsgo/redundant-or-die": "error", + "effecttsgo/redundant-schema-tag-identifier": "error", + "effecttsgo/return-effect-in-gen": "error", + "effecttsgo/run-effect-inside-effect": "error", + "effecttsgo/run-of-exit-to-run-exit": "error", + "effecttsgo/schema-literal-non-finite": "error", + "effecttsgo/schema-number": "error", + "effecttsgo/schema-opaque-instance-member": "error", + "effecttsgo/schema-struct-with-tag": "error", + "effecttsgo/schema-sync-in-effect": "error", + "effecttsgo/scope-in-layer-effect": "error", + "effecttsgo/sync-to-succeed": "error", + "effecttsgo/timeout-catch-tag-to-timeout-or-else": "error", + "effecttsgo/try-catch-in-effect-gen": "error", + "effecttsgo/unknown-in-effect-catch": "error", + "effecttsgo/unnecessary-effect-gen": "error", + "effecttsgo/unnecessary-fail-yieldable-error": "error", + "effecttsgo/unnecessary-pipe": "error", + "effecttsgo/unnecessary-pipe-chain": "error", + "effecttsgo/unnecessary-typeof-type": "error" + } +} diff --git a/testdata/tests/oxlint/.oxlintrc-recommended-override.json b/testdata/tests/oxlint/.oxlintrc-recommended-override.json index b80c8e13..a06a958d 100644 --- a/testdata/tests/oxlint/.oxlintrc-recommended-override.json +++ b/testdata/tests/oxlint/.oxlintrc-recommended-override.json @@ -1,6 +1,6 @@ { "extends": ["../../../oxlint-presets/recommended.json"], "rules": { - "effecttsgo/global-date": "off" + "effecttsgo/floating-effect": "off" } } diff --git a/testdata/tests/oxlint/global-date.ts b/testdata/tests/oxlint/global-date.ts deleted file mode 100644 index 4c890ca3..00000000 --- a/testdata/tests/oxlint/global-date.ts +++ /dev/null @@ -1 +0,0 @@ -export const now = Date.now() diff --git a/testdata/tests/oxlint/smoke.mjs b/testdata/tests/oxlint/smoke.mjs index b6a1f412..6b44defc 100644 --- a/testdata/tests/oxlint/smoke.mjs +++ b/testdata/tests/oxlint/smoke.mjs @@ -27,9 +27,12 @@ const run = (...args) => spawnSync(process.execPath, [oxlint, ...args], { const packagePreset = spawnSync(process.execPath, [ "--input-type=module", "--eval", - `import { recommended } from "@effect/tsgo/oxlint-presets"; + `import { recommended, strict } from "@effect/tsgo/oxlint-presets"; import recommendedJson from "@effect/tsgo/oxlint-presets/recommended.json" with { type: "json" }; - if (recommended.rules["effecttsgo/global-date"] !== "warn" || recommendedJson.rules["effecttsgo/global-date"] !== "warn") process.exit(1);` + import strictJson from "@effect/tsgo/oxlint-presets/strict.json" with { type: "json" }; + if (recommended.rules["effecttsgo/floating-effect"] !== "error" || recommendedJson.rules["effecttsgo/floating-effect"] !== "error") process.exit(1); + if (recommended.rules["effecttsgo/global-date"] !== undefined || recommendedJson.rules["effecttsgo/global-date"] !== undefined) process.exit(1); + if (strict.rules["effecttsgo/catch-unfailable-effect"] !== "error" || strictJson.rules["effecttsgo/catch-unfailable-effect"] !== "error") process.exit(1);` ], { cwd: packageDirectory, encoding: "utf8" @@ -62,12 +65,12 @@ const disabled = run("--type-aware", "--config", ".oxlintrc.json", "disabled.ts" assert.equal(disabled.status, 0, disabled.stderr) assert.doesNotMatch(`${disabled.stdout}\n${disabled.stderr}`, /effecttsgo\(floating-effect\)/) -const recommended = run("--config", ".oxlintrc-recommended.json", "global-date.ts") -assert.equal(recommended.status, 0, recommended.stderr) -assert.match(`${recommended.stdout}\n${recommended.stderr}`, /effecttsgo\(global-date\)/) +const recommended = run("--config", ".oxlintrc-recommended.json", "diagnostic.ts") +assert.equal(recommended.status, 1, recommended.stderr) +assert.match(`${recommended.stdout}\n${recommended.stderr}`, /effecttsgo\(floating-effect\)/) -const recommendedOverride = run("--config", ".oxlintrc-recommended-override.json", "global-date.ts") +const recommendedOverride = run("--config", ".oxlintrc-recommended-override.json", "diagnostic.ts") assert.equal(recommendedOverride.status, 0, recommendedOverride.stderr) -assert.doesNotMatch(`${recommendedOverride.stdout}\n${recommendedOverride.stderr}`, /effecttsgo\(global-date\)/) +assert.doesNotMatch(`${recommendedOverride.stdout}\n${recommendedOverride.stderr}`, /effecttsgo\(floating-effect\)/) console.log("Oxlint profile smoke test passed") From 30bba888076b32000c629ed54af6c5f238953c48 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Sep 2026 09:56:14 +0000 Subject: [PATCH 5/5] chore: update generated/latest --- .changeset/unknown-diagnostic-rule.md | 7 + .../030-tsoptions-validation.patch | 29 ++ .../typescript/030-tsoptions-validation.patch | 29 ++ _tools/gen_shims/config/tsoptions/foreach.go | 12 + .../typescript-go/tsoptions/compatibility.go | 26 ++ .../typescript-go/tsoptions/extra-shim.json | 2 +- .../typescript/tsoptions/compatibility.go | 21 ++ .../typescript/tsoptions/extra-shim.json | 2 +- etscheckerhooks/init.go | 2 + .../diagnostics/effectDiagnosticMessages.json | 4 + internal/effectconfigcheck/validation.go | 123 ++++++++ internal/effectconfigcheck/validation_test.go | 272 ++++++++++++++++++ internal/rule/rule.go | 6 + internal/rulerunner/diagnostics.go | 2 +- shim/_backport/diagnostics/shim.go | 1 + shim/_backport/tsoptions/compatibility.go | 26 ++ shim/_backport/tsoptions/foreach.go | 12 + shim/_backport/tsoptions/shim.go | 7 +- shim/diagnostics/shim.go | 1 + shim/tsoptions/compatibility.go | 26 ++ shim/tsoptions/foreach.go | 12 + shim/tsoptions/shim.go | 5 +- 22 files changed, 619 insertions(+), 8 deletions(-) create mode 100644 .changeset/unknown-diagnostic-rule.md create mode 100644 _patches/typescript-go/030-tsoptions-validation.patch create mode 100644 _patches/typescript/030-tsoptions-validation.patch create mode 100644 _tools/gen_shims/config/tsoptions/foreach.go create mode 100644 internal/effectconfigcheck/validation.go create mode 100644 internal/effectconfigcheck/validation_test.go create mode 100644 shim/_backport/tsoptions/foreach.go create mode 100644 shim/tsoptions/foreach.go diff --git a/.changeset/unknown-diagnostic-rule.md b/.changeset/unknown-diagnostic-rule.md new file mode 100644 index 00000000..a8135d4e --- /dev/null +++ b/.changeset/unknown-diagnostic-rule.md @@ -0,0 +1,7 @@ +--- +"@effect/tsgo": minor +--- + +Warn when `diagnosticSeverity` contains an unknown Effect rule name, including in overrides and inherited configurations. For example, `"floatingEfect": "error"` now reports `effect(unknownRuleName)` instead of being silently ignored. + +The check uses the fully merged configuration. Set `"unknownRuleName": "off"` to disable it or `"unknownRuleName": "error"` to raise its severity. Local keys are underlined in tsconfig; inherited keys without local syntax produce a diagnostic without a source location. diff --git a/_patches/typescript-go/030-tsoptions-validation.patch b/_patches/typescript-go/030-tsoptions-validation.patch new file mode 100644 index 00000000..d464fc24 --- /dev/null +++ b/_patches/typescript-go/030-tsoptions-validation.patch @@ -0,0 +1,29 @@ +diff --git a/internal/tsoptions/tsconfigparsing.go b/internal/tsoptions/tsconfigparsing.go +--- a/internal/tsoptions/tsconfigparsing.go ++++ b/internal/tsoptions/tsconfigparsing.go +@@ -19,6 +19,14 @@ + "github.com/microsoft/typescript-go/internal/vfs" + "github.com/microsoft/typescript-go/internal/vfs/vfsmatch" + ) ++ ++// ValidateCompilerOptionsCallback validates the final options after configuration ++// inheritance and existing options have been merged. ++var ValidateCompilerOptionsCallback func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic ++ ++func RegisterValidateCompilerOptionsCallback(cb func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic) { ++ ValidateCompilerOptionsCallback = cb ++} + + type extendsResult struct { + options *core.CompilerOptions +@@ -1367,6 +1375,10 @@ + return projectReferences + } + ++ if ValidateCompilerOptionsCallback != nil { ++ errors = append(errors, ValidateCompilerOptionsCallback(parsedConfig.options, tsconfigToSourceFile(sourceFile))...) ++ } ++ + fileNames, literalFileNamesLen := getFileNames(basePathForFileNames) + return &ParsedCommandLine{ + ParsedConfig: &core.ParsedOptions{ diff --git a/_patches/typescript/030-tsoptions-validation.patch b/_patches/typescript/030-tsoptions-validation.patch new file mode 100644 index 00000000..b8382981 --- /dev/null +++ b/_patches/typescript/030-tsoptions-validation.patch @@ -0,0 +1,29 @@ +diff --git a/tsc/internal/tsoptions/tsconfigparsing.go b/tsc/internal/tsoptions/tsconfigparsing.go +--- a/tsc/internal/tsoptions/tsconfigparsing.go ++++ b/tsc/internal/tsoptions/tsconfigparsing.go +@@ -22,6 +22,14 @@ + "github.com/microsoft/TypeScript/tsc/internal/vfs" + "github.com/microsoft/TypeScript/tsc/internal/vfs/vfsmatch" + ) ++ ++// ValidateCompilerOptionsCallback validates the final options after configuration ++// inheritance and existing options have been merged. ++var ValidateCompilerOptionsCallback func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic ++ ++func RegisterValidateCompilerOptionsCallback(cb func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic) { ++ ValidateCompilerOptionsCallback = cb ++} + + type extendsResult struct { + options *core.CompilerOptions +@@ -1508,6 +1516,10 @@ + return projectReferences + } + ++ if ValidateCompilerOptionsCallback != nil { ++ errors = append(errors, ValidateCompilerOptionsCallback(parsedConfig.options, tsconfigToSourceFile(sourceFile))...) ++ } ++ + fileNames, literalFileNamesLen := getFileNames(basePathForFileNames) + compileOnSave := new(false) + if raw, ok := parsedConfig.raw.(*collections.OrderedMap[string, any]); ok { diff --git a/_tools/gen_shims/config/tsoptions/foreach.go b/_tools/gen_shims/config/tsoptions/foreach.go new file mode 100644 index 00000000..41dec680 --- /dev/null +++ b/_tools/gen_shims/config/tsoptions/foreach.go @@ -0,0 +1,12 @@ +package tsoptions + +import ( + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/tsoptions" +) + +// ForEachTsConfigPropArray forwards through a regular call because go:linkname +// does not support generic functions. +func ForEachTsConfigPropArray[T any](sourceFile *ast.SourceFile, propKey string, callback func(*ast.PropertyAssignment) *T) *T { + return tsoptions.ForEachTsConfigPropArray(sourceFile, propKey, callback) +} diff --git a/_tools/gen_shims/providers/typescript-go/tsoptions/compatibility.go b/_tools/gen_shims/providers/typescript-go/tsoptions/compatibility.go index ed9f29bf..c575a7de 100644 --- a/_tools/gen_shims/providers/typescript-go/tsoptions/compatibility.go +++ b/_tools/gen_shims/providers/typescript-go/tsoptions/compatibility.go @@ -7,6 +7,32 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) +func ParseJsonConfigFileContent( + json any, + host tsoptions.ParseConfigHost, + basePath string, + existingOptions *core.CompilerOptions, + configFileName string, + resolutionStack []tspath.Path, + extraFileExtensions any, + extendedConfigCache tsoptions.ExtendedConfigCache, +) *tsoptions.ParsedCommandLine { + var extensions []tsoptions.FileExtensionInfo + if extraFileExtensions != nil { + extensions = extraFileExtensions.([]tsoptions.FileExtensionInfo) + } + return tsoptions.ParseJsonConfigFileContent( + json, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + extensions, + extendedConfigCache, + ) +} + func ParseJsonSourceFileConfigFileContent( sourceFile *tsoptions.TsConfigSourceFile, host tsoptions.ParseConfigHost, diff --git a/_tools/gen_shims/providers/typescript-go/tsoptions/extra-shim.json b/_tools/gen_shims/providers/typescript-go/tsoptions/extra-shim.json index 671b3056..cb667a60 100644 --- a/_tools/gen_shims/providers/typescript-go/tsoptions/extra-shim.json +++ b/_tools/gen_shims/providers/typescript-go/tsoptions/extra-shim.json @@ -1,3 +1,3 @@ { - "IgnoreFunctions": ["ParseJsonSourceFileConfigFileContent"] + "IgnoreFunctions": ["ParseJsonSourceFileConfigFileContent", "ParseJsonConfigFileContent"] } diff --git a/_tools/gen_shims/providers/typescript/tsoptions/compatibility.go b/_tools/gen_shims/providers/typescript/tsoptions/compatibility.go index 8d0d29cc..fc955cfa 100644 --- a/_tools/gen_shims/providers/typescript/tsoptions/compatibility.go +++ b/_tools/gen_shims/providers/typescript/tsoptions/compatibility.go @@ -7,6 +7,27 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) +func ParseJsonConfigFileContent( + json any, + host tsoptions.ParseConfigHost, + basePath string, + existingOptions *core.CompilerOptions, + configFileName string, + resolutionStack []tspath.Path, + _ any, + extendedConfigCache tsoptions.ExtendedConfigCache, +) *tsoptions.ParsedCommandLine { + return tsoptions.ParseJsonConfigFileContent( + json, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + extendedConfigCache, + ) +} + func ParseJsonSourceFileConfigFileContent( sourceFile *tsoptions.TsConfigSourceFile, host tsoptions.ParseConfigHost, diff --git a/_tools/gen_shims/providers/typescript/tsoptions/extra-shim.json b/_tools/gen_shims/providers/typescript/tsoptions/extra-shim.json index 671b3056..cb667a60 100644 --- a/_tools/gen_shims/providers/typescript/tsoptions/extra-shim.json +++ b/_tools/gen_shims/providers/typescript/tsoptions/extra-shim.json @@ -1,3 +1,3 @@ { - "IgnoreFunctions": ["ParseJsonSourceFileConfigFileContent"] + "IgnoreFunctions": ["ParseJsonSourceFileConfigFileContent", "ParseJsonConfigFileContent"] } diff --git a/etscheckerhooks/init.go b/etscheckerhooks/init.go index 9201af62..d3572ac1 100644 --- a/etscheckerhooks/init.go +++ b/etscheckerhooks/init.go @@ -7,6 +7,7 @@ import ( "context" "github.com/effect-ts/tsgo/etscore" + "github.com/effect-ts/tsgo/internal/effectconfigcheck" "github.com/effect-ts/tsgo/internal/effectconfigraw" "github.com/effect-ts/tsgo/internal/rulerunner" "github.com/microsoft/TypeScript/tsc/shim/ast" @@ -19,6 +20,7 @@ func init() { // Set the version suffix so that core.Version() includes the Effect version core.SetVersionSuffix("+effect-tsgo." + etscore.EffectVersion) effectconfigraw.Register() + effectconfigcheck.Register() // Register the after check source file callback checker.RegisterAfterCheckSourceFileCallback(afterCheckSourceFile) } diff --git a/internal/diagnostics/effectDiagnosticMessages.json b/internal/diagnostics/effectDiagnosticMessages.json index 1db9e0fa..9ff46b55 100644 --- a/internal/diagnostics/effectDiagnosticMessages.json +++ b/internal/diagnostics/effectDiagnosticMessages.json @@ -526,5 +526,9 @@ "`Effect.andThen` expresses this sequencing more directly than `Effect.flatMap` with a zero-parameter callback. effect(flatMapIgnoredParamToAndThen)": { "category": "Suggestion", "code": 377132 + }, + "Unknown Effect diagnostic rule `{0}` in `diagnosticSeverity`. effect(unknownRuleName)": { + "category": "Warning", + "code": 377134 } } diff --git a/internal/effectconfigcheck/validation.go b/internal/effectconfigcheck/validation.go new file mode 100644 index 00000000..57937f18 --- /dev/null +++ b/internal/effectconfigcheck/validation.go @@ -0,0 +1,123 @@ +// Package effectconfigcheck validates resolved Effect compiler options. +package effectconfigcheck + +import ( + "slices" + + "github.com/effect-ts/tsgo/etscore" + "github.com/effect-ts/tsgo/internal/directives" + "github.com/effect-ts/tsgo/internal/rule" + "github.com/effect-ts/tsgo/internal/rules" + "github.com/microsoft/TypeScript/tsc/shim/ast" + "github.com/microsoft/TypeScript/tsc/shim/core" + "github.com/microsoft/TypeScript/tsc/shim/diagnostics" + "github.com/microsoft/TypeScript/tsc/shim/tsoptions" +) + +func Register() { + tsoptions.RegisterValidateCompilerOptionsCallback(validate) +} + +func validate(options *core.CompilerOptions, sourceFile *ast.SourceFile) []*ast.Diagnostic { + if options == nil || !etscore.DiagnosticsEnabled(options.Effect) { + return nil + } + config := options.Effect + severity, configured := config.DiagnosticSeverity[rule.UnknownRuleNameName] + if !configured { + severity = etscore.SeverityWarning + } + if severity.IsOff() { + return nil + } + + // Syntax is used only to locate diagnostics; validation uses the merged options. + plugin := effectPluginSyntax(sourceFile) + var result []*ast.Diagnostic + check := func(severities map[string]etscore.Severity, syntax *ast.Node) { + var unknown []string + for name := range severities { + if name != rule.UnusedDirectiveName && name != rule.UnknownRuleNameName && rule.ByName(rules.All, name) == nil { + unknown = append(unknown, name) + } + } + // Maps have no iteration order; keep CLI output and baselines deterministic. + slices.Sort(unknown) + for _, name := range unknown { + var node *ast.Node + if property := findProperty(syntax, name); property != nil { + node = property.Name() + } + diagnostic := tsoptions.CreateDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, node, + diagnostics.Unknown_Effect_diagnostic_rule_0_in_diagnosticSeverity_effect_unknownRuleName, + name, + ) + diagnostic.SetCategory(directives.ToCategory(severity)) + result = append(result, diagnostic) + } + } + check(config.DiagnosticSeverity, propertyValue(plugin, "diagnosticSeverity")) + + // Inherited overrides precede local overrides. Only local object entries have + // syntax in this file, and the parser skips non-object entries. + var localOverrides []*ast.Node + for _, node := range arrayElements(propertyValue(plugin, "overrides")) { + if ast.IsObjectLiteralExpression(node) { + localOverrides = append(localOverrides, node) + } + } + localStart := len(config.Overrides) - len(localOverrides) + for i, override := range config.Overrides { + var syntax *ast.Node + if localStart >= 0 && i >= localStart { + syntax = propertyValue(propertyValue(localOverrides[i-localStart], "options"), "diagnosticSeverity") + } + check(override.Options.DiagnosticSeverity, syntax) + } + return result +} + +func effectPluginSyntax(sourceFile *ast.SourceFile) *ast.Node { + compilerOptions := tsoptions.ForEachTsConfigPropArray(sourceFile, "compilerOptions", func(property *ast.PropertyAssignment) *ast.PropertyAssignment { + return property + }) + if compilerOptions == nil { + return nil + } + for _, plugin := range arrayElements(propertyValue(compilerOptions.Initializer, "plugins")) { + name := propertyValue(plugin, "name") + if name != nil && ast.IsStringLiteralLike(name) && name.Text() == etscore.EffectPluginName { + return plugin + } + } + return nil +} + +func findProperty(node *ast.Node, name string) *ast.PropertyAssignment { + if node == nil || !ast.IsObjectLiteralExpression(node) { + return nil + } + var result *ast.PropertyAssignment + for _, property := range node.Properties() { + if ast.IsPropertyAssignment(property) && ast.GetTextOfPropertyName(property.Name()) == name { + // JSON parsing retains the last value for duplicate keys. + result = property.AsPropertyAssignment() + } + } + return result +} + +func propertyValue(node *ast.Node, name string) *ast.Node { + if property := findProperty(node, name); property != nil { + return property.Initializer + } + return nil +} + +func arrayElements(node *ast.Node) []*ast.Node { + if node != nil && ast.IsArrayLiteralExpression(node) { + return node.Elements() + } + return nil +} diff --git a/internal/effectconfigcheck/validation_test.go b/internal/effectconfigcheck/validation_test.go new file mode 100644 index 00000000..6deedb52 --- /dev/null +++ b/internal/effectconfigcheck/validation_test.go @@ -0,0 +1,272 @@ +package effectconfigcheck_test + +import ( + "strings" + "testing" + "testing/fstest" + + _ "github.com/effect-ts/tsgo/etscheckerhooks" + "github.com/effect-ts/tsgo/etscore" + "github.com/microsoft/TypeScript/tsc/shim/ast" + "github.com/microsoft/TypeScript/tsc/shim/bundled" + "github.com/microsoft/TypeScript/tsc/shim/compiler" + "github.com/microsoft/TypeScript/tsc/shim/core" + "github.com/microsoft/TypeScript/tsc/shim/diagnostics" + "github.com/microsoft/TypeScript/tsc/shim/execute/tsc" + "github.com/microsoft/TypeScript/tsc/shim/tsoptions" + "github.com/microsoft/TypeScript/tsc/shim/tspath" + "github.com/microsoft/TypeScript/tsc/shim/vfs" + "github.com/microsoft/TypeScript/tsc/shim/vfs/vfstest" +) + +type parseHost struct{ fs vfs.FS } + +func (h *parseHost) FS() vfs.FS { return h.fs } +func (h *parseHost) GetCurrentDirectory() string { return "/" } + +func newHost(files map[string]string) *parseHost { + entries := map[string]any{"/main.ts": &fstest.MapFile{Data: []byte("export {}")}} + for name, text := range files { + entries[name] = &fstest.MapFile{Data: []byte(text)} + } + return &parseHost{fs: bundled.WrapFS(vfstest.FromMap(entries, true))} +} + +func parse(t *testing.T, host *parseHost, path string, cache tsoptions.ExtendedConfigCache) *tsoptions.ParsedCommandLine { + t.Helper() + text, ok := host.fs.ReadFile(path) + if !ok { + t.Fatalf("missing config %s", path) + } + source := tsoptions.NewTsconfigSourceFileFromFilePath(path, tspath.Path(path), text) + return tsoptions.ParseJsonSourceFileConfigFileContent(source, host, tspath.GetDirectoryPath(path), nil, nil, path, nil, nil, cache) +} + +func config(options string, extra string) string { + return `{"files":["/main.ts"],"compilerOptions":{"plugins":[{"name":"@effect/language-service",` + options + `}]}` + extra + `}` +} + +func unknownDiagnostics(config *tsoptions.ParsedCommandLine) []*ast.Diagnostic { + var result []*ast.Diagnostic + for _, diagnostic := range config.Errors { + if diagnostic.Code() == 377134 { + result = append(result, diagnostic) + } + } + return result +} + +func TestUnknownRuleNames(t *testing.T) { + t.Parallel() + for _, tt := range []struct { + name, options string + count int + category diagnostics.Category + }{ + {"typo", `"diagnosticSeverity":{"floatingEfect":"error"}`, 1, diagnostics.CategoryWarning}, + {"unknown disabled rule still invalid", `"diagnosticSeverity":{"floatingEfect":"off"}`, 1, diagnostics.CategoryWarning}, + {"known names", `"diagnosticSeverity":{"floatingEffect":"error","unusedDirective":"warning","unknownRuleName":"warning"}`, 0, diagnostics.CategoryWarning}, + {"error", `"diagnosticSeverity":{"floatingEfect":"error","unknownRuleName":"error"}`, 1, diagnostics.CategoryError}, + {"suggestion", `"diagnosticSeverity":{"floatingEfect":"error","unknownRuleName":"suggestion"}`, 1, diagnostics.CategorySuggestion}, + {"off", `"diagnosticSeverity":{"floatingEfect":"error","unknownRuleName":"off"}`, 0, diagnostics.CategoryWarning}, + {"disabled", `"diagnostics":false,"diagnosticSeverity":{"floatingEfect":"error"}`, 0, diagnostics.CategoryWarning}, + {"null", `"diagnosticSeverity":null,"overrides":[{"options":{"diagnosticSeverity":{"floatingEfect":"error"}}}]`, 0, diagnostics.CategoryWarning}, + {"override", `"overrides":[null,{"options":{"diagnosticSeverity":{"floatingEfect":"error"}}}]`, 1, diagnostics.CategoryWarning}, + } { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{"/tsconfig.json": config(tt.options, "")}) + parsed := parse(t, host, "/tsconfig.json", nil) + got := unknownDiagnostics(parsed) + if len(got) != tt.count { + t.Fatalf("want %d warnings, got %d: %v", tt.count, len(got), parsed.Errors) + } + for _, diagnostic := range got { + if diagnostic.Category() != tt.category { + t.Fatalf("wrong category: %v", diagnostic.Category()) + } + if diagnostic.File() == nil || diagnostic.File().FileName() != "/tsconfig.json" { + t.Fatal("missing local config location") + } + if text := diagnostic.File().Text()[diagnostic.Pos():diagnostic.End()]; text != `"floatingEfect"` { + t.Fatalf("wrong underline: %q", text) + } + } + }) + } +} + +func TestUnknownRuleNamesExtends(t *testing.T) { + t.Parallel() + for _, tt := range []struct { + name, base, child string + count int + category diagnostics.Category + local bool + }{ + {"inherited key", `"diagnosticSeverity":{"floatingEfect":"error"}`, `"diagnosticSeverity":{}`, 1, diagnostics.CategoryWarning, false}, + {"child silences base", `"diagnosticSeverity":{"floatingEfect":"error"}`, `"diagnosticSeverity":{"unknownRuleName":"off"}`, 0, diagnostics.CategoryWarning, false}, + {"child disables diagnostics", `"diagnosticSeverity":{"floatingEfect":"error"}`, `"diagnostics":false`, 0, diagnostics.CategoryWarning, false}, + {"child raises base", `"diagnosticSeverity":{"floatingEfect":"error"}`, `"diagnosticSeverity":{"unknownRuleName":"error"}`, 1, diagnostics.CategoryError, false}, + {"base silences child", `"diagnosticSeverity":{"unknownRuleName":"off"}`, `"diagnosticSeverity":{"floatingEfect":"error"}`, 0, diagnostics.CategoryWarning, true}, + {"base disables child", `"diagnostics":false`, `"diagnosticSeverity":{"floatingEfect":"error"}`, 0, diagnostics.CategoryWarning, true}, + {"base raises child", `"diagnosticSeverity":{"unknownRuleName":"error"}`, `"diagnosticSeverity":{"floatingEfect":"error"}`, 1, diagnostics.CategoryError, true}, + } { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/base.json": config(tt.base, ""), + "/middle.json": `{"extends":"./base.json"}`, + "/tsconfig.json": config(tt.child, `,"extends":"./middle.json"`), + }) + parsed := parse(t, host, "/tsconfig.json", &tsc.ExtendedConfigCache{}) + got := unknownDiagnostics(parsed) + if len(got) != tt.count { + t.Fatalf("want %d warnings, got %d: %v", tt.count, len(got), parsed.Errors) + } + for _, d := range got { + if d.Category() != tt.category { + t.Fatalf("wrong category: %v", d.Category()) + } + if (d.File() != nil) != tt.local { + t.Fatalf("wrong inherited/local location: %v", d.File()) + } + } + }) + } +} + +func TestInheritedOverridesUseLocalSyntaxOnly(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/base.json": config(`"overrides":[{"options":{"diagnosticSeverity":{"inheritedTypo":"warning"}}}]`, ""), + "/tsconfig.json": config(`"overrides":[false,{"options":{"diagnosticSeverity":{"localTypo":"warning"}}}]`, `,"extends":"./base.json"`), + }) + got := unknownDiagnostics(parse(t, host, "/tsconfig.json", nil)) + if len(got) != 2 { + t.Fatalf("want two warnings, got %d", len(got)) + } + if got[0].File() != nil { + t.Fatal("inherited override must not be attributed to a local override") + } + if got[1].File() == nil { + t.Fatal("local override must have a location") + } + if text := got[1].File().Text()[got[1].Pos():got[1].End()]; text != `"localTypo"` { + t.Fatalf("wrong local underline: %q", text) + } +} + +func TestUnknownRuleNamesJSONAPI(t *testing.T) { + t.Parallel() + // Use the compiler's JSON representation, which both providers accept. + raw, errors := tsoptions.ParseConfigFileTextToJson("/tsconfig.json", "/tsconfig.json", config(`"diagnosticSeverity":{"floatingEfect":"error"}`, "")) + if len(errors) != 0 { + t.Fatalf("invalid config fixture: %v", errors) + } + parsed := tsoptions.ParseJsonConfigFileContent(raw, newHost(nil), "/", nil, "/tsconfig.json", nil, nil, nil) + got := unknownDiagnostics(parsed) + if len(got) != 1 || got[0].File() != nil { + t.Fatalf("expected one locationless warning: %v", got) + } +} + +func TestProjectReferencesAndSharedExtends(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/base.json": config(`"diagnosticSeverity":{"floatingEfect":"error"}`, ""), + "/tsconfig.json": `{"files":[],"references":[{"path":"./a"},{"path":"./b"},{"path":"./c"}]}`, + "/a/tsconfig.json": config(`"diagnosticSeverity":{"unknownRuleName":"off"}`, `,"extends":"../base.json"`), + "/b/tsconfig.json": config(`"diagnosticSeverity":{"unknownRuleName":"error"}`, `,"extends":"../base.json"`), + "/c/tsconfig.json": `{"extends":"../base.json"}`, + }) + cache := &tsc.ExtendedConfigCache{} + root := parse(t, host, "/tsconfig.json", cache) + program := compiler.NewProgram(compiler.ProgramOptions{ + Config: root, + Host: compiler.NewCompilerHost("/", host.fs, bundled.LibPath(), cache, nil), + SingleThreaded: core.TSTrue, + }) + if got := unknownDiagnostics(root); len(got) != 0 { + t.Fatal("reference diagnostics leaked into solution config") + } + refs := program.GetResolvedProjectReferences() + if len(refs) != 3 { + t.Fatalf("expected three resolved references, got %d", len(refs)) + } + for i, ref := range refs { + if ref == nil { + t.Fatalf("reference %d did not resolve", i) + } + got := unknownDiagnostics(ref) + if i == 0 { + if len(got) != 0 { + t.Fatal("project a did not silence inherited typo") + } + continue + } + category := diagnostics.CategoryWarning + if i == 1 { + category = diagnostics.CategoryError + } + if len(got) != 1 || got[0].Category() != category || got[0].File() != nil { + t.Fatalf("project %d: unexpected diagnostics %v", i, got) + } + } + // Parsing the base through the same cache must not reuse a child's severity. + got := unknownDiagnostics(parse(t, host, "/base.json", cache)) + if len(got) != 1 || got[0].Category() != diagnostics.CategoryWarning { + t.Fatalf("cached severity leaked: %v", got) + } +} + +func TestMultipleExtendsAndExistingOptions(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/base.json": config(`"diagnosticSeverity":{"floatingEfect":"error"}`, ""), + "/severity.json": config(`"diagnosticSeverity":{"unknownRuleName":"error"}`, ""), + "/tsconfig.json": `{"extends":["./base.json","./severity.json"]}`, + }) + got := unknownDiagnostics(parse(t, host, "/tsconfig.json", nil)) + if len(got) != 1 || got[0].Category() != diagnostics.CategoryError { + t.Fatalf("multiple extends failed: %v", got) + } + text, _ := host.fs.ReadFile("/tsconfig.json") + source := tsoptions.NewTsconfigSourceFileFromFilePath("/tsconfig.json", "/tsconfig.json", text) + existing := &core.CompilerOptions{Effect: &etscore.EffectPluginOptions{Diagnostics: true, DiagnosticSeverity: map[string]etscore.Severity{"existingTypo": etscore.SeverityError}}} + parsed := tsoptions.ParseJsonSourceFileConfigFileContent(source, host, "/", existing, nil, "/tsconfig.json", nil, nil, nil) + got = unknownDiagnostics(parsed) + if len(got) != 1 || !strings.Contains(strings.Join(got[0].MessageArgs(), " "), "existingTypo") { + t.Fatalf("existing options were not validated after merging: %v", got) + } +} + +func TestOtherPluginsAndCompilerErrors(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/tsconfig.json": `{"files":["/main.ts"],"compilerOptions":{"strcit":true,"plugins":[{"name":"other-plugin","diagnosticSeverity":{"unrelatedRule":"error"}}]}}`, + }) + parsed := parse(t, host, "/tsconfig.json", nil) + if len(unknownDiagnostics(parsed)) != 0 { + t.Fatal("validated an unrelated plugin") + } + if len(parsed.Errors) != 1 { + t.Fatalf("expected the existing compiler-option diagnostic, got %v", parsed.Errors) + } +} + +func TestUnknownRuleNamesDeterministicOrder(t *testing.T) { + t.Parallel() + host := newHost(map[string]string{ + "/tsconfig.json": config(`"diagnosticSeverity":{"zTypo":"warning","aTypo":"error","mTypo":"off"}`, ""), + }) + got := unknownDiagnostics(parse(t, host, "/tsconfig.json", nil)) + if len(got) != 3 { + t.Fatalf("expected three warnings, got %d", len(got)) + } + for i, name := range []string{"aTypo", "mTypo", "zTypo"} { + if args := got[i].MessageArgs(); len(args) != 1 || args[0] != name { + t.Fatalf("wrong diagnostic order: %v", args) + } + } +} diff --git a/internal/rule/rule.go b/internal/rule/rule.go index a135bb5a..d487ddf7 100644 --- a/internal/rule/rule.go +++ b/internal/rule/rule.go @@ -37,6 +37,12 @@ type Rule struct { Run func(ctx *Context) []*ast.Diagnostic } +// Configurable diagnostics that run outside the source-file rule registry. +const ( + UnusedDirectiveName = "unusedDirective" + UnknownRuleNameName = "unknownRuleName" +) + // ByName finds a rule by name in a slice. Returns nil if not found. func ByName(rules []Rule, name string) *Rule { for i := range rules { diff --git a/internal/rulerunner/diagnostics.go b/internal/rulerunner/diagnostics.go index caa39c86..461887a9 100644 --- a/internal/rulerunner/diagnostics.go +++ b/internal/rulerunner/diagnostics.go @@ -229,7 +229,7 @@ func createTransformedDiagnostic(original *ast.Diagnostic, newCategory tsdiag.Ca } func unusedDirectiveDiagnostics(sf *ast.SourceFile, allDirectives []directives.Directive, directiveSet *directives.DirectiveSet, resolvedSeverity map[string]etscore.Severity) []*ast.Diagnostic { - severity, ok := severityFromMap(resolvedSeverity, "unusedDirective") + severity, ok := severityFromMap(resolvedSeverity, rule.UnusedDirectiveName) if !ok { severity = etscore.SeverityWarning } diff --git a/shim/_backport/diagnostics/shim.go b/shim/_backport/diagnostics/shim.go index f8da8e92..0f471f85 100644 --- a/shim/_backport/diagnostics/shim.go +++ b/shim/_backport/diagnostics/shim.go @@ -2018,6 +2018,7 @@ var Unexpected_token_expected = diagnostics.Unexpected_token_expected var Unicode_escape_sequence_cannot_appear_here = diagnostics.Unicode_escape_sequence_cannot_appear_here var Unicode_escape_sequences_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set = diagnostics.Unicode_escape_sequences_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set var Unicode_property_value_expressions_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set = diagnostics.Unicode_property_value_expressions_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set +var Unknown_Effect_diagnostic_rule_0_in_diagnosticSeverity_effect_unknownRuleName = diagnostics.Unknown_Effect_diagnostic_rule_0_in_diagnosticSeverity_effect_unknownRuleName var Unknown_Unicode_property_name = diagnostics.Unknown_Unicode_property_name var Unknown_Unicode_property_name_or_value = diagnostics.Unknown_Unicode_property_name_or_value var Unknown_Unicode_property_value = diagnostics.Unknown_Unicode_property_value diff --git a/shim/_backport/tsoptions/compatibility.go b/shim/_backport/tsoptions/compatibility.go index 94805fc8..b9eca34e 100644 --- a/shim/_backport/tsoptions/compatibility.go +++ b/shim/_backport/tsoptions/compatibility.go @@ -7,6 +7,32 @@ import ( "github.com/microsoft/typescript-go/shim/tspath" ) +func ParseJsonConfigFileContent( + json any, + host tsoptions.ParseConfigHost, + basePath string, + existingOptions *core.CompilerOptions, + configFileName string, + resolutionStack []tspath.Path, + extraFileExtensions any, + extendedConfigCache tsoptions.ExtendedConfigCache, +) *tsoptions.ParsedCommandLine { + var extensions []tsoptions.FileExtensionInfo + if extraFileExtensions != nil { + extensions = extraFileExtensions.([]tsoptions.FileExtensionInfo) + } + return tsoptions.ParseJsonConfigFileContent( + json, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + extensions, + extendedConfigCache, + ) +} + func ParseJsonSourceFileConfigFileContent( sourceFile *tsoptions.TsConfigSourceFile, host tsoptions.ParseConfigHost, diff --git a/shim/_backport/tsoptions/foreach.go b/shim/_backport/tsoptions/foreach.go new file mode 100644 index 00000000..39f15e6a --- /dev/null +++ b/shim/_backport/tsoptions/foreach.go @@ -0,0 +1,12 @@ +package tsoptions + +import ( + "github.com/microsoft/typescript-go/shim/ast" + "github.com/microsoft/typescript-go/shim/tsoptions" +) + +// ForEachTsConfigPropArray forwards through a regular call because go:linkname +// does not support generic functions. +func ForEachTsConfigPropArray[T any](sourceFile *ast.SourceFile, propKey string, callback func(*ast.PropertyAssignment) *T) *T { + return tsoptions.ForEachTsConfigPropArray(sourceFile, propKey, callback) +} diff --git a/shim/_backport/tsoptions/shim.go b/shim/_backport/tsoptions/shim.go index ea2633e5..2bf39a03 100644 --- a/shim/_backport/tsoptions/shim.go +++ b/shim/_backport/tsoptions/shim.go @@ -136,9 +136,6 @@ type ParseConfigHost = tsoptions.ParseConfigHost //go:linkname ParseExtendedConfig github.com/microsoft/typescript-go/internal/tsoptions.ParseExtendedConfig func ParseExtendedConfig(fileName string, path tspath.Path, resolutionStack []tspath.Path, host tsoptions.ParseConfigHost, extendedConfigCache tsoptions.ExtendedConfigCache) *tsoptions.ExtendedConfigCacheEntry -//go:linkname ParseJsonConfigFileContent github.com/microsoft/typescript-go/internal/tsoptions.ParseJsonConfigFileContent -func ParseJsonConfigFileContent(json any, host tsoptions.ParseConfigHost, basePath string, existingOptions *core.CompilerOptions, configFileName string, resolutionStack []tspath.Path, extraFileExtensions []tsoptions.FileExtensionInfo, extendedConfigCache tsoptions.ExtendedConfigCache) *tsoptions.ParsedCommandLine - //go:linkname ParseListTypeOption github.com/microsoft/typescript-go/internal/tsoptions.ParseListTypeOption func ParseListTypeOption(opt *tsoptions.CommandLineOption, value string) ([]any, []*ast.Diagnostic) @@ -163,6 +160,9 @@ type ParsedCommandLine = tsoptions.ParsedCommandLine //go:linkname RegisterMergeCompilerOptionsCallback github.com/microsoft/typescript-go/internal/tsoptions.RegisterMergeCompilerOptionsCallback func RegisterMergeCompilerOptionsCallback(cb func(targetOptions *core.CompilerOptions, sourceOptions *core.CompilerOptions, rawSource any, sourceConfigPath string, basePath string)) +//go:linkname RegisterValidateCompilerOptionsCallback github.com/microsoft/typescript-go/internal/tsoptions.RegisterValidateCompilerOptionsCallback +func RegisterValidateCompilerOptionsCallback(cb func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic) + type SourceOutputAndProjectReference = tsoptions.SourceOutputAndProjectReference type TSConfig = tsoptions.TSConfig @@ -172,4 +172,5 @@ func TargetToLibMap() map[core.ScriptTarget]string type TsConfigSourceFile = tsoptions.TsConfigSourceFile var TscBuildOption = tsoptions.TscBuildOption +var ValidateCompilerOptionsCallback = tsoptions.ValidateCompilerOptionsCallback var WatchNameMap = tsoptions.WatchNameMap diff --git a/shim/diagnostics/shim.go b/shim/diagnostics/shim.go index d12eedf6..f5012b37 100644 --- a/shim/diagnostics/shim.go +++ b/shim/diagnostics/shim.go @@ -2004,6 +2004,7 @@ var Unexpected_token_expected = diagnostics.Unexpected_token_expected var Unicode_escape_sequence_cannot_appear_here = diagnostics.Unicode_escape_sequence_cannot_appear_here var Unicode_escape_sequences_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set = diagnostics.Unicode_escape_sequences_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set var Unicode_property_value_expressions_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set = diagnostics.Unicode_property_value_expressions_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set +var Unknown_Effect_diagnostic_rule_0_in_diagnosticSeverity_effect_unknownRuleName = diagnostics.Unknown_Effect_diagnostic_rule_0_in_diagnosticSeverity_effect_unknownRuleName var Unknown_Unicode_property_name = diagnostics.Unknown_Unicode_property_name var Unknown_Unicode_property_name_or_value = diagnostics.Unknown_Unicode_property_name_or_value var Unknown_Unicode_property_value = diagnostics.Unknown_Unicode_property_value diff --git a/shim/tsoptions/compatibility.go b/shim/tsoptions/compatibility.go index ed9f29bf..c575a7de 100644 --- a/shim/tsoptions/compatibility.go +++ b/shim/tsoptions/compatibility.go @@ -7,6 +7,32 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) +func ParseJsonConfigFileContent( + json any, + host tsoptions.ParseConfigHost, + basePath string, + existingOptions *core.CompilerOptions, + configFileName string, + resolutionStack []tspath.Path, + extraFileExtensions any, + extendedConfigCache tsoptions.ExtendedConfigCache, +) *tsoptions.ParsedCommandLine { + var extensions []tsoptions.FileExtensionInfo + if extraFileExtensions != nil { + extensions = extraFileExtensions.([]tsoptions.FileExtensionInfo) + } + return tsoptions.ParseJsonConfigFileContent( + json, + host, + basePath, + existingOptions, + configFileName, + resolutionStack, + extensions, + extendedConfigCache, + ) +} + func ParseJsonSourceFileConfigFileContent( sourceFile *tsoptions.TsConfigSourceFile, host tsoptions.ParseConfigHost, diff --git a/shim/tsoptions/foreach.go b/shim/tsoptions/foreach.go new file mode 100644 index 00000000..41dec680 --- /dev/null +++ b/shim/tsoptions/foreach.go @@ -0,0 +1,12 @@ +package tsoptions + +import ( + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/tsoptions" +) + +// ForEachTsConfigPropArray forwards through a regular call because go:linkname +// does not support generic functions. +func ForEachTsConfigPropArray[T any](sourceFile *ast.SourceFile, propKey string, callback func(*ast.PropertyAssignment) *T) *T { + return tsoptions.ForEachTsConfigPropArray(sourceFile, propKey, callback) +} diff --git a/shim/tsoptions/shim.go b/shim/tsoptions/shim.go index 91521673..6677ab7c 100644 --- a/shim/tsoptions/shim.go +++ b/shim/tsoptions/shim.go @@ -97,8 +97,6 @@ func ParseConfigFileTextToJson(fileName string, path tspath.Path, jsonText strin type ParseConfigHost = tsoptions.ParseConfigHost //go:linkname ParseExtendedConfig github.com/microsoft/typescript-go/internal/tsoptions.ParseExtendedConfig func ParseExtendedConfig(fileName string, path tspath.Path, resolutionStack []tspath.Path, host tsoptions.ParseConfigHost, extendedConfigCache tsoptions.ExtendedConfigCache) *tsoptions.ExtendedConfigCacheEntry -//go:linkname ParseJsonConfigFileContent github.com/microsoft/typescript-go/internal/tsoptions.ParseJsonConfigFileContent -func ParseJsonConfigFileContent(json any, host tsoptions.ParseConfigHost, basePath string, existingOptions *core.CompilerOptions, configFileName string, resolutionStack []tspath.Path, extraFileExtensions []tsoptions.FileExtensionInfo, extendedConfigCache tsoptions.ExtendedConfigCache) *tsoptions.ParsedCommandLine //go:linkname ParseListTypeOption github.com/microsoft/typescript-go/internal/tsoptions.ParseListTypeOption func ParseListTypeOption(opt *tsoptions.CommandLineOption, value string) ([]any, []*ast.Diagnostic) //go:linkname ParseString github.com/microsoft/typescript-go/internal/tsoptions.ParseString @@ -115,10 +113,13 @@ type ParsedBuildCommandLine = tsoptions.ParsedBuildCommandLine type ParsedCommandLine = tsoptions.ParsedCommandLine //go:linkname RegisterMergeCompilerOptionsCallback github.com/microsoft/typescript-go/internal/tsoptions.RegisterMergeCompilerOptionsCallback func RegisterMergeCompilerOptionsCallback(cb func(targetOptions *core.CompilerOptions, sourceOptions *core.CompilerOptions, rawSource any, sourceConfigPath string, basePath string)) +//go:linkname RegisterValidateCompilerOptionsCallback github.com/microsoft/typescript-go/internal/tsoptions.RegisterValidateCompilerOptionsCallback +func RegisterValidateCompilerOptionsCallback(cb func(*core.CompilerOptions, *ast.SourceFile) []*ast.Diagnostic) type SourceOutputAndProjectReference = tsoptions.SourceOutputAndProjectReference type TSConfig = tsoptions.TSConfig //go:linkname TargetToLibMap github.com/microsoft/typescript-go/internal/tsoptions.TargetToLibMap func TargetToLibMap() map[core.ScriptTarget]string type TsConfigSourceFile = tsoptions.TsConfigSourceFile var TscBuildOption = tsoptions.TscBuildOption +var ValidateCompilerOptionsCallback = tsoptions.ValidateCompilerOptionsCallback var WatchNameMap = tsoptions.WatchNameMap