@effect/language-service 0.72.0 → 0.73.0

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.
@@ -1161,6 +1161,13 @@ var option = (fa) => {
1161
1161
  nano[contE] = (_) => _ instanceof NanoDefectException ? fail(_) : succeed(none2());
1162
1162
  return nano;
1163
1163
  };
1164
+ var orUndefined = (fa) => {
1165
+ const nano = Object.create(MatchProto);
1166
+ nano[args] = fa;
1167
+ nano[contA] = (_) => succeed(_);
1168
+ nano[contE] = (_) => _ instanceof NanoDefectException ? fail(_) : succeed(void 0);
1169
+ return nano;
1170
+ };
1164
1171
  var ignore = (fa) => {
1165
1172
  const nano = Object.create(MatchProto);
1166
1173
  nano[args] = fa;
@@ -1352,7 +1359,7 @@ function makeTypeScriptUtils(ts) {
1352
1359
  if (!hasProperty(packageJsonScope, "packageDirectory")) return;
1353
1360
  if (!isString(packageJsonScope.packageDirectory)) return;
1354
1361
  const { name } = packageJsonContent;
1355
- const version = hasProperty(packageJsonScope, "version") ? packageJsonScope.version : "";
1362
+ const version = hasProperty(packageJsonContent, "version") ? packageJsonContent.version : "unknown";
1356
1363
  if (!isString(name)) return;
1357
1364
  if (!isString(version)) return;
1358
1365
  const hasEffectInPeerDependencies = hasProperty(packageJsonContent, "peerDependencies") && isObject(packageJsonContent.peerDependencies) && hasProperty(packageJsonContent.peerDependencies, "effect");
@@ -2568,6 +2575,8 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
2568
2575
  }
2569
2576
 
2570
2577
  // src/core/TypeParser.ts
2578
+ var checkedPackagesCache = /* @__PURE__ */ new Map();
2579
+ var programResolvedCacheSize = /* @__PURE__ */ new Map();
2571
2580
  var TypeParser = Tag("@effect/language-service/TypeParser");
2572
2581
  var nanoLayer3 = (fa) => gen(function* () {
2573
2582
  const ts = yield* service(TypeScriptApi);
@@ -2588,6 +2597,42 @@ function typeParserIssue(_message, _type, _node) {
2588
2597
  return TypeParserIssue.issue;
2589
2598
  }
2590
2599
  function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2600
+ function supportedEffect() {
2601
+ for (const fileName of program.getRootFileNames()) {
2602
+ const sourceFile = program.getSourceFile(fileName);
2603
+ if (!sourceFile) continue;
2604
+ const resolvedPackages = getEffectRelatedPackages(sourceFile);
2605
+ const effectPkgs = resolvedPackages["effect"];
2606
+ if (!effectPkgs) continue;
2607
+ for (const version of Object.keys(effectPkgs)) {
2608
+ if (String(version).startsWith("4")) return "v4";
2609
+ if (String(version).startsWith("3")) return "v3";
2610
+ }
2611
+ }
2612
+ return "v3";
2613
+ }
2614
+ function getEffectRelatedPackages(sourceFile) {
2615
+ let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
2616
+ const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
2617
+ const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
2618
+ if (newResolvedModuleSize !== oldResolvedSize) {
2619
+ const seenPackages = /* @__PURE__ */ new Set();
2620
+ resolvedPackages = {};
2621
+ program.getSourceFiles().map((_) => {
2622
+ const packageInfo = tsUtils.parsePackageContentNameAndVersionFromScope(_);
2623
+ if (!packageInfo) return;
2624
+ const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
2625
+ if (seenPackages.has(packageNameAndVersion)) return;
2626
+ seenPackages.add(packageNameAndVersion);
2627
+ if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
2628
+ resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
2629
+ resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
2630
+ });
2631
+ checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
2632
+ programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
2633
+ }
2634
+ return resolvedPackages;
2635
+ }
2591
2636
  const getSourceFilePackageInfo = cachedBy(
2592
2637
  fn("TypeParser.getSourceFilePackageInfo")(function* (sourceFile) {
2593
2638
  return tsUtils.resolveModuleWithPackageInfoFromSourceFile(program, sourceFile);
@@ -2816,19 +2861,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2816
2861
  );
2817
2862
  const effectType = cachedBy(
2818
2863
  fn("TypeParser.effectType")(function* (type, atLocation) {
2819
- const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
2820
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
2821
- );
2822
- if (propertiesSymbols.length === 0) {
2823
- return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
2864
+ if (supportedEffect() === "v4") {
2865
+ const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Effect");
2866
+ if (typeIdSymbol) {
2867
+ const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
2868
+ return yield* effectVarianceStruct(typeIdType, atLocation);
2869
+ }
2870
+ return yield* typeParserIssue("Type is not an effect", type, atLocation);
2871
+ } else {
2872
+ const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
2873
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
2874
+ );
2875
+ if (propertiesSymbols.length === 0) {
2876
+ return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
2877
+ }
2878
+ propertiesSymbols.sort(
2879
+ (a, b) => ts.symbolName(b).indexOf("EffectTypeId") - ts.symbolName(a).indexOf("EffectTypeId")
2880
+ );
2881
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
2882
+ const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2883
+ return effectVarianceStruct(propertyType, atLocation);
2884
+ }));
2824
2885
  }
2825
- propertiesSymbols.sort(
2826
- (a, b) => ts.symbolName(b).indexOf("EffectTypeId") - ts.symbolName(a).indexOf("EffectTypeId")
2827
- );
2828
- return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
2829
- const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2830
- return effectVarianceStruct(propertyType, atLocation);
2831
- }));
2832
2886
  }),
2833
2887
  "TypeParser.effectType",
2834
2888
  (type) => type
@@ -2957,7 +3011,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2957
3011
  fn("TypeParser.isEffectDataSourceFile")(function* (sourceFile) {
2958
3012
  const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2959
3013
  if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2960
- const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol);
3014
+ const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol) || typeChecker.tryGetMemberInModuleExports("taggedEnum", moduleSymbol);
2961
3015
  if (!taggedEnumSymbol) return yield* typeParserIssue("TaggedEnum not found", void 0, sourceFile);
2962
3016
  const taggedErrorSymbol = typeChecker.tryGetMemberInModuleExports("TaggedError", moduleSymbol);
2963
3017
  if (!taggedErrorSymbol) return yield* typeParserIssue("TaggedError not found", void 0, sourceFile);
@@ -3148,10 +3202,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3148
3202
  }))
3149
3203
  )
3150
3204
  ),
3151
- option
3205
+ orUndefined
3152
3206
  );
3153
- if (isSome2(isEffectGen)) {
3154
- effectGenResult = isEffectGen.value;
3207
+ if (isEffectGen) {
3208
+ effectGenResult = isEffectGen;
3155
3209
  }
3156
3210
  }
3157
3211
  if (scopeNode && effectGenResult) {
@@ -3271,6 +3325,21 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3271
3325
  const effectSchemaType = cachedBy(
3272
3326
  fn("TypeParser.effectSchemaType")(function* (type, atLocation) {
3273
3327
  yield* pipeableType(type, atLocation);
3328
+ const typeId = typeChecker.getPropertyOfType(type, "~effect/Schema/Schema");
3329
+ if (typeId) {
3330
+ const typeKey = typeChecker.getPropertyOfType(type, "Type");
3331
+ const encodedKey = typeChecker.getPropertyOfType(type, "Encoded");
3332
+ if (typeKey && encodedKey) {
3333
+ const typeType = typeChecker.getTypeOfSymbolAtLocation(typeKey, atLocation);
3334
+ const encodedType = typeChecker.getTypeOfSymbolAtLocation(encodedKey, atLocation);
3335
+ return {
3336
+ A: typeType,
3337
+ I: encodedType,
3338
+ R: typeChecker.getNeverType()
3339
+ };
3340
+ }
3341
+ return yield* typeParserIssue("missing Type and Encoded");
3342
+ }
3274
3343
  const ast = typeChecker.getPropertyOfType(type, "ast");
3275
3344
  if (!ast) return yield* typeParserIssue("Has no 'ast' property", type, atLocation);
3276
3345
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
@@ -3489,9 +3558,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3489
3558
  if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
3490
3559
  const isEffectSchemaModuleApi = yield* pipe(
3491
3560
  isNodeReferenceToEffectSchemaModuleApi("Class")(schemaCall.expression),
3492
- option
3561
+ orUndefined
3493
3562
  );
3494
- if (isSome2(isEffectSchemaModuleApi)) {
3563
+ if (isEffectSchemaModuleApi) {
3495
3564
  return {
3496
3565
  className: atLocation.name,
3497
3566
  selfTypeNode: schemaCall.typeArguments[0]
@@ -3526,9 +3595,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3526
3595
  const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
3527
3596
  const isEffectSchemaModuleApi = yield* pipe(
3528
3597
  isNodeReferenceToEffectSchemaModuleApi("TaggedClass")(schemaTaggedClassTCall.expression),
3529
- option
3598
+ orUndefined
3530
3599
  );
3531
- if (isSome2(isEffectSchemaModuleApi)) {
3600
+ if (isEffectSchemaModuleApi) {
3532
3601
  return {
3533
3602
  className: atLocation.name,
3534
3603
  selfTypeNode,
@@ -3565,9 +3634,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3565
3634
  const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
3566
3635
  const isEffectSchemaModuleApi = yield* pipe(
3567
3636
  isNodeReferenceToEffectSchemaModuleApi("TaggedError")(schemaTaggedErrorTCall.expression),
3568
- option
3637
+ orUndefined
3569
3638
  );
3570
- if (isSome2(isEffectSchemaModuleApi)) {
3639
+ if (isEffectSchemaModuleApi) {
3571
3640
  return {
3572
3641
  className: atLocation.name,
3573
3642
  selfTypeNode,
@@ -3587,6 +3656,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3587
3656
  );
3588
3657
  const extendsSchemaTaggedRequest = cachedBy(
3589
3658
  fn("TypeParser.extendsSchemaTaggedRequest")(function* (atLocation) {
3659
+ if (supportedEffect() === "v4") {
3660
+ return yield* typeParserIssue("Schema.TaggedClass is not supported in Effect v4", void 0, atLocation);
3661
+ }
3590
3662
  if (!atLocation.name) {
3591
3663
  return yield* typeParserIssue("Class has no name", void 0, atLocation);
3592
3664
  }
@@ -3604,9 +3676,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3604
3676
  const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3605
3677
  const isEffectSchemaModuleApi = yield* pipe(
3606
3678
  isNodeReferenceToEffectSchemaModuleApi("TaggedRequest")(schemaTaggedRequestTCall.expression),
3607
- option
3679
+ orUndefined
3608
3680
  );
3609
- if (isSome2(isEffectSchemaModuleApi)) {
3681
+ if (isEffectSchemaModuleApi) {
3610
3682
  return {
3611
3683
  className: atLocation.name,
3612
3684
  selfTypeNode,
@@ -3624,6 +3696,48 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3624
3696
  "TypeParser.extendsSchemaTaggedRequest",
3625
3697
  (atLocation) => atLocation
3626
3698
  );
3699
+ const extendsSchemaRequestClass = cachedBy(
3700
+ fn("TypeParser.extendsSchemaRequestClass")(function* (atLocation) {
3701
+ if (supportedEffect() === "v3") {
3702
+ return yield* typeParserIssue("Schema.RequestClass is not supported in Effect v3", void 0, atLocation);
3703
+ }
3704
+ if (!atLocation.name) {
3705
+ return yield* typeParserIssue("Class has no name", void 0, atLocation);
3706
+ }
3707
+ const heritageClauses = atLocation.heritageClauses;
3708
+ if (!heritageClauses) {
3709
+ return yield* typeParserIssue("Class has no heritage clauses", void 0, atLocation);
3710
+ }
3711
+ for (const heritageClause of heritageClauses) {
3712
+ for (const typeX of heritageClause.types) {
3713
+ if (ts.isExpressionWithTypeArguments(typeX)) {
3714
+ const expression = typeX.expression;
3715
+ if (ts.isCallExpression(expression)) {
3716
+ const schemaTaggedRequestTCall = expression.expression;
3717
+ if (ts.isCallExpression(schemaTaggedRequestTCall) && schemaTaggedRequestTCall.typeArguments && schemaTaggedRequestTCall.typeArguments.length > 0) {
3718
+ const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3719
+ const isEffectSchemaModuleApi = yield* pipe(
3720
+ isNodeReferenceToEffectSchemaModuleApi("RequestClass")(schemaTaggedRequestTCall.expression),
3721
+ orUndefined
3722
+ );
3723
+ if (isEffectSchemaModuleApi) {
3724
+ return {
3725
+ className: atLocation.name,
3726
+ selfTypeNode,
3727
+ tagStringLiteral: void 0,
3728
+ keyStringLiteral: schemaTaggedRequestTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedRequestTCall.arguments[0]) ? schemaTaggedRequestTCall.arguments[0] : void 0
3729
+ };
3730
+ }
3731
+ }
3732
+ }
3733
+ }
3734
+ }
3735
+ }
3736
+ return yield* typeParserIssue("Class does not extend Schema.RequestClass", void 0, atLocation);
3737
+ }),
3738
+ "TypeParser.extendsSchemaRequestClass",
3739
+ (atLocation) => atLocation
3740
+ );
3627
3741
  const extendsDataTaggedError = cachedBy(
3628
3742
  fn("TypeParser.extendsDataTaggedError")(function* (atLocation) {
3629
3743
  if (!atLocation.name) {
@@ -3643,13 +3757,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3643
3757
  if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedError") {
3644
3758
  const parsedDataModule = yield* pipe(
3645
3759
  importedDataModule(dataIdentifier.expression),
3646
- option
3760
+ orUndefined
3647
3761
  );
3648
- if (isSome2(parsedDataModule)) {
3762
+ if (parsedDataModule) {
3649
3763
  return {
3650
3764
  className: atLocation.name,
3651
3765
  keyStringLiteral: dataTaggedErrorCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedErrorCall.arguments[0]) ? dataTaggedErrorCall.arguments[0] : void 0,
3652
- Data: parsedDataModule.value
3766
+ Data: parsedDataModule
3653
3767
  };
3654
3768
  }
3655
3769
  }
@@ -3681,13 +3795,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3681
3795
  if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedClass") {
3682
3796
  const parsedDataModule = yield* pipe(
3683
3797
  importedDataModule(dataIdentifier.expression),
3684
- option
3798
+ orUndefined
3685
3799
  );
3686
- if (isSome2(parsedDataModule)) {
3800
+ if (parsedDataModule) {
3687
3801
  return {
3688
3802
  className: atLocation.name,
3689
3803
  keyStringLiteral: dataTaggedClassCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedClassCall.arguments[0]) ? dataTaggedClassCall.arguments[0] : void 0,
3690
- Data: parsedDataModule.value
3804
+ Data: parsedDataModule
3691
3805
  };
3692
3806
  }
3693
3807
  }
@@ -3721,9 +3835,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3721
3835
  if (ts.isPropertyAccessExpression(contextTagIdentifier) && ts.isIdentifier(contextTagIdentifier.name) && ts.idText(contextTagIdentifier.name) === "Tag") {
3722
3836
  const parsedContextModule = yield* pipe(
3723
3837
  importedContextModule(contextTagIdentifier.expression),
3724
- option
3838
+ orUndefined
3725
3839
  );
3726
- if (isSome2(parsedContextModule)) {
3840
+ if (parsedContextModule) {
3727
3841
  const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3728
3842
  if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3729
3843
  const type = typeChecker.getTypeOfSymbol(classSym);
@@ -3734,7 +3848,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3734
3848
  keyStringLiteral: ts.isStringLiteral(contextTagCall.arguments[0]) ? contextTagCall.arguments[0] : void 0,
3735
3849
  args: contextTagCall.arguments,
3736
3850
  Identifier: tagType.Identifier,
3737
- Tag: parsedContextModule.value
3851
+ Tag: parsedContextModule
3738
3852
  };
3739
3853
  }
3740
3854
  }
@@ -3772,9 +3886,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3772
3886
  const selfTypeNode = wholeCall.typeArguments[0];
3773
3887
  const isEffectTag = yield* pipe(
3774
3888
  isNodeReferenceToEffectModuleApi("Tag")(effectTagIdentifier),
3775
- option
3889
+ orUndefined
3776
3890
  );
3777
- if (isSome2(isEffectTag)) {
3891
+ if (isEffectTag) {
3778
3892
  return {
3779
3893
  className: atLocation.name,
3780
3894
  selfTypeNode,
@@ -3814,17 +3928,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3814
3928
  const selfTypeNode = effectServiceCall.typeArguments[0];
3815
3929
  const isEffectService = yield* pipe(
3816
3930
  isNodeReferenceToEffectModuleApi("Service")(effectServiceIdentifier),
3817
- option
3931
+ orUndefined
3818
3932
  );
3819
- if (isSome2(isEffectService)) {
3933
+ if (isEffectService) {
3820
3934
  const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3821
3935
  if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3822
3936
  const type = typeChecker.getTypeOfSymbol(classSym);
3823
3937
  const parsedContextTag = yield* pipe(
3824
3938
  contextTag(type, atLocation),
3825
- option
3939
+ orUndefined
3826
3940
  );
3827
- if (isSome2(parsedContextTag)) {
3941
+ if (parsedContextTag) {
3828
3942
  let accessors2 = void 0;
3829
3943
  let dependencies = void 0;
3830
3944
  if (wholeCall.arguments.length >= 2) {
@@ -3841,7 +3955,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3841
3955
  }
3842
3956
  }
3843
3957
  return {
3844
- ...parsedContextTag.value,
3958
+ ...parsedContextTag,
3845
3959
  className: atLocation.name,
3846
3960
  selfTypeNode,
3847
3961
  args: wholeCall.arguments,
@@ -3911,9 +4025,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3911
4025
  if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
3912
4026
  const isEffectSchemaModuleApi = yield* pipe(
3913
4027
  isNodeReferenceToEffectSqlModelModuleApi("Class")(schemaCall.expression),
3914
- option
4028
+ orUndefined
3915
4029
  );
3916
- if (isSome2(isEffectSchemaModuleApi)) {
4030
+ if (isEffectSchemaModuleApi) {
3917
4031
  return {
3918
4032
  className: atLocation.name,
3919
4033
  selfTypeNode: schemaCall.typeArguments[0]
@@ -4036,19 +4150,18 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4036
4150
  map4((s) => ({ _tag: "call", ...s }))
4037
4151
  )
4038
4152
  ),
4039
- option
4153
+ orUndefined
4040
4154
  );
4041
- if (isSome2(parsed)) {
4042
- const result2 = parsed.value;
4155
+ if (parsed) {
4043
4156
  let transformations;
4044
4157
  let flowNode;
4045
4158
  let childrenToTraverse = [];
4046
- if (result2._tag === "pipe") {
4047
- const signature = typeChecker.getResolvedSignature(result2.node);
4159
+ if (parsed._tag === "pipe") {
4160
+ const signature = typeChecker.getResolvedSignature(parsed.node);
4048
4161
  const typeArguments = signature ? typeChecker.getTypeArgumentsForResolvedSignature(signature) : void 0;
4049
4162
  transformations = [];
4050
- for (let i = 0; i < result2.args.length; i++) {
4051
- const arg = result2.args[i];
4163
+ for (let i = 0; i < parsed.args.length; i++) {
4164
+ const arg = parsed.args[i];
4052
4165
  const outType = typeArguments?.[i + 1];
4053
4166
  if (ts.isCallExpression(arg)) {
4054
4167
  transformations.push({
@@ -4057,7 +4170,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4057
4170
  args: Array.from(arg.arguments),
4058
4171
  // e.g., [(x) => x + 1]
4059
4172
  outType,
4060
- kind: result2.kind
4173
+ kind: parsed.kind
4061
4174
  });
4062
4175
  } else {
4063
4176
  transformations.push({
@@ -4065,17 +4178,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4065
4178
  // e.g., Effect.asVoid
4066
4179
  args: void 0,
4067
4180
  outType,
4068
- kind: result2.kind
4181
+ kind: parsed.kind
4069
4182
  });
4070
4183
  }
4071
4184
  }
4072
- flowNode = result2.node;
4073
- childrenToTraverse = result2.args;
4185
+ flowNode = parsed.node;
4186
+ childrenToTraverse = parsed.args;
4074
4187
  } else {
4075
4188
  const callSignature = typeChecker.getResolvedSignature(node);
4076
4189
  const outType = callSignature ? typeChecker.getReturnTypeOfSignature(callSignature) : void 0;
4077
4190
  transformations = [{
4078
- callee: result2.callee,
4191
+ callee: parsed.callee,
4079
4192
  args: void 0,
4080
4193
  outType,
4081
4194
  kind: "call"
@@ -4085,20 +4198,20 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4085
4198
  if (parentFlow) {
4086
4199
  parentFlow.transformations.unshift(...transformations);
4087
4200
  parentFlow.subject = {
4088
- node: result2.subject,
4089
- outType: typeCheckerUtils.getTypeAtLocation(result2.subject)
4201
+ node: parsed.subject,
4202
+ outType: typeCheckerUtils.getTypeAtLocation(parsed.subject)
4090
4203
  };
4091
- workQueue.push([result2.subject, parentFlow]);
4204
+ workQueue.push([parsed.subject, parentFlow]);
4092
4205
  } else {
4093
4206
  const newFlow = {
4094
4207
  node: flowNode,
4095
4208
  subject: {
4096
- node: result2.subject,
4097
- outType: typeCheckerUtils.getTypeAtLocation(result2.subject)
4209
+ node: parsed.subject,
4210
+ outType: typeCheckerUtils.getTypeAtLocation(parsed.subject)
4098
4211
  },
4099
4212
  transformations
4100
4213
  };
4101
- workQueue.push([result2.subject, newFlow]);
4214
+ workQueue.push([parsed.subject, newFlow]);
4102
4215
  }
4103
4216
  for (const child of childrenToTraverse) {
4104
4217
  ts.forEachChild(child, (c) => {
@@ -4108,17 +4221,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4108
4221
  continue;
4109
4222
  }
4110
4223
  if (includeEffectFn) {
4111
- const effectFnGenParsed = yield* pipe(effectFnGen(node), option);
4112
- const effectFnUntracedGenParsed = isNone2(effectFnGenParsed) ? yield* pipe(effectFnUntracedGen(node), option) : none2();
4113
- const effectFnNonGenParsed = isNone2(effectFnGenParsed) && isNone2(effectFnUntracedGenParsed) ? yield* pipe(effectFn(node), option) : none2();
4114
- const isEffectFnGen = isSome2(effectFnGenParsed);
4115
- const isEffectFnUntracedGen = isSome2(effectFnUntracedGenParsed);
4116
- const isEffectFnNonGen = isSome2(effectFnNonGenParsed);
4117
- const transformationKind = isEffectFnUntracedGen ? "effectFnUntraced" : "effectFn";
4118
- if (isEffectFnGen || isEffectFnUntracedGen) {
4119
- const effectFnParsed = isEffectFnGen ? effectFnGenParsed : effectFnUntracedGenParsed;
4120
- if (isSome2(effectFnParsed) && effectFnParsed.value.pipeArguments.length > 0) {
4121
- const fnResult = effectFnParsed.value;
4224
+ const effectFnKind = yield* pipe(
4225
+ map4(effectFnGen(node), (_) => ({ kind: "effectFnGen", ..._ })),
4226
+ orElse2(
4227
+ () => map4(effectFnUntracedGen(node), (_) => ({ kind: "effectFnUntracedGen", ..._ }))
4228
+ ),
4229
+ orElse2(() => map4(effectFn(node), (_) => ({ kind: "effectFn", ..._ }))),
4230
+ orUndefined
4231
+ );
4232
+ if (effectFnKind && (effectFnKind.kind === "effectFnGen" || effectFnKind.kind === "effectFnUntracedGen")) {
4233
+ if (effectFnKind.pipeArguments.length > 0) {
4234
+ const fnResult = effectFnKind;
4122
4235
  const pipeArgs = fnResult.pipeArguments;
4123
4236
  const transformations = [];
4124
4237
  let subjectType;
@@ -4138,14 +4251,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4138
4251
  callee: arg.expression,
4139
4252
  args: Array.from(arg.arguments),
4140
4253
  outType,
4141
- kind: transformationKind
4254
+ kind: effectFnKind.kind === "effectFnUntracedGen" ? "effectFnUntraced" : "effectFn"
4142
4255
  });
4143
4256
  } else {
4144
4257
  transformations.push({
4145
4258
  callee: arg,
4146
4259
  args: void 0,
4147
4260
  outType,
4148
- kind: transformationKind
4261
+ kind: effectFnKind.kind === "effectFnUntracedGen" ? "effectFnUntraced" : "effectFn"
4149
4262
  });
4150
4263
  }
4151
4264
  }
@@ -4167,8 +4280,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4167
4280
  continue;
4168
4281
  }
4169
4282
  }
4170
- if (isEffectFnNonGen && isSome2(effectFnNonGenParsed) && effectFnNonGenParsed.value.pipeArguments.length > 0) {
4171
- const fnResult = effectFnNonGenParsed.value;
4283
+ if (effectFnKind && effectFnKind.kind === "effectFn" && effectFnKind.pipeArguments.length > 0) {
4284
+ const fnResult = effectFnKind;
4172
4285
  const pipeArgs = fnResult.pipeArguments;
4173
4286
  const transformations = [];
4174
4287
  let subjectType;
@@ -4314,11 +4427,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4314
4427
  extendsDataTaggedError,
4315
4428
  extendsDataTaggedClass,
4316
4429
  extendsSchemaTaggedRequest,
4430
+ extendsSchemaRequestClass,
4317
4431
  extendsEffectSqlModelClass,
4318
4432
  lazyExpression,
4319
4433
  emptyFunction,
4320
4434
  pipingFlows,
4321
- reconstructPipingFlow
4435
+ reconstructPipingFlow,
4436
+ getEffectRelatedPackages,
4437
+ supportedEffect
4322
4438
  };
4323
4439
  }
4324
4440
 
@@ -4434,6 +4550,7 @@ var catchAllToMapError = createDiagnostic({
4434
4550
  apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
4435
4551
  const ts = yield* service(TypeScriptApi);
4436
4552
  const typeParser = yield* service(TypeParser);
4553
+ const catchAllName = typeParser.supportedEffect() === "v3" ? "catchAll" : "catch";
4437
4554
  const getFunctionBody = (node) => {
4438
4555
  if (ts.isArrowFunction(node)) {
4439
4556
  return node.body;
@@ -4448,10 +4565,10 @@ var catchAllToMapError = createDiagnostic({
4448
4565
  if (ts.isCallExpression(body)) {
4449
4566
  const isFailCall = yield* pipe(
4450
4567
  typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4451
- option
4568
+ orUndefined
4452
4569
  );
4453
- if (isSome2(isFailCall) && body.arguments.length >= 1) {
4454
- return some2({ failCall: body, failArg: body.arguments[0] });
4570
+ if (isFailCall && body.arguments.length >= 1) {
4571
+ return { failCall: body, failArg: body.arguments[0] };
4455
4572
  }
4456
4573
  }
4457
4574
  if (ts.isBlock(body)) {
@@ -4461,15 +4578,14 @@ var catchAllToMapError = createDiagnostic({
4461
4578
  if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4462
4579
  const isFailCall = yield* pipe(
4463
4580
  typeParser.isNodeReferenceToEffectModuleApi("fail")(stmt.expression.expression),
4464
- option
4581
+ orUndefined
4465
4582
  );
4466
- if (isSome2(isFailCall) && stmt.expression.arguments.length >= 1) {
4467
- return some2({ failCall: stmt.expression, failArg: stmt.expression.arguments[0] });
4583
+ if (isFailCall && stmt.expression.arguments.length >= 1) {
4584
+ return { failCall: stmt.expression, failArg: stmt.expression.arguments[0] };
4468
4585
  }
4469
4586
  }
4470
4587
  }
4471
4588
  }
4472
- return none2();
4473
4589
  });
4474
4590
  };
4475
4591
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
@@ -4479,10 +4595,10 @@ var catchAllToMapError = createDiagnostic({
4479
4595
  continue;
4480
4596
  }
4481
4597
  const isCatchAllCall = yield* pipe(
4482
- typeParser.isNodeReferenceToEffectModuleApi("catchAll")(transformation.callee),
4483
- option
4598
+ typeParser.isNodeReferenceToEffectModuleApi(catchAllName)(transformation.callee),
4599
+ orUndefined
4484
4600
  );
4485
- if (isNone2(isCatchAllCall)) {
4601
+ if (!isCatchAllCall) {
4486
4602
  continue;
4487
4603
  }
4488
4604
  const callback = transformation.args[0];
@@ -4490,11 +4606,11 @@ var catchAllToMapError = createDiagnostic({
4490
4606
  const functionBody = getFunctionBody(callback);
4491
4607
  if (!functionBody) continue;
4492
4608
  const failCallInfo = yield* getEffectFailCallInfo(functionBody);
4493
- if (isNone2(failCallInfo)) continue;
4494
- const { failArg, failCall } = failCallInfo.value;
4609
+ if (!failCallInfo) continue;
4610
+ const { failArg, failCall } = failCallInfo;
4495
4611
  report({
4496
4612
  location: transformation.callee,
4497
- messageText: `You can use Effect.mapError instead of Effect.catchAll + Effect.fail to transform the error type.`,
4613
+ messageText: `You can use Effect.mapError instead of Effect.${catchAllName} + Effect.fail to transform the error type.`,
4498
4614
  fixes: [{
4499
4615
  fixName: "catchAllToMapError_fix",
4500
4616
  description: "Replace with Effect.mapError",
@@ -4525,7 +4641,7 @@ var catchUnfailableEffect = createDiagnostic({
4525
4641
  apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
4526
4642
  const ts = yield* service(TypeScriptApi);
4527
4643
  const typeParser = yield* service(TypeParser);
4528
- const catchFunctions = ["catchAll", "catch", "catchIf", "catchSome", "catchTag", "catchTags"];
4644
+ const catchFunctions = typeParser.supportedEffect() === "v3" ? ["catchAll", "catch", "catchIf", "catchSome", "catchTag", "catchTags"] : ["catch", "catchIf", "catchTag", "catchTags"];
4529
4645
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
4530
4646
  for (const flow2 of flows) {
4531
4647
  for (let i = 0; i < flow2.transformations.length; i++) {
@@ -4590,7 +4706,12 @@ var classSelfMismatch = createDiagnostic({
4590
4706
  orElse2(() => typeParser.extendsSchemaClass(node)),
4591
4707
  orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
4592
4708
  orElse2(() => typeParser.extendsSchemaTaggedError(node)),
4593
- orElse2(() => typeParser.extendsSchemaTaggedRequest(node)),
4709
+ orElse2(
4710
+ () => pipe(
4711
+ typeParser.extendsSchemaTaggedRequest(node),
4712
+ orElse2(() => typeParser.extendsSchemaRequestClass(node))
4713
+ )
4714
+ ),
4594
4715
  orElse2(() => typeParser.extendsEffectSqlModelClass(node)),
4595
4716
  orElse2(() => void_)
4596
4717
  );
@@ -4817,39 +4938,18 @@ var deterministicKeys = createDiagnostic({
4817
4938
  });
4818
4939
 
4819
4940
  // src/diagnostics/duplicatePackage.ts
4820
- var checkedPackagesCache = /* @__PURE__ */ new Map();
4821
- var programResolvedCacheSize = /* @__PURE__ */ new Map();
4822
4941
  var duplicatePackage = createDiagnostic({
4823
4942
  name: "duplicatePackage",
4824
4943
  code: 6,
4825
4944
  description: "Detects when multiple versions of the same Effect package are loaded",
4826
4945
  severity: "warning",
4827
4946
  apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
4828
- const program = yield* service(TypeScriptProgram);
4829
- const tsUtils = yield* service(TypeScriptUtils);
4947
+ const typeParser = yield* service(TypeParser);
4830
4948
  const options = yield* service(LanguageServicePluginOptions);
4831
4949
  if (sourceFile.statements.length < 1) return;
4832
- let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
4833
- const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
4834
- const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
4835
- if (newResolvedModuleSize !== oldResolvedSize) {
4836
- const seenPackages = /* @__PURE__ */ new Set();
4837
- resolvedPackages = {};
4838
- program.getSourceFiles().map((_) => {
4839
- const packageInfo = tsUtils.parsePackageContentNameAndVersionFromScope(_);
4840
- if (!packageInfo) return;
4841
- const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
4842
- if (seenPackages.has(packageNameAndVersion)) return;
4843
- seenPackages.add(packageNameAndVersion);
4844
- if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
4845
- if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
4846
- resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
4847
- resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
4848
- });
4849
- checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
4850
- programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
4851
- }
4950
+ const resolvedPackages = typeParser.getEffectRelatedPackages(sourceFile);
4852
4951
  for (const packageName of Object.keys(resolvedPackages)) {
4952
+ if (options.allowedDuplicatedPackages.indexOf(packageName) > -1) return;
4853
4953
  if (Object.keys(resolvedPackages[packageName]).length > 1) {
4854
4954
  const versions = Object.keys(resolvedPackages[packageName]);
4855
4955
  report({
@@ -5673,23 +5773,25 @@ var globalErrorInEffectCatch = createDiagnostic({
5673
5773
  if (isEffectWithCatch) {
5674
5774
  const signature = typeChecker.getResolvedSignature(node);
5675
5775
  if (signature) {
5676
- const objectType = typeChecker.getParameterType(signature, 0);
5677
- const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
5678
- if (catchFunctionSymbol) {
5679
- const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
5680
- const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
5681
- if (signatures.length > 0) {
5682
- const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
5683
- if (returnType && typeCheckerUtils.isGlobalErrorType(returnType)) {
5684
- const nodeText = sourceFile.text.substring(
5685
- ts.getTokenPosOfNode(node.expression, sourceFile),
5686
- node.expression.end
5687
- );
5688
- report({
5689
- location: node.expression,
5690
- messageText: `The 'catch' callback in ${nodeText} returns global 'Error', which loses type safety as untagged errors merge together. Consider using a tagged error and optionally wrapping the original in a 'cause' property.`,
5691
- fixes: []
5692
- });
5776
+ const firstParameterType = typeChecker.getParameterType(signature, 0);
5777
+ for (const objectType of typeCheckerUtils.unrollUnionMembers(firstParameterType)) {
5778
+ const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
5779
+ if (catchFunctionSymbol) {
5780
+ const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
5781
+ const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
5782
+ if (signatures.length > 0) {
5783
+ const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
5784
+ if (returnType && typeCheckerUtils.isGlobalErrorType(returnType)) {
5785
+ const nodeText = sourceFile.text.substring(
5786
+ ts.getTokenPosOfNode(node.expression, sourceFile),
5787
+ node.expression.end
5788
+ );
5789
+ report({
5790
+ location: node.expression,
5791
+ messageText: `The 'catch' callback in ${nodeText} returns global 'Error', which loses type safety as untagged errors merge together. Consider using a tagged error and optionally wrapping the original in a 'cause' property.`,
5792
+ fixes: []
5793
+ });
5794
+ }
5693
5795
  }
5694
5796
  }
5695
5797
  }
@@ -6502,22 +6604,23 @@ var missingEffectError = createDiagnostic({
6502
6604
  map4((result) => {
6503
6605
  if (result.missingErrorTypes.length === 0) return;
6504
6606
  const fixes = [];
6505
- if (ts.isExpression(valueNode) && result.expectedErrorType.flags & ts.TypeFlags.Never) {
6607
+ const catchAllErrorsName = typeParser.supportedEffect() === "v3" ? "catchAll" : "catch";
6608
+ if (ts.isExpression(valueNode) && result.expectedErrorType.flags & ts.TypeFlags.Never && catchAllErrorsName) {
6506
6609
  fixes.push({
6507
- fixName: "missingEffectError_catchAll",
6508
- description: "Catch all errors with Effect.catchAll",
6610
+ fixName: `missingEffectError_${catchAllErrorsName}`,
6611
+ description: `Catch all errors with Effect.${catchAllErrorsName}`,
6509
6612
  apply: gen(function* () {
6510
6613
  const changeTracker = yield* service(ChangeTracker);
6511
6614
  changeTracker.insertText(
6512
6615
  sourceFile,
6513
6616
  ts.getTokenPosOfNode(valueNode, sourceFile),
6514
- effectModuleIdentifier + ".catchAll("
6617
+ effectModuleIdentifier + `.${catchAllErrorsName}(`
6515
6618
  );
6516
6619
  changeTracker.insertText(sourceFile, valueNode.end, ", () => ");
6517
6620
  changeTracker.insertNodeAt(
6518
6621
  sourceFile,
6519
6622
  valueNode.end,
6520
- createDieMessage("TODO: catchAll not implemented")
6623
+ createDieMessage(`TODO: ${catchAllErrorsName} not implemented`)
6521
6624
  );
6522
6625
  changeTracker.insertText(sourceFile, valueNode.end, ")");
6523
6626
  })
@@ -6599,6 +6702,7 @@ var missingEffectServiceDependency = createDiagnostic({
6599
6702
  const typeChecker = yield* service(TypeCheckerApi);
6600
6703
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
6601
6704
  const typeParser = yield* service(TypeParser);
6705
+ if (typeParser.supportedEffect() !== "v3") return;
6602
6706
  const nodeToVisit = [];
6603
6707
  const appendNodeToVisit = (node) => {
6604
6708
  nodeToVisit.push(node);
@@ -8818,6 +8922,7 @@ var scopeInLayerEffect = createDiagnostic({
8818
8922
  const typeChecker = yield* service(TypeCheckerApi);
8819
8923
  const typeParser = yield* service(TypeParser);
8820
8924
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
8925
+ if (typeParser.supportedEffect() !== "v3") return;
8821
8926
  const layerModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
8822
8927
  sourceFile,
8823
8928
  "effect",
@@ -9026,6 +9131,17 @@ var tryCatchInEffectGen = createDiagnostic({
9026
9131
  apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
9027
9132
  const ts = yield* service(TypeScriptApi);
9028
9133
  const typeParser = yield* service(TypeParser);
9134
+ const alternatives = typeParser.supportedEffect() === "v4" ? [
9135
+ "Effect.try",
9136
+ "Effect.tryPromise",
9137
+ "Effect.catch",
9138
+ "Effect.catchTag"
9139
+ ] : [
9140
+ "Effect.try",
9141
+ "Effect.tryPromise",
9142
+ "Effect.catchAll",
9143
+ "Effect.catchTag"
9144
+ ];
9029
9145
  const nodeToVisit = [];
9030
9146
  const appendNodeToVisit = (node) => {
9031
9147
  nodeToVisit.push(node);
@@ -9051,7 +9167,7 @@ var tryCatchInEffectGen = createDiagnostic({
9051
9167
  map4(() => {
9052
9168
  report({
9053
9169
  location: node,
9054
- messageText: "Avoid using try/catch inside Effect generators. Use Effect's error handling mechanisms instead (e.g., Effect.try, Effect.tryPromise, Effect.catchAll, Effect.catchTag).",
9170
+ messageText: `Avoid using try/catch inside Effect generators. Use Effect's error handling mechanisms instead (e.g. ${alternatives.join(", ")}).`,
9055
9171
  fixes: []
9056
9172
  });
9057
9173
  }),
@@ -9073,6 +9189,7 @@ var unknownInEffectCatch = createDiagnostic({
9073
9189
  const ts = yield* service(TypeScriptApi);
9074
9190
  const typeParser = yield* service(TypeParser);
9075
9191
  const typeChecker = yield* service(TypeCheckerApi);
9192
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9076
9193
  const nodeToVisit = [];
9077
9194
  const appendNodeToVisit = (node) => {
9078
9195
  nodeToVisit.push(node);
@@ -9093,24 +9210,26 @@ var unknownInEffectCatch = createDiagnostic({
9093
9210
  if (isEffectWithCatch) {
9094
9211
  const signature = typeChecker.getResolvedSignature(node);
9095
9212
  if (signature) {
9096
- const objectType = typeChecker.getParameterType(signature, 0);
9097
- const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
9098
- if (catchFunctionSymbol) {
9099
- const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
9100
- const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
9101
- if (signatures.length > 0) {
9102
- const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
9103
- if (returnType && (returnType.flags & ts.TypeFlags.Unknown || returnType.flags & ts.TypeFlags.Any)) {
9104
- const nodeText = sourceFile.text.substring(
9105
- ts.getTokenPosOfNode(node.expression, sourceFile),
9106
- node.expression.end
9107
- );
9108
- report({
9109
- location: node.expression,
9110
- messageText: `The 'catch' callback in ${nodeText} returns 'unknown'. The catch callback should be used to provide typed errors.
9213
+ const parameterType = typeChecker.getParameterType(signature, 0);
9214
+ for (const objectType of typeCheckerUtils.unrollUnionMembers(parameterType)) {
9215
+ const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
9216
+ if (catchFunctionSymbol) {
9217
+ const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
9218
+ const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
9219
+ if (signatures.length > 0) {
9220
+ const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
9221
+ if (returnType && (returnType.flags & ts.TypeFlags.Unknown || returnType.flags & ts.TypeFlags.Any)) {
9222
+ const nodeText = sourceFile.text.substring(
9223
+ ts.getTokenPosOfNode(node.expression, sourceFile),
9224
+ node.expression.end
9225
+ );
9226
+ report({
9227
+ location: node.expression,
9228
+ messageText: `The 'catch' callback in ${nodeText} returns 'unknown'. The catch callback should be used to provide typed errors.
9111
9229
  Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
9112
- fixes: []
9113
- });
9230
+ fixes: []
9231
+ });
9232
+ }
9114
9233
  }
9115
9234
  }
9116
9235
  }