@effect/language-service 0.21.4 → 0.21.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1766,33 +1766,6 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
1766
1766
  const execute = fn("LSP.ruleExecutor")(function* (rule) {
1767
1767
  const ruleNameLowered = rule.name.toLowerCase();
1768
1768
  if (skippedRules.indexOf(ruleNameLowered) > -1) return [];
1769
- let modifiedDiagnostics = yield* rule.apply(sourceFile);
1770
- const newLevel = pluginOptions.diagnosticSeverity[ruleNameLowered];
1771
- if (newLevel) {
1772
- for (const emitted of modifiedDiagnostics) {
1773
- emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : emitted.category;
1774
- }
1775
- }
1776
- for (const emitted of modifiedDiagnostics.slice(0)) {
1777
- let newLevel2 = void 0;
1778
- if (!(ruleNameLowered in sectionOverrides || ruleNameLowered in lineOverrides)) continue;
1779
- const lineOverride = (lineOverrides[ruleNameLowered] || []).find(
1780
- (_) => _.pos < emitted.node.getStart(sourceFile) && _.end >= emitted.node.getEnd()
1781
- );
1782
- if (lineOverride) {
1783
- newLevel2 = lineOverride.level;
1784
- } else {
1785
- const sectionOverride = (sectionOverrides[ruleNameLowered] || []).find(
1786
- (_) => _.pos < emitted.node.getStart(sourceFile)
1787
- );
1788
- if (sectionOverride) newLevel2 = sectionOverride.level;
1789
- }
1790
- if (newLevel2 === "off") {
1791
- modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
1792
- } else {
1793
- emitted.category = newLevel2 && newLevel2 in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel2] : emitted.category;
1794
- }
1795
- }
1796
1769
  const fixByDisableNextLine = (_) => ({
1797
1770
  fixName: rule.name + "_skipNextLine",
1798
1771
  description: "Disable " + rule.name + " for this line",
@@ -1825,11 +1798,34 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
1825
1798
  )
1826
1799
  )
1827
1800
  };
1828
- const rulesWithDisableFix = modifiedDiagnostics.map((diagnostic) => ({
1829
- ...diagnostic,
1830
- fixes: diagnostic.fixes.concat([fixByDisableNextLine(diagnostic), fixByDisableEntireFile])
1831
- }));
1832
- return rulesWithDisableFix;
1801
+ let modifiedDiagnostics = [];
1802
+ yield* rule.apply(sourceFile, (entry) => {
1803
+ modifiedDiagnostics.push({
1804
+ ...entry,
1805
+ fixes: entry.fixes.concat([fixByDisableNextLine(entry), fixByDisableEntireFile])
1806
+ });
1807
+ });
1808
+ if (!(ruleNameLowered in pluginOptions.diagnosticSeverity || ruleNameLowered in sectionOverrides || ruleNameLowered in lineOverrides)) return modifiedDiagnostics;
1809
+ for (const emitted of modifiedDiagnostics.slice(0)) {
1810
+ let newLevel = pluginOptions.diagnosticSeverity[ruleNameLowered];
1811
+ const lineOverride = (lineOverrides[ruleNameLowered] || []).find(
1812
+ (_) => _.pos < emitted.node.getStart(sourceFile) && _.end >= emitted.node.getEnd()
1813
+ );
1814
+ if (lineOverride) {
1815
+ newLevel = lineOverride.level;
1816
+ } else {
1817
+ const sectionOverride = (sectionOverrides[ruleNameLowered] || []).find(
1818
+ (_) => _.pos < emitted.node.getStart(sourceFile)
1819
+ );
1820
+ if (sectionOverride) newLevel = sectionOverride.level;
1821
+ }
1822
+ if (newLevel === "off") {
1823
+ modifiedDiagnostics = modifiedDiagnostics.filter((_) => _ !== emitted);
1824
+ } else {
1825
+ emitted.category = newLevel && newLevel in levelToDiagnosticCategory ? levelToDiagnosticCategory[newLevel] : emitted.category;
1826
+ }
1827
+ }
1828
+ return modifiedDiagnostics;
1833
1829
  });
1834
1830
  return { execute };
1835
1831
  }
@@ -2100,6 +2096,16 @@ function make4(ts, typeChecker) {
2100
2096
  "TypeParser.effectType",
2101
2097
  (type) => type
2102
2098
  );
2099
+ const strictEffectType = cachedBy(
2100
+ fn("TypeParser.strictEffectType")(function* (type, atLocation) {
2101
+ if (!(type.symbol && type.symbol.name === "Effect" && !type.aliasSymbol)) {
2102
+ return yield* typeParserIssue("Type name should be Effect with no alias symbol", type, atLocation);
2103
+ }
2104
+ return yield* effectType(type, atLocation);
2105
+ }),
2106
+ "TypeParser.strictEffectType",
2107
+ (type) => type
2108
+ );
2103
2109
  const layerType = cachedBy(
2104
2110
  fn("TypeParser.layerType")(function* (type, atLocation) {
2105
2111
  yield* pipeableType(type, atLocation);
@@ -2451,6 +2457,7 @@ function make4(ts, typeChecker) {
2451
2457
  );
2452
2458
  return {
2453
2459
  effectType,
2460
+ strictEffectType,
2454
2461
  layerType,
2455
2462
  fiberType,
2456
2463
  effectSubtype,
@@ -2537,6 +2544,7 @@ var getMissingTypeEntriesInTargetType = fn(
2537
2544
  "TypeCheckerApi.getMissingTypeEntriesInTargetType"
2538
2545
  )(
2539
2546
  function* (realType, expectedType) {
2547
+ if (realType === expectedType) return [];
2540
2548
  const typeChecker = yield* service(TypeCheckerApi);
2541
2549
  const result = [];
2542
2550
  let toTest = [realType];
@@ -2846,12 +2854,11 @@ var programResolvedCacheSize = /* @__PURE__ */ new Map();
2846
2854
  var duplicatePackage = createDiagnostic({
2847
2855
  name: "duplicatePackage",
2848
2856
  code: 6,
2849
- apply: fn("duplicatePackage.apply")(function* (sourceFile) {
2857
+ apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
2850
2858
  const ts = yield* service(TypeScriptApi);
2851
2859
  const program = yield* service(TypeScriptProgram);
2852
2860
  const options = yield* service(LanguageServicePluginOptions);
2853
- const effectDiagnostics = [];
2854
- if (sourceFile.statements.length < 1) return [];
2861
+ if (sourceFile.statements.length < 1) return;
2855
2862
  let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
2856
2863
  const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
2857
2864
  const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
@@ -2875,7 +2882,7 @@ var duplicatePackage = createDiagnostic({
2875
2882
  for (const packageName of Object.keys(resolvedPackages)) {
2876
2883
  if (Object.keys(resolvedPackages[packageName]).length > 1) {
2877
2884
  const versions = Object.keys(resolvedPackages[packageName]);
2878
- effectDiagnostics.push({
2885
+ report({
2879
2886
  node: sourceFile.statements[0],
2880
2887
  category: ts.DiagnosticCategory.Warning,
2881
2888
  messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
@@ -2887,7 +2894,6 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
2887
2894
  });
2888
2895
  }
2889
2896
  }
2890
- return effectDiagnostics;
2891
2897
  })
2892
2898
  });
2893
2899
 
@@ -2895,7 +2901,7 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
2895
2901
  var floatingEffect = createDiagnostic({
2896
2902
  name: "floatingEffect",
2897
2903
  code: 3,
2898
- apply: fn("floatingEffect.apply")(function* (sourceFile) {
2904
+ apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
2899
2905
  const ts = yield* service(TypeScriptApi);
2900
2906
  const typeChecker = yield* service(TypeCheckerApi);
2901
2907
  const typeParser = yield* service(TypeParser);
@@ -2906,7 +2912,6 @@ var floatingEffect = createDiagnostic({
2906
2912
  if (ts.isBinaryExpression(expression) && expression.operatorToken && (expression.operatorToken.kind === ts.SyntaxKind.EqualsToken || expression.operatorToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken || expression.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken || expression.operatorToken.kind === ts.SyntaxKind.BarBarEqualsToken)) return false;
2907
2913
  return true;
2908
2914
  }
2909
- const effectDiagnostics = [];
2910
2915
  const nodeToVisit = [];
2911
2916
  const appendNodeToVisit = (node) => {
2912
2917
  nodeToVisit.push(node);
@@ -2926,7 +2931,7 @@ var floatingEffect = createDiagnostic({
2926
2931
  option
2927
2932
  );
2928
2933
  if (isNone2(allowedFloatingEffects)) {
2929
- effectDiagnostics.push({
2934
+ report({
2930
2935
  node,
2931
2936
  category: ts.DiagnosticCategory.Error,
2932
2937
  messageText: `Effect must be yielded or assigned to a variable.`,
@@ -2935,7 +2940,6 @@ var floatingEffect = createDiagnostic({
2935
2940
  }
2936
2941
  }
2937
2942
  }
2938
- return effectDiagnostics;
2939
2943
  })
2940
2944
  });
2941
2945
 
@@ -2943,11 +2947,10 @@ var floatingEffect = createDiagnostic({
2943
2947
  var genericEffectServices = createDiagnostic({
2944
2948
  name: "genericEffectServices",
2945
2949
  code: 10,
2946
- apply: fn("genericEffectServices.apply")(function* (sourceFile) {
2950
+ apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
2947
2951
  const ts = yield* service(TypeScriptApi);
2948
2952
  const typeParser = yield* service(TypeParser);
2949
2953
  const typeChecker = yield* service(TypeCheckerApi);
2950
- const effectDiagnostics = [];
2951
2954
  const nodeToVisit = [];
2952
2955
  const appendNodeToVisit = (node) => {
2953
2956
  nodeToVisit.push(node);
@@ -2971,7 +2974,7 @@ var genericEffectServices = createDiagnostic({
2971
2974
  yield* pipe(
2972
2975
  typeParser.contextTag(type, node),
2973
2976
  map4(() => {
2974
- effectDiagnostics.push({
2977
+ report({
2975
2978
  node: reportAt,
2976
2979
  category: ts.DiagnosticCategory.Warning,
2977
2980
  messageText: `Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior.`,
@@ -2983,7 +2986,6 @@ var genericEffectServices = createDiagnostic({
2983
2986
  );
2984
2987
  }
2985
2988
  }
2986
- return effectDiagnostics;
2987
2989
  })
2988
2990
  });
2989
2991
 
@@ -2991,12 +2993,11 @@ var genericEffectServices = createDiagnostic({
2991
2993
  var leakingRequirements = createDiagnostic({
2992
2994
  name: "leakingRequirements",
2993
2995
  code: 8,
2994
- apply: fn("leakingRequirements.apply")(function* (sourceFile) {
2996
+ apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
2995
2997
  const ts = yield* service(TypeScriptApi);
2996
2998
  const typeChecker = yield* service(TypeCheckerApi);
2997
2999
  const typeParser = yield* service(TypeParser);
2998
3000
  const typeOrder = yield* deterministicTypeOrder;
2999
- const effectDiagnostics = [];
3000
3001
  const parseLeakedRequirements = cachedBy(
3001
3002
  fn("leakingServices.checkServiceLeaking")(
3002
3003
  function* (service2, atLocation) {
@@ -3047,7 +3048,7 @@ var leakingRequirements = createDiagnostic({
3047
3048
  );
3048
3049
  function reportLeakingRequirements(node, requirements) {
3049
3050
  if (requirements.length === 0) return;
3050
- effectDiagnostics.push({
3051
+ report({
3051
3052
  node,
3052
3053
  category: ts.DiagnosticCategory.Warning,
3053
3054
  messageText: `This Service is leaking the ${requirements.map((_) => typeChecker.typeToString(_)).join(" | ")} requirement`,
@@ -3089,7 +3090,6 @@ var leakingRequirements = createDiagnostic({
3089
3090
  );
3090
3091
  }
3091
3092
  }
3092
- return effectDiagnostics;
3093
3093
  })
3094
3094
  });
3095
3095
 
@@ -3097,28 +3097,23 @@ var leakingRequirements = createDiagnostic({
3097
3097
  var missingEffectContext = createDiagnostic({
3098
3098
  name: "missingEffectContext",
3099
3099
  code: 1,
3100
- apply: fn("missingEffectContext.apply")(function* (sourceFile) {
3100
+ apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
3101
3101
  const ts = yield* service(TypeScriptApi);
3102
3102
  const typeChecker = yield* service(TypeCheckerApi);
3103
3103
  const typeParser = yield* service(TypeParser);
3104
3104
  const typeOrder = yield* deterministicTypeOrder;
3105
- const checkForMissingContextTypes = fn(
3106
- "missingEffectContext.apply.checkForMissingContextTypes"
3107
- )(function* (node, expectedType, valueNode, realType) {
3108
- const expectedEffect = yield* typeParser.effectType(
3109
- expectedType,
3110
- node
3111
- );
3112
- const realEffect = yield* typeParser.effectType(
3113
- realType,
3114
- valueNode
3115
- );
3116
- return yield* getMissingTypeEntriesInTargetType(
3117
- realEffect.R,
3118
- expectedEffect.R
3119
- );
3120
- });
3121
- const effectDiagnostics = [];
3105
+ const checkForMissingContextTypes = (node, expectedType, valueNode, realType) => pipe(
3106
+ all2(
3107
+ typeParser.effectType(expectedType, node),
3108
+ typeParser.effectType(realType, valueNode)
3109
+ ),
3110
+ flatMap3(
3111
+ ([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
3112
+ realEffect.R,
3113
+ expectedEffect.R
3114
+ )
3115
+ )
3116
+ );
3122
3117
  const sortTypes = sort(typeOrder);
3123
3118
  const entries = yield* expectedAndRealType(sourceFile);
3124
3119
  for (const [node, expectedType, valueNode, realType] of entries) {
@@ -3132,7 +3127,7 @@ var missingEffectContext = createDiagnostic({
3132
3127
  orElse3(() => succeed([]))
3133
3128
  );
3134
3129
  if (missingContext.length > 0) {
3135
- effectDiagnostics.push(
3130
+ report(
3136
3131
  {
3137
3132
  node,
3138
3133
  category: ts.DiagnosticCategory.Error,
@@ -3142,7 +3137,6 @@ var missingEffectContext = createDiagnostic({
3142
3137
  );
3143
3138
  }
3144
3139
  }
3145
- return effectDiagnostics;
3146
3140
  })
3147
3141
  });
3148
3142
 
@@ -3150,28 +3144,23 @@ var missingEffectContext = createDiagnostic({
3150
3144
  var missingEffectError = createDiagnostic({
3151
3145
  name: "missingEffectError",
3152
3146
  code: 1,
3153
- apply: fn("missingEffectError.apply")(function* (sourceFile) {
3147
+ apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
3154
3148
  const ts = yield* service(TypeScriptApi);
3155
3149
  const typeChecker = yield* service(TypeCheckerApi);
3156
3150
  const typeParser = yield* service(TypeParser);
3157
3151
  const typeOrder = yield* deterministicTypeOrder;
3158
- const checkForMissingErrorTypes = fn("missingEffectError.apply.checkForMissingErrorTypes")(
3159
- function* (node, expectedType, valueNode, realType) {
3160
- const expectedEffect = yield* typeParser.effectType(
3161
- expectedType,
3162
- node
3163
- );
3164
- const realEffect = yield* typeParser.effectType(
3165
- realType,
3166
- valueNode
3167
- );
3168
- return yield* getMissingTypeEntriesInTargetType(
3152
+ const checkForMissingErrorTypes = (node, expectedType, valueNode, realType) => pipe(
3153
+ all2(
3154
+ typeParser.effectType(expectedType, node),
3155
+ typeParser.effectType(realType, valueNode)
3156
+ ),
3157
+ flatMap3(
3158
+ ([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
3169
3159
  realEffect.E,
3170
3160
  expectedEffect.E
3171
- );
3172
- }
3161
+ )
3162
+ )
3173
3163
  );
3174
- const effectDiagnostics = [];
3175
3164
  const sortTypes = sort(typeOrder);
3176
3165
  const entries = yield* expectedAndRealType(sourceFile);
3177
3166
  for (const [node, expectedType, valueNode, realType] of entries) {
@@ -3185,7 +3174,7 @@ var missingEffectError = createDiagnostic({
3185
3174
  orElse3(() => succeed([]))
3186
3175
  );
3187
3176
  if (missingContext.length > 0) {
3188
- effectDiagnostics.push(
3177
+ report(
3189
3178
  {
3190
3179
  node,
3191
3180
  category: ts.DiagnosticCategory.Error,
@@ -3195,7 +3184,6 @@ var missingEffectError = createDiagnostic({
3195
3184
  );
3196
3185
  }
3197
3186
  }
3198
- return effectDiagnostics;
3199
3187
  })
3200
3188
  });
3201
3189
 
@@ -3203,12 +3191,10 @@ var missingEffectError = createDiagnostic({
3203
3191
  var missingReturnYieldStar = createDiagnostic({
3204
3192
  name: "missingReturnYieldStar",
3205
3193
  code: 7,
3206
- apply: fn("missingReturnYieldStar.apply")(function* (sourceFile) {
3194
+ apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
3207
3195
  const ts = yield* service(TypeScriptApi);
3208
3196
  const typeChecker = yield* service(TypeCheckerApi);
3209
3197
  const typeParser = yield* service(TypeParser);
3210
- const effectDiagnostics = [];
3211
- const brokenYields = /* @__PURE__ */ new Set();
3212
3198
  const nodeToVisit = [];
3213
3199
  const appendNodeToVisit = (node) => {
3214
3200
  nodeToVisit.push(node);
@@ -3236,36 +3222,32 @@ var missingReturnYieldStar = createDiagnostic({
3236
3222
  option
3237
3223
  );
3238
3224
  if (isSome2(effectGenLike)) {
3239
- brokenYields.add(node);
3225
+ const fix = node.expression ? [{
3226
+ fixName: "missingReturnYieldStar_fix",
3227
+ description: "Add return statement",
3228
+ apply: gen2(function* () {
3229
+ const changeTracker = yield* service(ChangeTracker);
3230
+ changeTracker.replaceNode(
3231
+ sourceFile,
3232
+ node,
3233
+ ts.factory.createReturnStatement(
3234
+ node
3235
+ )
3236
+ );
3237
+ })
3238
+ }] : [];
3239
+ report({
3240
+ node,
3241
+ category: ts.DiagnosticCategory.Error,
3242
+ messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
3243
+ fixes: fix
3244
+ });
3240
3245
  }
3241
3246
  }
3242
3247
  }
3243
3248
  }
3244
3249
  }
3245
3250
  }
3246
- brokenYields.forEach((node) => {
3247
- const fix = node.expression ? [{
3248
- fixName: "missingReturnYieldStar_fix",
3249
- description: "Add return statement",
3250
- apply: gen2(function* () {
3251
- const changeTracker = yield* service(ChangeTracker);
3252
- changeTracker.replaceNode(
3253
- sourceFile,
3254
- node,
3255
- ts.factory.createReturnStatement(
3256
- node
3257
- )
3258
- );
3259
- })
3260
- }] : [];
3261
- effectDiagnostics.push({
3262
- node,
3263
- category: ts.DiagnosticCategory.Error,
3264
- messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
3265
- fixes: fix
3266
- });
3267
- });
3268
- return effectDiagnostics;
3269
3251
  })
3270
3252
  });
3271
3253
 
@@ -3273,10 +3255,9 @@ var missingReturnYieldStar = createDiagnostic({
3273
3255
  var missingStarInYieldEffectGen = createDiagnostic({
3274
3256
  name: "missingStarInYieldEffectGen",
3275
3257
  code: 4,
3276
- apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile) {
3258
+ apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
3277
3259
  const ts = yield* service(TypeScriptApi);
3278
3260
  const typeParser = yield* service(TypeParser);
3279
- const effectDiagnostics = [];
3280
3261
  const brokenGenerators = /* @__PURE__ */ new Set();
3281
3262
  const brokenYields = /* @__PURE__ */ new Set();
3282
3263
  const nodeToVisit = [];
@@ -3311,7 +3292,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
3311
3292
  }
3312
3293
  }
3313
3294
  brokenGenerators.forEach(
3314
- (node) => effectDiagnostics.push({
3295
+ (node) => report({
3315
3296
  node,
3316
3297
  category: ts.DiagnosticCategory.Error,
3317
3298
  messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
@@ -3334,14 +3315,13 @@ var missingStarInYieldEffectGen = createDiagnostic({
3334
3315
  );
3335
3316
  })
3336
3317
  }] : [];
3337
- effectDiagnostics.push({
3318
+ report({
3338
3319
  node,
3339
3320
  category: ts.DiagnosticCategory.Error,
3340
3321
  messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
3341
3322
  fixes: fix
3342
3323
  });
3343
3324
  });
3344
- return effectDiagnostics;
3345
3325
  })
3346
3326
  });
3347
3327
 
@@ -3349,12 +3329,10 @@ var missingStarInYieldEffectGen = createDiagnostic({
3349
3329
  var returnEffectInGen = createDiagnostic({
3350
3330
  name: "returnEffectInGen",
3351
3331
  code: 11,
3352
- apply: fn("returnEffectInGen.apply")(function* (sourceFile) {
3332
+ apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
3353
3333
  const ts = yield* service(TypeScriptApi);
3354
3334
  const typeChecker = yield* service(TypeCheckerApi);
3355
3335
  const typeParser = yield* service(TypeParser);
3356
- const effectDiagnostics = [];
3357
- const brokenReturnStatements = /* @__PURE__ */ new Set();
3358
3336
  const nodeToVisit = [];
3359
3337
  const appendNodeToVisit = (node) => {
3360
3338
  nodeToVisit.push(node);
@@ -3372,48 +3350,43 @@ var returnEffectInGen = createDiagnostic({
3372
3350
  );
3373
3351
  if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
3374
3352
  const type = typeChecker.getTypeAtLocation(node.expression);
3375
- const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
3353
+ const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
3376
3354
  if (isSome2(maybeEffect)) {
3377
- const maybeEffectSubtype = yield* option(typeParser.effectSubtype(type, node.expression));
3378
- if (isNone2(maybeEffectSubtype)) {
3379
- if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
3380
- const effectGenNode = generatorOrRegularFunction.parent;
3381
- yield* pipe(
3382
- typeParser.effectGen(effectGenNode),
3383
- orElse3(() => typeParser.effectFnUntracedGen(effectGenNode)),
3384
- orElse3(() => typeParser.effectFnGen(effectGenNode)),
3385
- map4(() => brokenReturnStatements.add(node)),
3386
- ignore
3387
- );
3388
- }
3355
+ if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
3356
+ const effectGenNode = generatorOrRegularFunction.parent;
3357
+ yield* pipe(
3358
+ typeParser.effectGen(effectGenNode),
3359
+ orElse3(() => typeParser.effectFnUntracedGen(effectGenNode)),
3360
+ orElse3(() => typeParser.effectFnGen(effectGenNode)),
3361
+ map4(() => {
3362
+ const fix = node.expression ? [{
3363
+ fixName: "returnEffectInGen_fix",
3364
+ description: "Add yield* statement",
3365
+ apply: gen2(function* () {
3366
+ const changeTracker = yield* service(ChangeTracker);
3367
+ changeTracker.replaceNode(
3368
+ sourceFile,
3369
+ node.expression,
3370
+ ts.factory.createYieldExpression(
3371
+ ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3372
+ node.expression
3373
+ )
3374
+ );
3375
+ })
3376
+ }] : [];
3377
+ report({
3378
+ node,
3379
+ category: ts.DiagnosticCategory.Suggestion,
3380
+ messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>. Maybe you wanted to return yield* instead? Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect.`,
3381
+ fixes: fix
3382
+ });
3383
+ }),
3384
+ ignore
3385
+ );
3389
3386
  }
3390
3387
  }
3391
3388
  }
3392
3389
  }
3393
- brokenReturnStatements.forEach((node) => {
3394
- const fix = node.expression ? [{
3395
- fixName: "returnEffectInGen_fix",
3396
- description: "Add yield* statement",
3397
- apply: gen2(function* () {
3398
- const changeTracker = yield* service(ChangeTracker);
3399
- changeTracker.replaceNode(
3400
- sourceFile,
3401
- node.expression,
3402
- ts.factory.createYieldExpression(
3403
- ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3404
- node.expression
3405
- )
3406
- );
3407
- })
3408
- }] : [];
3409
- effectDiagnostics.push({
3410
- node,
3411
- category: ts.DiagnosticCategory.Suggestion,
3412
- messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>. Maybe you wanted to return yield* instead? Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect.`,
3413
- fixes: fix
3414
- });
3415
- });
3416
- return effectDiagnostics;
3417
3390
  })
3418
3391
  });
3419
3392
 
@@ -3421,11 +3394,9 @@ var returnEffectInGen = createDiagnostic({
3421
3394
  var unnecessaryEffectGen = createDiagnostic({
3422
3395
  name: "unnecessaryEffectGen",
3423
3396
  code: 5,
3424
- apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile) {
3397
+ apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
3425
3398
  const ts = yield* service(TypeScriptApi);
3426
3399
  const typeParser = yield* service(TypeParser);
3427
- const effectDiagnostics = [];
3428
- const unnecessaryGenerators = /* @__PURE__ */ new Map();
3429
3400
  const nodeToVisit = [];
3430
3401
  const appendNodeToVisit = (node) => {
3431
3402
  nodeToVisit.push(node);
@@ -3438,29 +3409,27 @@ var unnecessaryEffectGen = createDiagnostic({
3438
3409
  if (ts.isCallExpression(node)) {
3439
3410
  yield* pipe(
3440
3411
  typeParser.unnecessaryEffectGen(node),
3441
- map4(({ replacementNode }) => unnecessaryGenerators.set(node, replacementNode)),
3412
+ map4(
3413
+ ({ replacementNode }) => report({
3414
+ node,
3415
+ category: ts.DiagnosticCategory.Suggestion,
3416
+ messageText: `This Effect.gen contains a single return statement.`,
3417
+ fixes: [{
3418
+ fixName: "unnecessaryEffectGen_fix",
3419
+ description: "Remove the Effect.gen, and keep the body",
3420
+ apply: gen2(function* () {
3421
+ const textChanges = yield* service(
3422
+ ChangeTracker
3423
+ );
3424
+ textChanges.replaceNode(sourceFile, node, yield* replacementNode);
3425
+ })
3426
+ }]
3427
+ })
3428
+ ),
3442
3429
  ignore
3443
3430
  );
3444
3431
  }
3445
3432
  }
3446
- unnecessaryGenerators.forEach(
3447
- (yieldedResult, effectGenCall) => effectDiagnostics.push({
3448
- node: effectGenCall,
3449
- category: ts.DiagnosticCategory.Suggestion,
3450
- messageText: `This Effect.gen contains a single return statement.`,
3451
- fixes: [{
3452
- fixName: "unnecessaryEffectGen_fix",
3453
- description: "Remove the Effect.gen, and keep the body",
3454
- apply: gen2(function* () {
3455
- const textChanges = yield* service(
3456
- ChangeTracker
3457
- );
3458
- textChanges.replaceNode(sourceFile, effectGenCall, yield* yieldedResult);
3459
- })
3460
- }]
3461
- })
3462
- );
3463
- return effectDiagnostics;
3464
3433
  })
3465
3434
  });
3466
3435
 
@@ -3468,11 +3437,9 @@ var unnecessaryEffectGen = createDiagnostic({
3468
3437
  var unnecessaryPipe = createDiagnostic({
3469
3438
  name: "unnecessaryPipe",
3470
3439
  code: 9,
3471
- apply: fn("unnecessaryPipe.apply")(function* (sourceFile) {
3440
+ apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
3472
3441
  const ts = yield* service(TypeScriptApi);
3473
3442
  const typeParser = yield* service(TypeParser);
3474
- const pipeDiagnostics = [];
3475
- const unnecessaryPipes = /* @__PURE__ */ new Map();
3476
3443
  const nodeToVisit = [];
3477
3444
  const appendNodeToVisit = (node) => {
3478
3445
  nodeToVisit.push(node);
@@ -3485,29 +3452,29 @@ var unnecessaryPipe = createDiagnostic({
3485
3452
  if (ts.isCallExpression(node)) {
3486
3453
  yield* pipe(
3487
3454
  typeParser.pipeCall(node),
3488
- map4(({ args, subject }) => args.length === 0 ? unnecessaryPipes.set(node, subject) : void 0),
3455
+ map4(({ args, subject }) => {
3456
+ if (args.length === 0) {
3457
+ report({
3458
+ node,
3459
+ category: ts.DiagnosticCategory.Suggestion,
3460
+ messageText: `This pipe call contains no arguments.`,
3461
+ fixes: [{
3462
+ fixName: "unnecessaryPipe_fix",
3463
+ description: "Remove the pipe call",
3464
+ apply: gen2(function* () {
3465
+ const textChanges = yield* service(
3466
+ ChangeTracker
3467
+ );
3468
+ textChanges.replaceNode(sourceFile, node, subject);
3469
+ })
3470
+ }]
3471
+ });
3472
+ }
3473
+ }),
3489
3474
  ignore
3490
3475
  );
3491
3476
  }
3492
3477
  }
3493
- unnecessaryPipes.forEach(
3494
- (pipeCall, pipeSubject) => pipeDiagnostics.push({
3495
- node: pipeCall,
3496
- category: ts.DiagnosticCategory.Suggestion,
3497
- messageText: `This pipe call contains no arguments.`,
3498
- fixes: [{
3499
- fixName: "unnecessaryPipe_fix",
3500
- description: "Remove the pipe call",
3501
- apply: gen2(function* () {
3502
- const textChanges = yield* service(
3503
- ChangeTracker
3504
- );
3505
- textChanges.replaceNode(sourceFile, pipeSubject, pipeCall);
3506
- })
3507
- }]
3508
- })
3509
- );
3510
- return pipeDiagnostics;
3511
3478
  })
3512
3479
  });
3513
3480