From eeadcdb4e79b9602e084a72b9fe223387010c358 Mon Sep 17 00:00:00 2001 From: FND Date: Tue, 8 Sep 2026 17:44:02 +0200 Subject: [PATCH] feat(rules): add sleepThenEffectToDelay diagnostic Flags Effect.sleep sequenced before an effect via andThen, flatMap, or zipRight (pipe and data-first shapes), suggesting Effect.delay instead. Closes #610 --- .changeset/sleep-then-to-delay.md | 5 + README.md | 1 + _packages/tsgo/src/metadata.json | 24 ++ docs/rules/sleep-then-effect-to-delay.md | 67 ++++ .../diagnostics/effectDiagnosticMessages.json | 4 + internal/rules/rules.go | 1 + internal/rules/sleep_then_effect_to_delay.go | 234 ++++++++++++ shim/diagnostics/shim.go | 1 + .../sleepThenEffectToDelay.errors.txt | 26 ++ ...Delay.flows.sleepThenEffectToDelay.mermaid | 41 ++ .../sleepThenEffectToDelay.flows.txt | 1 + .../sleepThenEffectToDelay.layers.txt | 1 + .../sleepThenEffectToDelay.pipings.txt | 89 +++++ .../sleepThenEffectToDelay.quickfixes.txt | 5 + .../sleepThenEffectToDelay.errors.txt | 138 +++++++ ...Delay.flows.sleepThenEffectToDelay.mermaid | 207 ++++++++++ .../sleepThenEffectToDelay.flows.txt | 1 + .../sleepThenEffectToDelay.layers.txt | 1 + .../sleepThenEffectToDelay.pipings.txt | 359 ++++++++++++++++++ .../sleepThenEffectToDelay.quickfixes.txt | 93 +++++ .../sleepThenEffectToDelay_preview.errors.txt | 20 + ...ows.sleepThenEffectToDelay_preview.mermaid | 12 + .../sleepThenEffectToDelay_preview.flows.txt | 1 + .../sleepThenEffectToDelay_preview.layers.txt | 1 + ...sleepThenEffectToDelay_preview.pipings.txt | 19 + ...epThenEffectToDelay_preview.quickfixes.txt | 13 + .../tests/effect-v3/sleepThenEffectToDelay.ts | 19 + .../tests/effect-v4/sleepThenEffectToDelay.ts | 104 +++++ .../sleepThenEffectToDelay_preview.ts | 10 + 29 files changed, 1498 insertions(+) create mode 100644 .changeset/sleep-then-to-delay.md create mode 100644 docs/rules/sleep-then-effect-to-delay.md create mode 100644 internal/rules/sleep_then_effect_to_delay.go create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.errors.txt create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.txt create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.layers.txt create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.pipings.txt create mode 100644 testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.quickfixes.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.errors.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.layers.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.pipings.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.quickfixes.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.errors.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.sleepThenEffectToDelay_preview.mermaid create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.layers.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.pipings.txt create mode 100644 testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.quickfixes.txt create mode 100644 testdata/tests/effect-v3/sleepThenEffectToDelay.ts create mode 100644 testdata/tests/effect-v4/sleepThenEffectToDelay.ts create mode 100644 testdata/tests/effect-v4/sleepThenEffectToDelay_preview.ts diff --git a/.changeset/sleep-then-to-delay.md b/.changeset/sleep-then-to-delay.md new file mode 100644 index 00000000..fba8ee82 --- /dev/null +++ b/.changeset/sleep-then-to-delay.md @@ -0,0 +1,5 @@ +--- +"@effect/tsgo": patch +--- + +Add `sleepThenEffectToDelay` diagnostic (`TS377133`) to suggest using `Effect.delay` instead of sequencing `Effect.sleep` before an effect. diff --git a/README.md b/README.md index b3778c5c..72e61399 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Some diagnostics are off by default or have a default severity of suggestion, bu schemaStructWithTagSuggests using Schema.TaggedStruct instead of Schema.Struct with _tag field schemaUnionOfLiteralsSuggests combining multiple Schema.Literal calls in Schema.Union into a single Schema.Literal serviceNotAsClassWarns when Context.Service is used as a variable instead of a class declaration + sleepThenEffectToDelaySequencing Effect.sleep before an effect re-implements Effect.delay strictBooleanExpressionsEnforces boolean types in conditional expressions for type safety syncToSucceedSuggests using Effect.succeed instead of Effect.sync when the thunk returns a constant value timeoutCatchTagToTimeoutOrElseSuggests dedicated timeout combinators instead of catching TimeoutError immediately after Effect.timeout diff --git a/_packages/tsgo/src/metadata.json b/_packages/tsgo/src/metadata.json index b4483bac..07ec4279 100644 --- a/_packages/tsgo/src/metadata.json +++ b/_packages/tsgo/src/metadata.json @@ -2526,6 +2526,30 @@ ] } }, + { + "name": "sleepThenEffectToDelay", + "group": "style", + "description": "Sequencing Effect.sleep before an effect re-implements Effect.delay", + "defaultSeverity": "suggestion", + "fixable": false, + "supportedEffect": [ + "v3", + "v4" + ], + "codes": [ + 377133 + ], + "preview": { + "sourceText": "import { Effect } from \"effect\"\n\ndeclare const sendRequest: Effect.Effect\u003cvoid\u003e\n\nexport const throttled = Effect.sleep(\"1 second\").pipe(\n Effect.andThen(sendRequest)\n)\n", + "diagnostics": [ + { + "start": 139, + "end": 153, + "text": "Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay)" + } + ] + } + }, { "name": "strictBooleanExpressions", "group": "style", diff --git a/docs/rules/sleep-then-effect-to-delay.md b/docs/rules/sleep-then-effect-to-delay.md new file mode 100644 index 00000000..47074153 --- /dev/null +++ b/docs/rules/sleep-then-effect-to-delay.md @@ -0,0 +1,67 @@ + + +# `sleepThenEffectToDelay` + +Sequencing Effect.sleep before an effect re-implements Effect.delay + +| Property | Value | +| --- | --- | +| Category | Style | +| Default severity | `suggestion` | +| Fixable | No | +| Effect versions | v3, v4 | +| Diagnostic codes | `TS377133` | +| Language Service name | `sleepThenEffectToDelay` | +| Oxlint name | `effecttsgo/sleep-then-effect-to-delay` | + +## Preview + +```ts +import { Effect } from "effect" + +declare const sendRequest: Effect.Effect + +export const throttled = Effect.sleep("1 second").pipe( + Effect.andThen(sendRequest) +/** + ^^^^^^^^^^^^^^ effecttsgo(sleep-then-effect-to-delay): Sequencing Effect.sleep before an effect re-implements Effect.delay. +*/ +) +``` + +## 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": { + "sleepThenEffectToDelay": "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/sleep-then-effect-to-delay": "warn" + } +} +``` diff --git a/internal/diagnostics/effectDiagnosticMessages.json b/internal/diagnostics/effectDiagnosticMessages.json index 73c2c660..925f89d2 100644 --- a/internal/diagnostics/effectDiagnosticMessages.json +++ b/internal/diagnostics/effectDiagnosticMessages.json @@ -506,5 +506,9 @@ "This module reference imports `{0}`, which is obsolete in Effect v4. In Effect v4, Schema is provided directly by `Schema` from `effect` (or `effect/Schema`). effect(obsoleteSchemaImport)": { "category": "Warning", "code": 377128 + }, + "Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay)": { + "category": "Suggestion", + "code": 377133 } } diff --git a/internal/rules/rules.go b/internal/rules/rules.go index ccaa3bee..ed0e6303 100644 --- a/internal/rules/rules.go +++ b/internal/rules/rules.go @@ -119,4 +119,5 @@ var All = []rule.Rule{ AcquireReleaseDisposable, RaceFirstWithSleepToTimeout, RunOfExitToRunExit, + SleepThenEffectToDelay, } diff --git a/internal/rules/sleep_then_effect_to_delay.go b/internal/rules/sleep_then_effect_to_delay.go new file mode 100644 index 00000000..20240f26 --- /dev/null +++ b/internal/rules/sleep_then_effect_to_delay.go @@ -0,0 +1,234 @@ +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" + "github.com/microsoft/TypeScript/tsc/shim/core" + tsdiag "github.com/microsoft/TypeScript/tsc/shim/diagnostics" + "github.com/microsoft/TypeScript/tsc/shim/scanner" +) + +// SleepThenEffectToDelay suggests using Effect.delay instead of sequencing Effect.sleep before an effect. +var SleepThenEffectToDelay = rule.Rule{ + Name: "sleepThenEffectToDelay", + Group: "style", + Description: "Sequencing Effect.sleep before an effect re-implements Effect.delay", + DefaultSeverity: etscore.SeveritySuggestion, + SupportedEffect: []string{"v3", "v4"}, + Codes: []int32{ + tsdiag.Sequencing_Effect_sleep_before_an_effect_re_implements_Effect_delay_effect_sleepThenEffectToDelay.Code(), + }, + Run: func(ctx *rule.Context) []*ast.Diagnostic { + matches := AnalyzeSleepThenEffectToDelay(ctx.TypeParser, ctx.Checker, ctx.SourceFile) + diags := make([]*ast.Diagnostic, len(matches)) + for i, match := range matches { + diags[i] = ctx.NewDiagnostic( + match.SourceFile, + match.Location, + tsdiag.Sequencing_Effect_sleep_before_an_effect_re_implements_Effect_delay_effect_sleepThenEffectToDelay, + nil, + ) + } + return diags + }, +} + +// SleepThenEffectToDelayMatch holds match details for diagnostic emission. +type SleepThenEffectToDelayMatch struct { + SourceFile *ast.SourceFile + Location core.TextRange + Callee *ast.Node +} + +// AnalyzeSleepThenEffectToDelay finds sequencing calls where Effect.sleep is the first operand. +func AnalyzeSleepThenEffectToDelay(tp *typeparser.TypeParser, c *checker.Checker, sf *ast.SourceFile) []SleepThenEffectToDelayMatch { + if tp == nil || c == nil || sf == nil { + return nil + } + + var matches []SleepThenEffectToDelayMatch + visitedCallees := make(map[core.TextRange]bool) + + flows := tp.PipingFlows(sf, true) + for _, flow := range flows { + if flow == nil { + continue + } + + var sequencer *typeparser.PipingFlowTransformation + + if isDirectEffectSleepCall(tp, flow.Subject.Node) { + if len(flow.Transformations) > 0 { + sequencer = &flow.Transformations[0] + } + } else if len(flow.Transformations) > 1 && isEffectSleepTransformation(tp, &flow.Transformations[0]) { + sequencer = &flow.Transformations[1] + } + + if sequencer == nil || sequencer.Callee == nil { + continue + } + + if !isSequencerTransformation(tp, c, sequencer) { + continue + } + + loc := scanner.GetErrorRangeForNode(sf, sequencer.Callee) + if visitedCallees[loc] { + continue + } + visitedCallees[loc] = true + + matches = append(matches, SleepThenEffectToDelayMatch{ + SourceFile: sf, + Location: loc, + Callee: sequencer.Callee, + }) + } + + return matches +} + +func isDirectEffectSleepCall(tp *typeparser.TypeParser, node *ast.Node) bool { + if node == nil { + return false + } + node = ast.SkipParentheses(node) + if node.Kind != ast.KindCallExpression { + return false + } + call := node.AsCallExpression() + if call == nil || call.Expression == nil { + return false + } + return tp.IsNodeReferenceToEffectModuleApi(call.Expression, "sleep") +} + +func isEffectSleepTransformation(tp *typeparser.TypeParser, transformation *typeparser.PipingFlowTransformation) bool { + if transformation == nil || transformation.Callee == nil { + return false + } + return tp.IsNodeReferenceToEffectModuleApi(transformation.Callee, "sleep") +} + +func isSequencerTransformation(tp *typeparser.TypeParser, c *checker.Checker, transformation *typeparser.PipingFlowTransformation) bool { + if tp == nil || c == nil || transformation == nil || transformation.Callee == nil || len(transformation.Args) == 0 { + return false + } + callee := transformation.Callee + arg := transformation.Args[0] + if arg == nil { + return false + } + + switch { + case tp.IsNodeReferenceToEffectModuleApi(callee, "andThen"): + t := tp.GetTypeAtLocation(arg) + return sleepContinuationIsEffect(tp, t) + + case tp.IsNodeReferenceToEffectModuleApi(callee, "zipRight"): + t := tp.GetTypeAtLocation(arg) + return sleepContinuationIsEffect(tp, t) + + case tp.IsNodeReferenceToEffectModuleApi(callee, "flatMap"): + return isCallbackIgnoringParam(tp, c, arg) + + default: + return false + } +} + +func isCallbackIgnoringParam(tp *typeparser.TypeParser, c *checker.Checker, callbackNode *ast.Node) bool { + if callbackNode == nil { + return false + } + callbackNode = ast.SkipParentheses(callbackNode) + var params *ast.NodeList + var body *ast.Node + + switch callbackNode.Kind { + case ast.KindArrowFunction: + fn := callbackNode.AsArrowFunction() + params = fn.Parameters + body = fn.Body + case ast.KindFunctionExpression: + fn := callbackNode.AsFunctionExpression() + params = fn.Parameters + body = fn.Body + default: + return false + } + + if body == nil { + return false + } + + paramCount := 0 + if params != nil { + paramCount = len(params.Nodes) + } + + if paramCount == 0 { + return true + } + + if paramCount == 1 { + paramDecl := params.Nodes[0].AsParameterDeclaration() + if paramDecl == nil || paramDecl.Name() == nil || paramDecl.DotDotDotToken != nil { + return false + } + nameNode := paramDecl.Name() + if nameNode.Kind != ast.KindIdentifier { + return false + } + paramSymbol := tp.GetSymbolAtLocation(nameNode) + if paramSymbol == nil { + return true + } + return !sleepParamIsReferenced(tp, c, paramSymbol, body) + } + + return false +} + +// sleepParamIsReferenced checks if the given parameter symbol is referenced in the node tree. +func sleepParamIsReferenced(tp *typeparser.TypeParser, c *checker.Checker, paramSymbol *ast.Symbol, body *ast.Node) bool { + var usesParameter func(node *ast.Node) bool + usesParameter = func(node *ast.Node) bool { + if node == nil { + return false + } + if node.Kind == ast.KindShorthandPropertyAssignment && c.GetShorthandAssignmentValueSymbol(node) == paramSymbol { + return true + } + if node.Kind == ast.KindIdentifier { + sym := tp.GetSymbolAtLocation(node) + if sym != nil && (sym == paramSymbol || checker.Checker_getSymbolIfSameReference(c, sym, paramSymbol) != nil) { + return true + } + } + return node.ForEachChild(usesParameter) + } + return usesParameter(body) +} + +// sleepContinuationIsEffect checks whether all constituents of the type (unrolling unions) +// satisfy the Effect variance interface. +func sleepContinuationIsEffect(tp *typeparser.TypeParser, t *checker.Type) bool { + if tp == nil || t == nil { + return false + } + members := tp.UnrollUnionMembers(t) + if len(members) == 0 { + return false + } + for _, m := range members { + if !tp.IsEffectType(m) { + return false + } + } + return true +} diff --git a/shim/diagnostics/shim.go b/shim/diagnostics/shim.go index f93ae1fd..e9b4e666 100644 --- a/shim/diagnostics/shim.go +++ b/shim/diagnostics/shim.go @@ -1544,6 +1544,7 @@ var Searching_all_ancestor_node_modules_directories_for_preferred_extensions_Col var See_also_https_Colon_Slash_Slashaka_ms_Slashtsconfig_Slashmodule = diagnostics.See_also_https_Colon_Slash_Slashaka_ms_Slashtsconfig_Slashmodule var Selection_is_not_a_valid_statement_or_statements = diagnostics.Selection_is_not_a_valid_statement_or_statements var Selection_is_not_a_valid_type_node = diagnostics.Selection_is_not_a_valid_type_node +var Sequencing_Effect_sleep_before_an_effect_re_implements_Effect_delay_effect_sleepThenEffectToDelay = diagnostics.Sequencing_Effect_sleep_before_an_effect_re_implements_Effect_delay_effect_sleepThenEffectToDelay var Service_0_is_required_but_not_provided_by_dependencies_effect_missingEffectServiceDependency = diagnostics.Service_0_is_required_but_not_provided_by_dependencies_effect_missingEffectServiceDependency var Services_0_are_required_but_not_provided_by_dependencies_effect_missingEffectServiceDependency = diagnostics.Services_0_are_required_but_not_provided_by_dependencies_effect_missingEffectServiceDependency var Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations = diagnostics.Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.errors.txt b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.errors.txt new file mode 100644 index 00000000..995e8041 --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.errors.txt @@ -0,0 +1,26 @@ +=== Metadata === +Effect version: 3.19.19 + + + +==== /.src/sleepThenEffectToDelay.ts (0 errors) ==== + // @effect-v3 + // @effect-diagnostics *:off + // @effect-diagnostics sleepThenEffectToDelay:suggestion + import { Effect } from "effect" + + declare const sendRequest: Effect.Effect + + // Negative control: GOOD forms only + export const goodDelayPipe = sendRequest.pipe(Effect.delay("1 second")) + export const goodDelayDataFirst = Effect.delay(sendRequest, "100 millis") + + export const goodGenStandalone = Effect.gen(function* () { + yield* Effect.sleep("1 second") + return yield* sendRequest + }) + + export const goodParamUsingCallback = Effect.sleep("1 second").pipe( + Effect.flatMap((val) => Effect.succeed(val)) + ) + diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid new file mode 100644 index 00000000..3da70f8b --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid @@ -0,0 +1,41 @@ +flowchart TB + 0[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 1["type: Effect#lt;void, never, never#gt;
callee: Effect.delay
args: #91;#quot;1 second#quot;#93;"] + 2[/"type: #123; #40;duration: DurationInput#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A, E, R#gt;; #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;, duration: DurationInput#41;: Effect#lt;A, E, R#gt;; #125;
node: Effect.delay"/] + 3[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 4[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 5["type: Effect#lt;void, never, never#gt;
callee:
args: #91;#93;"] + 6[/"type: #123; #40;duration: DurationInput#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A, E, R#gt;; #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;, duration: DurationInput#41;: Effect#lt;A, E, R#gt;; #125;
node: Effect.delay"/] + 7[/"type: #quot;100 millis#quot;
node: #quot;100 millis#quot;"/] + 8((("type: Effect#lt;void, never, never#gt;
node: Effect.gen#40;function* #40;#41; #123;#92;n yield* Effect.sleep#40;#quot;1 second#quot;#41;#92;n return yield* sendRequest#92;n#125;#41;"))) + 9[/"type: void
node: yield* sendRequest"/] + 10[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 11["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 12[/"type: #40;duration: DurationInput#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 13[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 14["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 15[/"type: #40;duration: DurationInput#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 16["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;val#41; =#gt; Effect.succeed#40;val#41;#93;"] + 17[/"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"/] + 18[["type: #40;val: void#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;val#41; =#gt; Effect.succeed#40;val#41;"]] + 19[/"type: void
node: val"/] + 20["type: Effect#lt;void, never, never#gt;
callee: Effect.succeed
args: #91;#93;"] + 21[/"type: #lt;A#gt;#40;value: A#41; =#gt; Effect#lt;A, never, never#gt;
node: Effect.succeed"/] + 2 -->|"kind: transformCallee"| 1 + 3 -->|"kind: transformArg"| 1 + 0 -->|"kind: pipe"| 1 + 4 -->|"kind: pipe"| 5 + 6 -->|"kind: transformCallee"| 4 + 7 -->|"kind: transformArg"| 4 + 9 -->|"kind: potentialReturn"| 8 + 10 -->|"kind: pipe"| 11 + 12 -->|"kind: transformCallee"| 11 + 11 -->|"kind: yieldable"| 8 + 13 -->|"kind: pipe"| 14 + 15 -->|"kind: transformCallee"| 14 + 17 -->|"kind: transformCallee"| 16 + 19 -->|"kind: pipe"| 20 + 21 -->|"kind: transformCallee"| 20 + 20 -->|"kind: potentialReturn"| 18 + 18 -->|"kind: transformArg"| 16 + 14 -->|"kind: pipe"| 16 \ No newline at end of file diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.txt b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.txt new file mode 100644 index 00000000..7579d164 --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.flows.txt @@ -0,0 +1 @@ +/.src/sleepThenEffectToDelay.ts -> sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.layers.txt b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.layers.txt new file mode 100644 index 00000000..eb56d913 --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.layers.txt @@ -0,0 +1 @@ +==== /.src/sleepThenEffectToDelay.ts (0 layer exports) ==== diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.pipings.txt b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.pipings.txt new file mode 100644 index 00000000..72984f06 --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.pipings.txt @@ -0,0 +1,89 @@ +==== /.src/sleepThenEffectToDelay.ts (6 flows) ==== + +=== Piping Flow === +Location: 9:29 - 9:72 +Node: sendRequest.pipe(Effect.delay("1 second")) +Node Kind: KindCallExpression + +Subject: sendRequest +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.delay + args: ["1 second"] + outType: Effect + +=== Piping Flow === +Location: 10:34 - 10:74 +Node: Effect.delay(sendRequest, "100 millis") +Node Kind: KindCallExpression + +Subject: sendRequest +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.delay + args: ["100 millis"] + outType: Effect + +=== Piping Flow === +Location: 12:33 - 15:3 +Node: Effect.gen(function* () {\n yield* Effect.sleep("1 second")\n return yield* sendRequest\n}) +Node Kind: KindCallExpression + +Subject: function* () {\n yield* Effect.sleep("1 second")\n return yield* sendRequest\n} +Subject Type: () => Generator>, void, any> + +Transformations (1): + [0] kind: call + callee: Effect.gen + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 13:9 - 13:34 +Node: Effect.sleep("1 second") +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (1): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 17:38 - 19:2 +Node: Effect.sleep("1 second").pipe(\n Effect.flatMap((val) => Effect.succeed(val))\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [(val) => Effect.succeed(val)] + outType: Effect + +=== Piping Flow === +Location: 18:26 - 18:46 +Node: Effect.succeed(val) +Node Kind: KindCallExpression + +Subject: val +Subject Type: void + +Transformations (1): + [0] kind: call + callee: Effect.succeed + args: (constant) + outType: Effect diff --git a/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.quickfixes.txt b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.quickfixes.txt new file mode 100644 index 00000000..dad05bfc --- /dev/null +++ b/testdata/baselines/reference/effect-v3/sleepThenEffectToDelay.quickfixes.txt @@ -0,0 +1,5 @@ +=== Quick Fix Inventory === +(no diagnostics) + +=== Quick Fix Application Results === +(no quick fixes to apply) diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.errors.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.errors.txt new file mode 100644 index 00000000..dceaa540 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.errors.txt @@ -0,0 +1,138 @@ +=== Metadata === +Effect version: 4.0.0 + +/.src/sleepThenEffectToDelay.ts(10,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(15,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(20,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(25,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(31,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(37,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(44,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(48,36): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) +/.src/sleepThenEffectToDelay.ts(54,36): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + + +==== /.src/sleepThenEffectToDelay.ts (9 errors) ==== + // @effect-v4 + // @effect-diagnostics *:off + // @effect-diagnostics sleepThenEffectToDelay:suggestion + import { Effect, pipe } from "effect" + + declare const sendRequest: Effect.Effect + + // BAD: pipe form with andThen + export const badPipeAndThen = Effect.sleep("1 second").pipe( + Effect.andThen(sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe form with flatMap (0 params) + export const badPipeFlatMap = Effect.sleep("1 second").pipe( + Effect.flatMap(() => sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe form with flatMap (unused param _) + export const badPipeFlatMapUnderscore = Effect.sleep("1 second").pipe( + Effect.flatMap((_) => sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe form with flatMap (unused named param) + export const badPipeFlatMapUnusedNamed = Effect.sleep("1 second").pipe( + Effect.flatMap((_unused) => sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe helper function with andThen + export const badPipeHelperAndThen = pipe( + Effect.sleep("1 second"), + Effect.andThen(sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe helper function with flatMap + export const badPipeHelperFlatMap = pipe( + Effect.sleep("1 second"), + Effect.flatMap(() => sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: pipe with sleep transformation step (flow.Transformations[0]) + export const badPipeSleepStep = pipe( + "1 second", + Effect.sleep, + Effect.andThen(sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + + // BAD: data-first andThen + export const badDataFirstAndThen = Effect.andThen( + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Effect.sleep("1 second"), + sendRequest + ) + + // BAD: data-first flatMap + export const badDataFirstFlatMap = Effect.flatMap( + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Effect.sleep("100 millis"), + () => sendRequest + ) + + // GOOD: Effect.delay in pipe form + export const goodDelayPipe = sendRequest.pipe(Effect.delay("1 second")) + + // GOOD: Effect.delay data-first form + export const goodDelayDataFirst = Effect.delay(sendRequest, "100 millis") + + // GOOD: standalone yield* sleep in Effect.gen + export const goodGenStandalone = Effect.gen(function* () { + yield* Effect.sleep("1 second") + return yield* sendRequest + }) + + // GOOD: non-sequencer first stage (withLive) + declare const withLive: (effect: Effect.Effect) => Effect.Effect + export const goodTestClockFirstStage = Effect.sleep("1 second").pipe( + withLive, + Effect.andThen(sendRequest) + ) + + // GOOD: non-sequencer first stage (schedule) + declare const schedule: (effect: Effect.Effect) => Effect.Effect + export const goodScheduleFirstStage = Effect.sleep("1 second").pipe( + schedule, + Effect.andThen(sendRequest) + ) + + // GOOD: unrelated sleep function + declare const unrelatedSleep: (d: string) => { pipe: (f: any) => any } + export const goodUnrelatedSleep = unrelatedSleep("1 second").pipe( + Effect.andThen(sendRequest) + ) + + // GOOD: param-using callback in pipe flatMap + export const goodParamUsingCallback = Effect.sleep("1 second").pipe( + Effect.flatMap((val) => Effect.succeed(val)) + ) + + // GOOD: param-using callback in data-first flatMap + export const goodDataFirstParamUsing = Effect.flatMap( + Effect.sleep("1 second"), + (val) => Effect.succeed(val) + ) + + + // GOOD: standalone sleep without sequencer + export const goodStandaloneSleep = Effect.sleep("1 second") + diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid new file mode 100644 index 00000000..14c18593 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid @@ -0,0 +1,207 @@ +flowchart TB + 0[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 1["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 2[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 3["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 4[/"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"/] + 5[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 6[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 7["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 8[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 9["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;#41; =#gt; sendRequest#93;"] + 10[/"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"/] + 11[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;#41; =#gt; sendRequest"]] + 12[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 13[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 14["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 15[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 16["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;_#41; =#gt; sendRequest#93;"] + 17[/"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"/] + 18[["type: #40;_: void#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;_#41; =#gt; sendRequest"]] + 19[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 20[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 21["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 22[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 23["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;_unused#41; =#gt; sendRequest#93;"] + 24[/"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"/] + 25[["type: #40;_unused: void#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;_unused#41; =#gt; sendRequest"]] + 26[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 27[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 28["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 29[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 30["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 31[/"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"/] + 32[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 33[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 34["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 35[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 36["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;#41; =#gt; sendRequest#93;"] + 37[/"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"/] + 38[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;#41; =#gt; sendRequest"]] + 39[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 40[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 41["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 42["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 43[/"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"/] + 44[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 45[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 46["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 47[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 48["type: Effect#lt;void, never, never#gt;
callee:
args: #91;#93;"] + 49[/"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"/] + 50[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 51[/"type: #quot;100 millis#quot;
node: #quot;100 millis#quot;"/] + 52["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 53[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 54["type: Effect#lt;void, never, never#gt;
callee:
args: #91;#93;"] + 55[/"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"/] + 56[["type: #40;#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;#41; =#gt; sendRequest"]] + 57[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 58[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 59["type: Effect#lt;void, never, never#gt;
callee: Effect.delay
args: #91;#quot;1 second#quot;#93;"] + 60[/"type: #123; #40;duration: Input#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A, E, R#gt;; #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;, duration: Input#41;: Effect#lt;A, E, R#gt;; #125;
node: Effect.delay"/] + 61[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 62[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 63["type: Effect#lt;void, never, never#gt;
callee:
args: #91;#93;"] + 64[/"type: #123; #40;duration: Input#41;: #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;#41; =#gt; Effect#lt;A, E, R#gt;; #lt;A, E, R#gt;#40;self: Effect#lt;A, E, R#gt;, duration: Input#41;: Effect#lt;A, E, R#gt;; #125;
node: Effect.delay"/] + 65[/"type: #quot;100 millis#quot;
node: #quot;100 millis#quot;"/] + 66((("type: Effect#lt;void, never, never#gt;
node: Effect.gen#40;function* #40;#41; #123;#92;n yield* Effect.sleep#40;#quot;1 second#quot;#41;#92;n return yield* sendRequest#92;n#125;#41;"))) + 67[/"type: void
node: yield* sendRequest"/] + 68[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 69["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 70[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 71[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 72["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 73[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 74["type: Effect#lt;void, never, never#gt;
callee: withLive
args: #91;#93;"] + 75["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 76[/"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"/] + 77[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 78[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 79["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 80[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 81["type: Effect#lt;void, never, never#gt;
callee: schedule
args: #91;#93;"] + 82["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 83[/"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"/] + 84[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 85[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 86["type: #123; pipe: #40;f: any#41; =#gt; any; #125;
callee: unrelatedSleep
args: #91;#93;"] + 87[/"type: #40;d: string#41; =#gt; #123; pipe: #40;f: any#41; =#gt; any; #125;
node: unrelatedSleep"/] + 88["type:
callee: Effect.andThen
args: #91;sendRequest#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: Effect.andThen"/] + 90[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 91[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 92["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 93[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 94["type: Effect#lt;void, never, never#gt;
callee: Effect.flatMap
args: #91;#40;val#41; =#gt; Effect.succeed#40;val#41;#93;"] + 95[/"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"/] + 96[["type: #40;val: void#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;val#41; =#gt; Effect.succeed#40;val#41;"]] + 97[/"type: void
node: val"/] + 98["type: Effect#lt;void, never, never#gt;
callee: Effect.succeed
args: #91;#93;"] + 99[/"type: #lt;A#gt;#40;value: A#41; =#gt; Effect#lt;A, never, never#gt;
node: Effect.succeed"/] + 100[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 101["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 102[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 103["type: Effect#lt;void, never, never#gt;
callee:
args: #91;#93;"] + 104[/"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"/] + 105[["type: #40;val: void#41; =#gt; Effect#lt;void, never, never#gt;
node: #40;val#41; =#gt; Effect.succeed#40;val#41;"]] + 106[/"type: void
node: val"/] + 107["type: Effect#lt;void, never, never#gt;
callee: Effect.succeed
args: #91;#93;"] + 108[/"type: #lt;A#gt;#40;value: A#41; =#gt; Effect#lt;A, never, never#gt;
node: Effect.succeed"/] + 109[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 110["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 111[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 0 -->|"kind: pipe"| 1 + 2 -->|"kind: transformCallee"| 1 + 4 -->|"kind: transformCallee"| 3 + 5 -->|"kind: transformArg"| 3 + 1 -->|"kind: pipe"| 3 + 6 -->|"kind: pipe"| 7 + 8 -->|"kind: transformCallee"| 7 + 10 -->|"kind: transformCallee"| 9 + 12 -->|"kind: potentialReturn"| 11 + 11 -->|"kind: transformArg"| 9 + 7 -->|"kind: pipe"| 9 + 13 -->|"kind: pipe"| 14 + 15 -->|"kind: transformCallee"| 14 + 17 -->|"kind: transformCallee"| 16 + 19 -->|"kind: potentialReturn"| 18 + 18 -->|"kind: transformArg"| 16 + 14 -->|"kind: pipe"| 16 + 20 -->|"kind: pipe"| 21 + 22 -->|"kind: transformCallee"| 21 + 24 -->|"kind: transformCallee"| 23 + 26 -->|"kind: potentialReturn"| 25 + 25 -->|"kind: transformArg"| 23 + 21 -->|"kind: pipe"| 23 + 27 -->|"kind: pipe"| 28 + 29 -->|"kind: transformCallee"| 28 + 31 -->|"kind: transformCallee"| 30 + 32 -->|"kind: transformArg"| 30 + 28 -->|"kind: pipe"| 30 + 33 -->|"kind: pipe"| 34 + 35 -->|"kind: transformCallee"| 34 + 37 -->|"kind: transformCallee"| 36 + 39 -->|"kind: potentialReturn"| 38 + 38 -->|"kind: transformArg"| 36 + 34 -->|"kind: pipe"| 36 + 40 -->|"kind: pipe"| 41 + 43 -->|"kind: transformCallee"| 42 + 44 -->|"kind: transformArg"| 42 + 41 -->|"kind: pipe"| 42 + 45 -->|"kind: pipe"| 46 + 47 -->|"kind: transformCallee"| 46 + 46 -->|"kind: pipe"| 48 + 49 -->|"kind: transformCallee"| 45 + 50 -->|"kind: transformArg"| 45 + 51 -->|"kind: pipe"| 52 + 53 -->|"kind: transformCallee"| 52 + 52 -->|"kind: pipe"| 54 + 55 -->|"kind: transformCallee"| 51 + 57 -->|"kind: potentialReturn"| 56 + 56 -->|"kind: transformArg"| 51 + 60 -->|"kind: transformCallee"| 59 + 61 -->|"kind: transformArg"| 59 + 58 -->|"kind: pipe"| 59 + 62 -->|"kind: pipe"| 63 + 64 -->|"kind: transformCallee"| 62 + 65 -->|"kind: transformArg"| 62 + 67 -->|"kind: potentialReturn"| 66 + 68 -->|"kind: pipe"| 69 + 70 -->|"kind: transformCallee"| 69 + 69 -->|"kind: yieldable"| 66 + 71 -->|"kind: pipe"| 72 + 73 -->|"kind: transformCallee"| 72 + 72 -->|"kind: pipe"| 74 + 76 -->|"kind: transformCallee"| 75 + 77 -->|"kind: transformArg"| 75 + 74 -->|"kind: pipe"| 75 + 78 -->|"kind: pipe"| 79 + 80 -->|"kind: transformCallee"| 79 + 79 -->|"kind: pipe"| 81 + 83 -->|"kind: transformCallee"| 82 + 84 -->|"kind: transformArg"| 82 + 81 -->|"kind: pipe"| 82 + 85 -->|"kind: pipe"| 86 + 87 -->|"kind: transformCallee"| 86 + 89 -->|"kind: transformCallee"| 88 + 90 -->|"kind: transformArg"| 88 + 86 -->|"kind: pipe"| 88 + 91 -->|"kind: pipe"| 92 + 93 -->|"kind: transformCallee"| 92 + 95 -->|"kind: transformCallee"| 94 + 97 -->|"kind: pipe"| 98 + 99 -->|"kind: transformCallee"| 98 + 98 -->|"kind: potentialReturn"| 96 + 96 -->|"kind: transformArg"| 94 + 92 -->|"kind: pipe"| 94 + 100 -->|"kind: pipe"| 101 + 102 -->|"kind: transformCallee"| 101 + 101 -->|"kind: pipe"| 103 + 104 -->|"kind: transformCallee"| 100 + 106 -->|"kind: pipe"| 107 + 108 -->|"kind: transformCallee"| 107 + 107 -->|"kind: potentialReturn"| 105 + 105 -->|"kind: transformArg"| 100 + 109 -->|"kind: pipe"| 110 + 111 -->|"kind: transformCallee"| 110 \ No newline at end of file diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.txt new file mode 100644 index 00000000..7579d164 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.flows.txt @@ -0,0 +1 @@ +/.src/sleepThenEffectToDelay.ts -> sleepThenEffectToDelay.flows.sleepThenEffectToDelay.mermaid diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.layers.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.layers.txt new file mode 100644 index 00000000..eb56d913 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.layers.txt @@ -0,0 +1 @@ +==== /.src/sleepThenEffectToDelay.ts (0 layer exports) ==== diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.pipings.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.pipings.txt new file mode 100644 index 00000000..0d3acd8a --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.pipings.txt @@ -0,0 +1,359 @@ +==== /.src/sleepThenEffectToDelay.ts (21 flows) ==== + +=== Piping Flow === +Location: 9:30 - 11:2 +Node: Effect.sleep("1 second").pipe(\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 14:30 - 16:2 +Node: Effect.sleep("1 second").pipe(\n Effect.flatMap(() => sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [() => sendRequest] + outType: Effect + +=== Piping Flow === +Location: 19:40 - 21:2 +Node: Effect.sleep("1 second").pipe(\n Effect.flatMap((_) => sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [(_) => sendRequest] + outType: Effect + +=== Piping Flow === +Location: 24:41 - 26:2 +Node: Effect.sleep("1 second").pipe(\n Effect.flatMap((_unused) => sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [(_unused) => sendRequest] + outType: Effect + +=== Piping Flow === +Location: 29:36 - 32:2 +Node: pipe(\n Effect.sleep("1 second"),\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipe + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 35:36 - 38:2 +Node: pipe(\n Effect.sleep("1 second"),\n Effect.flatMap(() => sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipe + callee: Effect.flatMap + args: [() => sendRequest] + outType: Effect + +=== Piping Flow === +Location: 41:32 - 45:2 +Node: pipe(\n "1 second",\n Effect.sleep,\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: pipe + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipe + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 48:35 - 51:2 +Node: Effect.andThen(\n Effect.sleep("1 second"),\n sendRequest\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: dataFirst + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 54:35 - 57:2 +Node: Effect.flatMap(\n Effect.sleep("100 millis"),\n () => sendRequest\n) +Node Kind: KindCallExpression + +Subject: "100 millis" +Subject Type: "100 millis" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: dataFirst + callee: Effect.flatMap + args: [() => sendRequest] + outType: Effect + +=== Piping Flow === +Location: 60:29 - 60:72 +Node: sendRequest.pipe(Effect.delay("1 second")) +Node Kind: KindCallExpression + +Subject: sendRequest +Subject Type: Effect + +Transformations (1): + [0] kind: pipeable + callee: Effect.delay + args: ["1 second"] + outType: Effect + +=== Piping Flow === +Location: 63:34 - 63:74 +Node: Effect.delay(sendRequest, "100 millis") +Node Kind: KindCallExpression + +Subject: sendRequest +Subject Type: Effect + +Transformations (1): + [0] kind: dataFirst + callee: Effect.delay + args: ["100 millis"] + outType: Effect + +=== Piping Flow === +Location: 66:33 - 69:3 +Node: Effect.gen(function* () {\n yield* Effect.sleep("1 second")\n return yield* sendRequest\n}) +Node Kind: KindCallExpression + +Subject: function* () {\n yield* Effect.sleep("1 second")\n return yield* sendRequest\n} +Subject Type: () => Generator, void, any> + +Transformations (1): + [0] kind: call + callee: Effect.gen + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 67:9 - 67:34 +Node: Effect.sleep("1 second") +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (1): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 73:39 - 76:2 +Node: Effect.sleep("1 second").pipe(\n withLive,\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (3): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: withLive + args: (constant) + outType: Effect + [2] kind: pipeable + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 80:38 - 83:2 +Node: Effect.sleep("1 second").pipe(\n schedule,\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (3): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: schedule + args: (constant) + outType: Effect + [2] kind: pipeable + callee: Effect.andThen + args: [sendRequest] + outType: Effect + +=== Piping Flow === +Location: 87:34 - 89:2 +Node: unrelatedSleep("1 second").pipe(\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: unrelatedSleep + args: (constant) + outType: { pipe: (f: any) => any; } + [1] kind: pipeable + callee: Effect.andThen + args: [sendRequest] + outType: + +=== Piping Flow === +Location: 92:38 - 94:2 +Node: Effect.sleep("1 second").pipe(\n Effect.flatMap((val) => Effect.succeed(val))\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.flatMap + args: [(val) => Effect.succeed(val)] + outType: Effect + +=== Piping Flow === +Location: 93:26 - 93:46 +Node: Effect.succeed(val) +Node Kind: KindCallExpression + +Subject: val +Subject Type: void + +Transformations (1): + [0] kind: call + callee: Effect.succeed + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 97:39 - 100:2 +Node: Effect.flatMap(\n Effect.sleep("1 second"),\n (val) => Effect.succeed(val)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: dataFirst + callee: Effect.flatMap + args: [(val) => Effect.succeed(val)] + outType: Effect + +=== Piping Flow === +Location: 99:11 - 99:31 +Node: Effect.succeed(val) +Node Kind: KindCallExpression + +Subject: val +Subject Type: void + +Transformations (1): + [0] kind: call + callee: Effect.succeed + args: (constant) + outType: Effect + +=== Piping Flow === +Location: 104:35 - 104:60 +Node: Effect.sleep("1 second") +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (1): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.quickfixes.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.quickfixes.txt new file mode 100644 index 00000000..436f57af --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay.quickfixes.txt @@ -0,0 +1,93 @@ +=== Quick Fix Inventory === + +[D1] (10:3-10:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D2] (15:3-15:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D3] (20:3-20:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D4] (25:3-25:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D5] (31:3-31:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D6] (37:3-37:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D7] (44:3-44:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D8] (48:36-48:50) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +[D9] (54:36-54:50) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +=== Quick Fix Application Results === + +=== [D1] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D1] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D2] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D2] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D3] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D3] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D4] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D4] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D5] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D5] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D6] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D6] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D7] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D7] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D8] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D8] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default + +=== [D9] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D9] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.errors.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.errors.txt new file mode 100644 index 00000000..eb03ab3d --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.errors.txt @@ -0,0 +1,20 @@ +=== Metadata === +Effect version: 4.0.0 + +/.src/sleepThenEffectToDelay_preview.ts(9,3): suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + + +==== /.src/sleepThenEffectToDelay_preview.ts (1 errors) ==== + // @effect-v4 + // @effect-diagnostics *:off + // @effect-diagnostics sleepThenEffectToDelay:suggestion + import { Effect } from "effect" + + declare const sendRequest: Effect.Effect + + export const throttled = Effect.sleep("1 second").pipe( + Effect.andThen(sendRequest) + ~~~~~~~~~~~~~~ +!!! suggestion TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + ) + diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.sleepThenEffectToDelay_preview.mermaid b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.sleepThenEffectToDelay_preview.mermaid new file mode 100644 index 00000000..a54d7276 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.sleepThenEffectToDelay_preview.mermaid @@ -0,0 +1,12 @@ +flowchart TB + 0[/"type: #quot;1 second#quot;
node: #quot;1 second#quot;"/] + 1["type: Effect#lt;void, never, never#gt;
callee: Effect.sleep
args: #91;#93;"] + 2[/"type: #40;duration: Input#41; =#gt; Effect#lt;void, never, never#gt;
node: Effect.sleep"/] + 3["type: Effect#lt;void, never, never#gt;
callee: Effect.andThen
args: #91;sendRequest#93;"] + 4[/"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"/] + 5[/"type: Effect#lt;void, never, never#gt;
node: sendRequest"/] + 0 -->|"kind: pipe"| 1 + 2 -->|"kind: transformCallee"| 1 + 4 -->|"kind: transformCallee"| 3 + 5 -->|"kind: transformArg"| 3 + 1 -->|"kind: pipe"| 3 \ No newline at end of file diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.txt new file mode 100644 index 00000000..2779189f --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.flows.txt @@ -0,0 +1 @@ +/.src/sleepThenEffectToDelay_preview.ts -> sleepThenEffectToDelay_preview.flows.sleepThenEffectToDelay_preview.mermaid diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.layers.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.layers.txt new file mode 100644 index 00000000..68080cf0 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.layers.txt @@ -0,0 +1 @@ +==== /.src/sleepThenEffectToDelay_preview.ts (0 layer exports) ==== diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.pipings.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.pipings.txt new file mode 100644 index 00000000..430f5740 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.pipings.txt @@ -0,0 +1,19 @@ +==== /.src/sleepThenEffectToDelay_preview.ts (1 flows) ==== + +=== Piping Flow === +Location: 8:25 - 10:2 +Node: Effect.sleep("1 second").pipe(\n Effect.andThen(sendRequest)\n) +Node Kind: KindCallExpression + +Subject: "1 second" +Subject Type: "1 second" + +Transformations (2): + [0] kind: call + callee: Effect.sleep + args: (constant) + outType: Effect + [1] kind: pipeable + callee: Effect.andThen + args: [sendRequest] + outType: Effect diff --git a/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.quickfixes.txt b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.quickfixes.txt new file mode 100644 index 00000000..8f821763 --- /dev/null +++ b/testdata/baselines/reference/effect-v4/sleepThenEffectToDelay_preview.quickfixes.txt @@ -0,0 +1,13 @@ +=== Quick Fix Inventory === + +[D1] (9:3-9:17) TS377133: Sequencing Effect.sleep before an effect re-implements Effect.delay. effect(sleepThenEffectToDelay) + Fix 0: "Disable sleepThenEffectToDelay for this line" + Fix 1: "Disable sleepThenEffectToDelay for entire file" + +=== Quick Fix Application Results === + +=== [D1] Fix 0: "Disable sleepThenEffectToDelay for this line" === +skipped by default + +=== [D1] Fix 1: "Disable sleepThenEffectToDelay for entire file" === +skipped by default diff --git a/testdata/tests/effect-v3/sleepThenEffectToDelay.ts b/testdata/tests/effect-v3/sleepThenEffectToDelay.ts new file mode 100644 index 00000000..d2094264 --- /dev/null +++ b/testdata/tests/effect-v3/sleepThenEffectToDelay.ts @@ -0,0 +1,19 @@ +// @effect-v3 +// @effect-diagnostics *:off +// @effect-diagnostics sleepThenEffectToDelay:suggestion +import { Effect } from "effect" + +declare const sendRequest: Effect.Effect + +// Negative control: GOOD forms only +export const goodDelayPipe = sendRequest.pipe(Effect.delay("1 second")) +export const goodDelayDataFirst = Effect.delay(sendRequest, "100 millis") + +export const goodGenStandalone = Effect.gen(function* () { + yield* Effect.sleep("1 second") + return yield* sendRequest +}) + +export const goodParamUsingCallback = Effect.sleep("1 second").pipe( + Effect.flatMap((val) => Effect.succeed(val)) +) diff --git a/testdata/tests/effect-v4/sleepThenEffectToDelay.ts b/testdata/tests/effect-v4/sleepThenEffectToDelay.ts new file mode 100644 index 00000000..0ea7139d --- /dev/null +++ b/testdata/tests/effect-v4/sleepThenEffectToDelay.ts @@ -0,0 +1,104 @@ +// @effect-v4 +// @effect-diagnostics *:off +// @effect-diagnostics sleepThenEffectToDelay:suggestion +import { Effect, pipe } from "effect" + +declare const sendRequest: Effect.Effect + +// BAD: pipe form with andThen +export const badPipeAndThen = Effect.sleep("1 second").pipe( + Effect.andThen(sendRequest) +) + +// BAD: pipe form with flatMap (0 params) +export const badPipeFlatMap = Effect.sleep("1 second").pipe( + Effect.flatMap(() => sendRequest) +) + +// BAD: pipe form with flatMap (unused param _) +export const badPipeFlatMapUnderscore = Effect.sleep("1 second").pipe( + Effect.flatMap((_) => sendRequest) +) + +// BAD: pipe form with flatMap (unused named param) +export const badPipeFlatMapUnusedNamed = Effect.sleep("1 second").pipe( + Effect.flatMap((_unused) => sendRequest) +) + +// BAD: pipe helper function with andThen +export const badPipeHelperAndThen = pipe( + Effect.sleep("1 second"), + Effect.andThen(sendRequest) +) + +// BAD: pipe helper function with flatMap +export const badPipeHelperFlatMap = pipe( + Effect.sleep("1 second"), + Effect.flatMap(() => sendRequest) +) + +// BAD: pipe with sleep transformation step (flow.Transformations[0]) +export const badPipeSleepStep = pipe( + "1 second", + Effect.sleep, + Effect.andThen(sendRequest) +) + +// BAD: data-first andThen +export const badDataFirstAndThen = Effect.andThen( + Effect.sleep("1 second"), + sendRequest +) + +// BAD: data-first flatMap +export const badDataFirstFlatMap = Effect.flatMap( + Effect.sleep("100 millis"), + () => sendRequest +) + +// GOOD: Effect.delay in pipe form +export const goodDelayPipe = sendRequest.pipe(Effect.delay("1 second")) + +// GOOD: Effect.delay data-first form +export const goodDelayDataFirst = Effect.delay(sendRequest, "100 millis") + +// GOOD: standalone yield* sleep in Effect.gen +export const goodGenStandalone = Effect.gen(function* () { + yield* Effect.sleep("1 second") + return yield* sendRequest +}) + +// GOOD: non-sequencer first stage (withLive) +declare const withLive: (effect: Effect.Effect) => Effect.Effect +export const goodTestClockFirstStage = Effect.sleep("1 second").pipe( + withLive, + Effect.andThen(sendRequest) +) + +// GOOD: non-sequencer first stage (schedule) +declare const schedule: (effect: Effect.Effect) => Effect.Effect +export const goodScheduleFirstStage = Effect.sleep("1 second").pipe( + schedule, + Effect.andThen(sendRequest) +) + +// GOOD: unrelated sleep function +declare const unrelatedSleep: (d: string) => { pipe: (f: any) => any } +export const goodUnrelatedSleep = unrelatedSleep("1 second").pipe( + Effect.andThen(sendRequest) +) + +// GOOD: param-using callback in pipe flatMap +export const goodParamUsingCallback = Effect.sleep("1 second").pipe( + Effect.flatMap((val) => Effect.succeed(val)) +) + +// GOOD: param-using callback in data-first flatMap +export const goodDataFirstParamUsing = Effect.flatMap( + Effect.sleep("1 second"), + (val) => Effect.succeed(val) +) + + +// GOOD: standalone sleep without sequencer +export const goodStandaloneSleep = Effect.sleep("1 second") diff --git a/testdata/tests/effect-v4/sleepThenEffectToDelay_preview.ts b/testdata/tests/effect-v4/sleepThenEffectToDelay_preview.ts new file mode 100644 index 00000000..d0de7af8 --- /dev/null +++ b/testdata/tests/effect-v4/sleepThenEffectToDelay_preview.ts @@ -0,0 +1,10 @@ +// @effect-v4 +// @effect-diagnostics *:off +// @effect-diagnostics sleepThenEffectToDelay:suggestion +import { Effect } from "effect" + +declare const sendRequest: Effect.Effect + +export const throttled = Effect.sleep("1 second").pipe( + Effect.andThen(sendRequest) +)