@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.
package/transform.js CHANGED
@@ -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");
@@ -2563,6 +2570,8 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
2563
2570
  }
2564
2571
 
2565
2572
  // src/core/TypeParser.ts
2573
+ var checkedPackagesCache = /* @__PURE__ */ new Map();
2574
+ var programResolvedCacheSize = /* @__PURE__ */ new Map();
2566
2575
  var TypeParser = Tag("@effect/language-service/TypeParser");
2567
2576
  var nanoLayer3 = (fa) => gen(function* () {
2568
2577
  const ts = yield* service(TypeScriptApi);
@@ -2583,6 +2592,42 @@ function typeParserIssue(_message, _type, _node) {
2583
2592
  return TypeParserIssue.issue;
2584
2593
  }
2585
2594
  function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2595
+ function supportedEffect() {
2596
+ for (const fileName of program.getRootFileNames()) {
2597
+ const sourceFile = program.getSourceFile(fileName);
2598
+ if (!sourceFile) continue;
2599
+ const resolvedPackages = getEffectRelatedPackages(sourceFile);
2600
+ const effectPkgs = resolvedPackages["effect"];
2601
+ if (!effectPkgs) continue;
2602
+ for (const version of Object.keys(effectPkgs)) {
2603
+ if (String(version).startsWith("4")) return "v4";
2604
+ if (String(version).startsWith("3")) return "v3";
2605
+ }
2606
+ }
2607
+ return "v3";
2608
+ }
2609
+ function getEffectRelatedPackages(sourceFile) {
2610
+ let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
2611
+ const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
2612
+ const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
2613
+ if (newResolvedModuleSize !== oldResolvedSize) {
2614
+ const seenPackages = /* @__PURE__ */ new Set();
2615
+ resolvedPackages = {};
2616
+ program.getSourceFiles().map((_) => {
2617
+ const packageInfo = tsUtils.parsePackageContentNameAndVersionFromScope(_);
2618
+ if (!packageInfo) return;
2619
+ const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
2620
+ if (seenPackages.has(packageNameAndVersion)) return;
2621
+ seenPackages.add(packageNameAndVersion);
2622
+ if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
2623
+ resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
2624
+ resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
2625
+ });
2626
+ checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
2627
+ programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
2628
+ }
2629
+ return resolvedPackages;
2630
+ }
2586
2631
  const getSourceFilePackageInfo = cachedBy(
2587
2632
  fn("TypeParser.getSourceFilePackageInfo")(function* (sourceFile) {
2588
2633
  return tsUtils.resolveModuleWithPackageInfoFromSourceFile(program, sourceFile);
@@ -2811,19 +2856,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2811
2856
  );
2812
2857
  const effectType = cachedBy(
2813
2858
  fn("TypeParser.effectType")(function* (type, atLocation) {
2814
- const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
2815
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
2816
- );
2817
- if (propertiesSymbols.length === 0) {
2818
- return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
2859
+ if (supportedEffect() === "v4") {
2860
+ const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Effect");
2861
+ if (typeIdSymbol) {
2862
+ const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
2863
+ return yield* effectVarianceStruct(typeIdType, atLocation);
2864
+ }
2865
+ return yield* typeParserIssue("Type is not an effect", type, atLocation);
2866
+ } else {
2867
+ const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
2868
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
2869
+ );
2870
+ if (propertiesSymbols.length === 0) {
2871
+ return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
2872
+ }
2873
+ propertiesSymbols.sort(
2874
+ (a, b) => ts.symbolName(b).indexOf("EffectTypeId") - ts.symbolName(a).indexOf("EffectTypeId")
2875
+ );
2876
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
2877
+ const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2878
+ return effectVarianceStruct(propertyType, atLocation);
2879
+ }));
2819
2880
  }
2820
- propertiesSymbols.sort(
2821
- (a, b) => ts.symbolName(b).indexOf("EffectTypeId") - ts.symbolName(a).indexOf("EffectTypeId")
2822
- );
2823
- return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
2824
- const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2825
- return effectVarianceStruct(propertyType, atLocation);
2826
- }));
2827
2881
  }),
2828
2882
  "TypeParser.effectType",
2829
2883
  (type) => type
@@ -2952,7 +3006,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2952
3006
  fn("TypeParser.isEffectDataSourceFile")(function* (sourceFile) {
2953
3007
  const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2954
3008
  if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2955
- const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol);
3009
+ const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol) || typeChecker.tryGetMemberInModuleExports("taggedEnum", moduleSymbol);
2956
3010
  if (!taggedEnumSymbol) return yield* typeParserIssue("TaggedEnum not found", void 0, sourceFile);
2957
3011
  const taggedErrorSymbol = typeChecker.tryGetMemberInModuleExports("TaggedError", moduleSymbol);
2958
3012
  if (!taggedErrorSymbol) return yield* typeParserIssue("TaggedError not found", void 0, sourceFile);
@@ -3143,10 +3197,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3143
3197
  }))
3144
3198
  )
3145
3199
  ),
3146
- option
3200
+ orUndefined
3147
3201
  );
3148
- if (isSome2(isEffectGen)) {
3149
- effectGenResult = isEffectGen.value;
3202
+ if (isEffectGen) {
3203
+ effectGenResult = isEffectGen;
3150
3204
  }
3151
3205
  }
3152
3206
  if (scopeNode && effectGenResult) {
@@ -3266,6 +3320,21 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3266
3320
  const effectSchemaType = cachedBy(
3267
3321
  fn("TypeParser.effectSchemaType")(function* (type, atLocation) {
3268
3322
  yield* pipeableType(type, atLocation);
3323
+ const typeId = typeChecker.getPropertyOfType(type, "~effect/Schema/Schema");
3324
+ if (typeId) {
3325
+ const typeKey = typeChecker.getPropertyOfType(type, "Type");
3326
+ const encodedKey = typeChecker.getPropertyOfType(type, "Encoded");
3327
+ if (typeKey && encodedKey) {
3328
+ const typeType = typeChecker.getTypeOfSymbolAtLocation(typeKey, atLocation);
3329
+ const encodedType = typeChecker.getTypeOfSymbolAtLocation(encodedKey, atLocation);
3330
+ return {
3331
+ A: typeType,
3332
+ I: encodedType,
3333
+ R: typeChecker.getNeverType()
3334
+ };
3335
+ }
3336
+ return yield* typeParserIssue("missing Type and Encoded");
3337
+ }
3269
3338
  const ast = typeChecker.getPropertyOfType(type, "ast");
3270
3339
  if (!ast) return yield* typeParserIssue("Has no 'ast' property", type, atLocation);
3271
3340
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
@@ -3484,9 +3553,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3484
3553
  if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
3485
3554
  const isEffectSchemaModuleApi = yield* pipe(
3486
3555
  isNodeReferenceToEffectSchemaModuleApi("Class")(schemaCall.expression),
3487
- option
3556
+ orUndefined
3488
3557
  );
3489
- if (isSome2(isEffectSchemaModuleApi)) {
3558
+ if (isEffectSchemaModuleApi) {
3490
3559
  return {
3491
3560
  className: atLocation.name,
3492
3561
  selfTypeNode: schemaCall.typeArguments[0]
@@ -3521,9 +3590,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3521
3590
  const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
3522
3591
  const isEffectSchemaModuleApi = yield* pipe(
3523
3592
  isNodeReferenceToEffectSchemaModuleApi("TaggedClass")(schemaTaggedClassTCall.expression),
3524
- option
3593
+ orUndefined
3525
3594
  );
3526
- if (isSome2(isEffectSchemaModuleApi)) {
3595
+ if (isEffectSchemaModuleApi) {
3527
3596
  return {
3528
3597
  className: atLocation.name,
3529
3598
  selfTypeNode,
@@ -3560,9 +3629,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3560
3629
  const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
3561
3630
  const isEffectSchemaModuleApi = yield* pipe(
3562
3631
  isNodeReferenceToEffectSchemaModuleApi("TaggedError")(schemaTaggedErrorTCall.expression),
3563
- option
3632
+ orUndefined
3564
3633
  );
3565
- if (isSome2(isEffectSchemaModuleApi)) {
3634
+ if (isEffectSchemaModuleApi) {
3566
3635
  return {
3567
3636
  className: atLocation.name,
3568
3637
  selfTypeNode,
@@ -3582,6 +3651,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3582
3651
  );
3583
3652
  const extendsSchemaTaggedRequest = cachedBy(
3584
3653
  fn("TypeParser.extendsSchemaTaggedRequest")(function* (atLocation) {
3654
+ if (supportedEffect() === "v4") {
3655
+ return yield* typeParserIssue("Schema.TaggedClass is not supported in Effect v4", void 0, atLocation);
3656
+ }
3585
3657
  if (!atLocation.name) {
3586
3658
  return yield* typeParserIssue("Class has no name", void 0, atLocation);
3587
3659
  }
@@ -3599,9 +3671,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3599
3671
  const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3600
3672
  const isEffectSchemaModuleApi = yield* pipe(
3601
3673
  isNodeReferenceToEffectSchemaModuleApi("TaggedRequest")(schemaTaggedRequestTCall.expression),
3602
- option
3674
+ orUndefined
3603
3675
  );
3604
- if (isSome2(isEffectSchemaModuleApi)) {
3676
+ if (isEffectSchemaModuleApi) {
3605
3677
  return {
3606
3678
  className: atLocation.name,
3607
3679
  selfTypeNode,
@@ -3619,6 +3691,48 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3619
3691
  "TypeParser.extendsSchemaTaggedRequest",
3620
3692
  (atLocation) => atLocation
3621
3693
  );
3694
+ const extendsSchemaRequestClass = cachedBy(
3695
+ fn("TypeParser.extendsSchemaRequestClass")(function* (atLocation) {
3696
+ if (supportedEffect() === "v3") {
3697
+ return yield* typeParserIssue("Schema.RequestClass is not supported in Effect v3", void 0, atLocation);
3698
+ }
3699
+ if (!atLocation.name) {
3700
+ return yield* typeParserIssue("Class has no name", void 0, atLocation);
3701
+ }
3702
+ const heritageClauses = atLocation.heritageClauses;
3703
+ if (!heritageClauses) {
3704
+ return yield* typeParserIssue("Class has no heritage clauses", void 0, atLocation);
3705
+ }
3706
+ for (const heritageClause of heritageClauses) {
3707
+ for (const typeX of heritageClause.types) {
3708
+ if (ts.isExpressionWithTypeArguments(typeX)) {
3709
+ const expression = typeX.expression;
3710
+ if (ts.isCallExpression(expression)) {
3711
+ const schemaTaggedRequestTCall = expression.expression;
3712
+ if (ts.isCallExpression(schemaTaggedRequestTCall) && schemaTaggedRequestTCall.typeArguments && schemaTaggedRequestTCall.typeArguments.length > 0) {
3713
+ const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3714
+ const isEffectSchemaModuleApi = yield* pipe(
3715
+ isNodeReferenceToEffectSchemaModuleApi("RequestClass")(schemaTaggedRequestTCall.expression),
3716
+ orUndefined
3717
+ );
3718
+ if (isEffectSchemaModuleApi) {
3719
+ return {
3720
+ className: atLocation.name,
3721
+ selfTypeNode,
3722
+ tagStringLiteral: void 0,
3723
+ keyStringLiteral: schemaTaggedRequestTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedRequestTCall.arguments[0]) ? schemaTaggedRequestTCall.arguments[0] : void 0
3724
+ };
3725
+ }
3726
+ }
3727
+ }
3728
+ }
3729
+ }
3730
+ }
3731
+ return yield* typeParserIssue("Class does not extend Schema.RequestClass", void 0, atLocation);
3732
+ }),
3733
+ "TypeParser.extendsSchemaRequestClass",
3734
+ (atLocation) => atLocation
3735
+ );
3622
3736
  const extendsDataTaggedError = cachedBy(
3623
3737
  fn("TypeParser.extendsDataTaggedError")(function* (atLocation) {
3624
3738
  if (!atLocation.name) {
@@ -3638,13 +3752,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3638
3752
  if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedError") {
3639
3753
  const parsedDataModule = yield* pipe(
3640
3754
  importedDataModule(dataIdentifier.expression),
3641
- option
3755
+ orUndefined
3642
3756
  );
3643
- if (isSome2(parsedDataModule)) {
3757
+ if (parsedDataModule) {
3644
3758
  return {
3645
3759
  className: atLocation.name,
3646
3760
  keyStringLiteral: dataTaggedErrorCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedErrorCall.arguments[0]) ? dataTaggedErrorCall.arguments[0] : void 0,
3647
- Data: parsedDataModule.value
3761
+ Data: parsedDataModule
3648
3762
  };
3649
3763
  }
3650
3764
  }
@@ -3676,13 +3790,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3676
3790
  if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedClass") {
3677
3791
  const parsedDataModule = yield* pipe(
3678
3792
  importedDataModule(dataIdentifier.expression),
3679
- option
3793
+ orUndefined
3680
3794
  );
3681
- if (isSome2(parsedDataModule)) {
3795
+ if (parsedDataModule) {
3682
3796
  return {
3683
3797
  className: atLocation.name,
3684
3798
  keyStringLiteral: dataTaggedClassCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedClassCall.arguments[0]) ? dataTaggedClassCall.arguments[0] : void 0,
3685
- Data: parsedDataModule.value
3799
+ Data: parsedDataModule
3686
3800
  };
3687
3801
  }
3688
3802
  }
@@ -3716,9 +3830,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3716
3830
  if (ts.isPropertyAccessExpression(contextTagIdentifier) && ts.isIdentifier(contextTagIdentifier.name) && ts.idText(contextTagIdentifier.name) === "Tag") {
3717
3831
  const parsedContextModule = yield* pipe(
3718
3832
  importedContextModule(contextTagIdentifier.expression),
3719
- option
3833
+ orUndefined
3720
3834
  );
3721
- if (isSome2(parsedContextModule)) {
3835
+ if (parsedContextModule) {
3722
3836
  const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3723
3837
  if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3724
3838
  const type = typeChecker.getTypeOfSymbol(classSym);
@@ -3729,7 +3843,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3729
3843
  keyStringLiteral: ts.isStringLiteral(contextTagCall.arguments[0]) ? contextTagCall.arguments[0] : void 0,
3730
3844
  args: contextTagCall.arguments,
3731
3845
  Identifier: tagType.Identifier,
3732
- Tag: parsedContextModule.value
3846
+ Tag: parsedContextModule
3733
3847
  };
3734
3848
  }
3735
3849
  }
@@ -3767,9 +3881,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3767
3881
  const selfTypeNode = wholeCall.typeArguments[0];
3768
3882
  const isEffectTag = yield* pipe(
3769
3883
  isNodeReferenceToEffectModuleApi("Tag")(effectTagIdentifier),
3770
- option
3884
+ orUndefined
3771
3885
  );
3772
- if (isSome2(isEffectTag)) {
3886
+ if (isEffectTag) {
3773
3887
  return {
3774
3888
  className: atLocation.name,
3775
3889
  selfTypeNode,
@@ -3809,17 +3923,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3809
3923
  const selfTypeNode = effectServiceCall.typeArguments[0];
3810
3924
  const isEffectService = yield* pipe(
3811
3925
  isNodeReferenceToEffectModuleApi("Service")(effectServiceIdentifier),
3812
- option
3926
+ orUndefined
3813
3927
  );
3814
- if (isSome2(isEffectService)) {
3928
+ if (isEffectService) {
3815
3929
  const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3816
3930
  if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3817
3931
  const type = typeChecker.getTypeOfSymbol(classSym);
3818
3932
  const parsedContextTag = yield* pipe(
3819
3933
  contextTag(type, atLocation),
3820
- option
3934
+ orUndefined
3821
3935
  );
3822
- if (isSome2(parsedContextTag)) {
3936
+ if (parsedContextTag) {
3823
3937
  let accessors2 = void 0;
3824
3938
  let dependencies = void 0;
3825
3939
  if (wholeCall.arguments.length >= 2) {
@@ -3836,7 +3950,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3836
3950
  }
3837
3951
  }
3838
3952
  return {
3839
- ...parsedContextTag.value,
3953
+ ...parsedContextTag,
3840
3954
  className: atLocation.name,
3841
3955
  selfTypeNode,
3842
3956
  args: wholeCall.arguments,
@@ -3906,9 +4020,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3906
4020
  if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
3907
4021
  const isEffectSchemaModuleApi = yield* pipe(
3908
4022
  isNodeReferenceToEffectSqlModelModuleApi("Class")(schemaCall.expression),
3909
- option
4023
+ orUndefined
3910
4024
  );
3911
- if (isSome2(isEffectSchemaModuleApi)) {
4025
+ if (isEffectSchemaModuleApi) {
3912
4026
  return {
3913
4027
  className: atLocation.name,
3914
4028
  selfTypeNode: schemaCall.typeArguments[0]
@@ -4031,19 +4145,18 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4031
4145
  map4((s) => ({ _tag: "call", ...s }))
4032
4146
  )
4033
4147
  ),
4034
- option
4148
+ orUndefined
4035
4149
  );
4036
- if (isSome2(parsed)) {
4037
- const result2 = parsed.value;
4150
+ if (parsed) {
4038
4151
  let transformations;
4039
4152
  let flowNode;
4040
4153
  let childrenToTraverse = [];
4041
- if (result2._tag === "pipe") {
4042
- const signature = typeChecker.getResolvedSignature(result2.node);
4154
+ if (parsed._tag === "pipe") {
4155
+ const signature = typeChecker.getResolvedSignature(parsed.node);
4043
4156
  const typeArguments = signature ? typeChecker.getTypeArgumentsForResolvedSignature(signature) : void 0;
4044
4157
  transformations = [];
4045
- for (let i = 0; i < result2.args.length; i++) {
4046
- const arg = result2.args[i];
4158
+ for (let i = 0; i < parsed.args.length; i++) {
4159
+ const arg = parsed.args[i];
4047
4160
  const outType = typeArguments?.[i + 1];
4048
4161
  if (ts.isCallExpression(arg)) {
4049
4162
  transformations.push({
@@ -4052,7 +4165,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4052
4165
  args: Array.from(arg.arguments),
4053
4166
  // e.g., [(x) => x + 1]
4054
4167
  outType,
4055
- kind: result2.kind
4168
+ kind: parsed.kind
4056
4169
  });
4057
4170
  } else {
4058
4171
  transformations.push({
@@ -4060,17 +4173,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4060
4173
  // e.g., Effect.asVoid
4061
4174
  args: void 0,
4062
4175
  outType,
4063
- kind: result2.kind
4176
+ kind: parsed.kind
4064
4177
  });
4065
4178
  }
4066
4179
  }
4067
- flowNode = result2.node;
4068
- childrenToTraverse = result2.args;
4180
+ flowNode = parsed.node;
4181
+ childrenToTraverse = parsed.args;
4069
4182
  } else {
4070
4183
  const callSignature = typeChecker.getResolvedSignature(node);
4071
4184
  const outType = callSignature ? typeChecker.getReturnTypeOfSignature(callSignature) : void 0;
4072
4185
  transformations = [{
4073
- callee: result2.callee,
4186
+ callee: parsed.callee,
4074
4187
  args: void 0,
4075
4188
  outType,
4076
4189
  kind: "call"
@@ -4080,20 +4193,20 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4080
4193
  if (parentFlow) {
4081
4194
  parentFlow.transformations.unshift(...transformations);
4082
4195
  parentFlow.subject = {
4083
- node: result2.subject,
4084
- outType: typeCheckerUtils.getTypeAtLocation(result2.subject)
4196
+ node: parsed.subject,
4197
+ outType: typeCheckerUtils.getTypeAtLocation(parsed.subject)
4085
4198
  };
4086
- workQueue.push([result2.subject, parentFlow]);
4199
+ workQueue.push([parsed.subject, parentFlow]);
4087
4200
  } else {
4088
4201
  const newFlow = {
4089
4202
  node: flowNode,
4090
4203
  subject: {
4091
- node: result2.subject,
4092
- outType: typeCheckerUtils.getTypeAtLocation(result2.subject)
4204
+ node: parsed.subject,
4205
+ outType: typeCheckerUtils.getTypeAtLocation(parsed.subject)
4093
4206
  },
4094
4207
  transformations
4095
4208
  };
4096
- workQueue.push([result2.subject, newFlow]);
4209
+ workQueue.push([parsed.subject, newFlow]);
4097
4210
  }
4098
4211
  for (const child of childrenToTraverse) {
4099
4212
  ts.forEachChild(child, (c) => {
@@ -4103,17 +4216,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4103
4216
  continue;
4104
4217
  }
4105
4218
  if (includeEffectFn) {
4106
- const effectFnGenParsed = yield* pipe(effectFnGen(node), option);
4107
- const effectFnUntracedGenParsed = isNone2(effectFnGenParsed) ? yield* pipe(effectFnUntracedGen(node), option) : none2();
4108
- const effectFnNonGenParsed = isNone2(effectFnGenParsed) && isNone2(effectFnUntracedGenParsed) ? yield* pipe(effectFn(node), option) : none2();
4109
- const isEffectFnGen = isSome2(effectFnGenParsed);
4110
- const isEffectFnUntracedGen = isSome2(effectFnUntracedGenParsed);
4111
- const isEffectFnNonGen = isSome2(effectFnNonGenParsed);
4112
- const transformationKind = isEffectFnUntracedGen ? "effectFnUntraced" : "effectFn";
4113
- if (isEffectFnGen || isEffectFnUntracedGen) {
4114
- const effectFnParsed = isEffectFnGen ? effectFnGenParsed : effectFnUntracedGenParsed;
4115
- if (isSome2(effectFnParsed) && effectFnParsed.value.pipeArguments.length > 0) {
4116
- const fnResult = effectFnParsed.value;
4219
+ const effectFnKind = yield* pipe(
4220
+ map4(effectFnGen(node), (_) => ({ kind: "effectFnGen", ..._ })),
4221
+ orElse2(
4222
+ () => map4(effectFnUntracedGen(node), (_) => ({ kind: "effectFnUntracedGen", ..._ }))
4223
+ ),
4224
+ orElse2(() => map4(effectFn(node), (_) => ({ kind: "effectFn", ..._ }))),
4225
+ orUndefined
4226
+ );
4227
+ if (effectFnKind && (effectFnKind.kind === "effectFnGen" || effectFnKind.kind === "effectFnUntracedGen")) {
4228
+ if (effectFnKind.pipeArguments.length > 0) {
4229
+ const fnResult = effectFnKind;
4117
4230
  const pipeArgs = fnResult.pipeArguments;
4118
4231
  const transformations = [];
4119
4232
  let subjectType;
@@ -4133,14 +4246,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4133
4246
  callee: arg.expression,
4134
4247
  args: Array.from(arg.arguments),
4135
4248
  outType,
4136
- kind: transformationKind
4249
+ kind: effectFnKind.kind === "effectFnUntracedGen" ? "effectFnUntraced" : "effectFn"
4137
4250
  });
4138
4251
  } else {
4139
4252
  transformations.push({
4140
4253
  callee: arg,
4141
4254
  args: void 0,
4142
4255
  outType,
4143
- kind: transformationKind
4256
+ kind: effectFnKind.kind === "effectFnUntracedGen" ? "effectFnUntraced" : "effectFn"
4144
4257
  });
4145
4258
  }
4146
4259
  }
@@ -4162,8 +4275,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4162
4275
  continue;
4163
4276
  }
4164
4277
  }
4165
- if (isEffectFnNonGen && isSome2(effectFnNonGenParsed) && effectFnNonGenParsed.value.pipeArguments.length > 0) {
4166
- const fnResult = effectFnNonGenParsed.value;
4278
+ if (effectFnKind && effectFnKind.kind === "effectFn" && effectFnKind.pipeArguments.length > 0) {
4279
+ const fnResult = effectFnKind;
4167
4280
  const pipeArgs = fnResult.pipeArguments;
4168
4281
  const transformations = [];
4169
4282
  let subjectType;
@@ -4309,11 +4422,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4309
4422
  extendsDataTaggedError,
4310
4423
  extendsDataTaggedClass,
4311
4424
  extendsSchemaTaggedRequest,
4425
+ extendsSchemaRequestClass,
4312
4426
  extendsEffectSqlModelClass,
4313
4427
  lazyExpression,
4314
4428
  emptyFunction,
4315
4429
  pipingFlows,
4316
- reconstructPipingFlow
4430
+ reconstructPipingFlow,
4431
+ getEffectRelatedPackages,
4432
+ supportedEffect
4317
4433
  };
4318
4434
  }
4319
4435
 
@@ -4429,6 +4545,7 @@ var catchAllToMapError = createDiagnostic({
4429
4545
  apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
4430
4546
  const ts = yield* service(TypeScriptApi);
4431
4547
  const typeParser = yield* service(TypeParser);
4548
+ const catchAllName = typeParser.supportedEffect() === "v3" ? "catchAll" : "catch";
4432
4549
  const getFunctionBody = (node) => {
4433
4550
  if (ts.isArrowFunction(node)) {
4434
4551
  return node.body;
@@ -4443,10 +4560,10 @@ var catchAllToMapError = createDiagnostic({
4443
4560
  if (ts.isCallExpression(body)) {
4444
4561
  const isFailCall = yield* pipe(
4445
4562
  typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4446
- option
4563
+ orUndefined
4447
4564
  );
4448
- if (isSome2(isFailCall) && body.arguments.length >= 1) {
4449
- return some2({ failCall: body, failArg: body.arguments[0] });
4565
+ if (isFailCall && body.arguments.length >= 1) {
4566
+ return { failCall: body, failArg: body.arguments[0] };
4450
4567
  }
4451
4568
  }
4452
4569
  if (ts.isBlock(body)) {
@@ -4456,15 +4573,14 @@ var catchAllToMapError = createDiagnostic({
4456
4573
  if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4457
4574
  const isFailCall = yield* pipe(
4458
4575
  typeParser.isNodeReferenceToEffectModuleApi("fail")(stmt.expression.expression),
4459
- option
4576
+ orUndefined
4460
4577
  );
4461
- if (isSome2(isFailCall) && stmt.expression.arguments.length >= 1) {
4462
- return some2({ failCall: stmt.expression, failArg: stmt.expression.arguments[0] });
4578
+ if (isFailCall && stmt.expression.arguments.length >= 1) {
4579
+ return { failCall: stmt.expression, failArg: stmt.expression.arguments[0] };
4463
4580
  }
4464
4581
  }
4465
4582
  }
4466
4583
  }
4467
- return none2();
4468
4584
  });
4469
4585
  };
4470
4586
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
@@ -4474,10 +4590,10 @@ var catchAllToMapError = createDiagnostic({
4474
4590
  continue;
4475
4591
  }
4476
4592
  const isCatchAllCall = yield* pipe(
4477
- typeParser.isNodeReferenceToEffectModuleApi("catchAll")(transformation.callee),
4478
- option
4593
+ typeParser.isNodeReferenceToEffectModuleApi(catchAllName)(transformation.callee),
4594
+ orUndefined
4479
4595
  );
4480
- if (isNone2(isCatchAllCall)) {
4596
+ if (!isCatchAllCall) {
4481
4597
  continue;
4482
4598
  }
4483
4599
  const callback = transformation.args[0];
@@ -4485,11 +4601,11 @@ var catchAllToMapError = createDiagnostic({
4485
4601
  const functionBody = getFunctionBody(callback);
4486
4602
  if (!functionBody) continue;
4487
4603
  const failCallInfo = yield* getEffectFailCallInfo(functionBody);
4488
- if (isNone2(failCallInfo)) continue;
4489
- const { failArg, failCall } = failCallInfo.value;
4604
+ if (!failCallInfo) continue;
4605
+ const { failArg, failCall } = failCallInfo;
4490
4606
  report({
4491
4607
  location: transformation.callee,
4492
- messageText: `You can use Effect.mapError instead of Effect.catchAll + Effect.fail to transform the error type.`,
4608
+ messageText: `You can use Effect.mapError instead of Effect.${catchAllName} + Effect.fail to transform the error type.`,
4493
4609
  fixes: [{
4494
4610
  fixName: "catchAllToMapError_fix",
4495
4611
  description: "Replace with Effect.mapError",
@@ -4520,7 +4636,7 @@ var catchUnfailableEffect = createDiagnostic({
4520
4636
  apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
4521
4637
  const ts = yield* service(TypeScriptApi);
4522
4638
  const typeParser = yield* service(TypeParser);
4523
- const catchFunctions = ["catchAll", "catch", "catchIf", "catchSome", "catchTag", "catchTags"];
4639
+ const catchFunctions = typeParser.supportedEffect() === "v3" ? ["catchAll", "catch", "catchIf", "catchSome", "catchTag", "catchTags"] : ["catch", "catchIf", "catchTag", "catchTags"];
4524
4640
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
4525
4641
  for (const flow2 of flows) {
4526
4642
  for (let i = 0; i < flow2.transformations.length; i++) {
@@ -4585,7 +4701,12 @@ var classSelfMismatch = createDiagnostic({
4585
4701
  orElse2(() => typeParser.extendsSchemaClass(node)),
4586
4702
  orElse2(() => typeParser.extendsSchemaTaggedClass(node)),
4587
4703
  orElse2(() => typeParser.extendsSchemaTaggedError(node)),
4588
- orElse2(() => typeParser.extendsSchemaTaggedRequest(node)),
4704
+ orElse2(
4705
+ () => pipe(
4706
+ typeParser.extendsSchemaTaggedRequest(node),
4707
+ orElse2(() => typeParser.extendsSchemaRequestClass(node))
4708
+ )
4709
+ ),
4589
4710
  orElse2(() => typeParser.extendsEffectSqlModelClass(node)),
4590
4711
  orElse2(() => void_)
4591
4712
  );
@@ -4812,39 +4933,18 @@ var deterministicKeys = createDiagnostic({
4812
4933
  });
4813
4934
 
4814
4935
  // src/diagnostics/duplicatePackage.ts
4815
- var checkedPackagesCache = /* @__PURE__ */ new Map();
4816
- var programResolvedCacheSize = /* @__PURE__ */ new Map();
4817
4936
  var duplicatePackage = createDiagnostic({
4818
4937
  name: "duplicatePackage",
4819
4938
  code: 6,
4820
4939
  description: "Detects when multiple versions of the same Effect package are loaded",
4821
4940
  severity: "warning",
4822
4941
  apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
4823
- const program = yield* service(TypeScriptProgram);
4824
- const tsUtils = yield* service(TypeScriptUtils);
4942
+ const typeParser = yield* service(TypeParser);
4825
4943
  const options = yield* service(LanguageServicePluginOptions);
4826
4944
  if (sourceFile.statements.length < 1) return;
4827
- let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
4828
- const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
4829
- const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
4830
- if (newResolvedModuleSize !== oldResolvedSize) {
4831
- const seenPackages = /* @__PURE__ */ new Set();
4832
- resolvedPackages = {};
4833
- program.getSourceFiles().map((_) => {
4834
- const packageInfo = tsUtils.parsePackageContentNameAndVersionFromScope(_);
4835
- if (!packageInfo) return;
4836
- const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
4837
- if (seenPackages.has(packageNameAndVersion)) return;
4838
- seenPackages.add(packageNameAndVersion);
4839
- if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
4840
- if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
4841
- resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
4842
- resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
4843
- });
4844
- checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
4845
- programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
4846
- }
4945
+ const resolvedPackages = typeParser.getEffectRelatedPackages(sourceFile);
4847
4946
  for (const packageName of Object.keys(resolvedPackages)) {
4947
+ if (options.allowedDuplicatedPackages.indexOf(packageName) > -1) return;
4848
4948
  if (Object.keys(resolvedPackages[packageName]).length > 1) {
4849
4949
  const versions = Object.keys(resolvedPackages[packageName]);
4850
4950
  report({
@@ -5668,23 +5768,25 @@ var globalErrorInEffectCatch = createDiagnostic({
5668
5768
  if (isEffectWithCatch) {
5669
5769
  const signature = typeChecker.getResolvedSignature(node);
5670
5770
  if (signature) {
5671
- const objectType = typeChecker.getParameterType(signature, 0);
5672
- const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
5673
- if (catchFunctionSymbol) {
5674
- const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
5675
- const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
5676
- if (signatures.length > 0) {
5677
- const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
5678
- if (returnType && typeCheckerUtils.isGlobalErrorType(returnType)) {
5679
- const nodeText = sourceFile.text.substring(
5680
- ts.getTokenPosOfNode(node.expression, sourceFile),
5681
- node.expression.end
5682
- );
5683
- report({
5684
- location: node.expression,
5685
- 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.`,
5686
- fixes: []
5687
- });
5771
+ const firstParameterType = typeChecker.getParameterType(signature, 0);
5772
+ for (const objectType of typeCheckerUtils.unrollUnionMembers(firstParameterType)) {
5773
+ const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
5774
+ if (catchFunctionSymbol) {
5775
+ const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
5776
+ const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
5777
+ if (signatures.length > 0) {
5778
+ const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
5779
+ if (returnType && typeCheckerUtils.isGlobalErrorType(returnType)) {
5780
+ const nodeText = sourceFile.text.substring(
5781
+ ts.getTokenPosOfNode(node.expression, sourceFile),
5782
+ node.expression.end
5783
+ );
5784
+ report({
5785
+ location: node.expression,
5786
+ 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.`,
5787
+ fixes: []
5788
+ });
5789
+ }
5688
5790
  }
5689
5791
  }
5690
5792
  }
@@ -6497,22 +6599,23 @@ var missingEffectError = createDiagnostic({
6497
6599
  map4((result) => {
6498
6600
  if (result.missingErrorTypes.length === 0) return;
6499
6601
  const fixes = [];
6500
- if (ts.isExpression(valueNode) && result.expectedErrorType.flags & ts.TypeFlags.Never) {
6602
+ const catchAllErrorsName = typeParser.supportedEffect() === "v3" ? "catchAll" : "catch";
6603
+ if (ts.isExpression(valueNode) && result.expectedErrorType.flags & ts.TypeFlags.Never && catchAllErrorsName) {
6501
6604
  fixes.push({
6502
- fixName: "missingEffectError_catchAll",
6503
- description: "Catch all errors with Effect.catchAll",
6605
+ fixName: `missingEffectError_${catchAllErrorsName}`,
6606
+ description: `Catch all errors with Effect.${catchAllErrorsName}`,
6504
6607
  apply: gen(function* () {
6505
6608
  const changeTracker = yield* service(ChangeTracker);
6506
6609
  changeTracker.insertText(
6507
6610
  sourceFile,
6508
6611
  ts.getTokenPosOfNode(valueNode, sourceFile),
6509
- effectModuleIdentifier + ".catchAll("
6612
+ effectModuleIdentifier + `.${catchAllErrorsName}(`
6510
6613
  );
6511
6614
  changeTracker.insertText(sourceFile, valueNode.end, ", () => ");
6512
6615
  changeTracker.insertNodeAt(
6513
6616
  sourceFile,
6514
6617
  valueNode.end,
6515
- createDieMessage("TODO: catchAll not implemented")
6618
+ createDieMessage(`TODO: ${catchAllErrorsName} not implemented`)
6516
6619
  );
6517
6620
  changeTracker.insertText(sourceFile, valueNode.end, ")");
6518
6621
  })
@@ -6594,6 +6697,7 @@ var missingEffectServiceDependency = createDiagnostic({
6594
6697
  const typeChecker = yield* service(TypeCheckerApi);
6595
6698
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
6596
6699
  const typeParser = yield* service(TypeParser);
6700
+ if (typeParser.supportedEffect() !== "v3") return;
6597
6701
  const nodeToVisit = [];
6598
6702
  const appendNodeToVisit = (node) => {
6599
6703
  nodeToVisit.push(node);
@@ -8813,6 +8917,7 @@ var scopeInLayerEffect = createDiagnostic({
8813
8917
  const typeChecker = yield* service(TypeCheckerApi);
8814
8918
  const typeParser = yield* service(TypeParser);
8815
8919
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
8920
+ if (typeParser.supportedEffect() !== "v3") return;
8816
8921
  const layerModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
8817
8922
  sourceFile,
8818
8923
  "effect",
@@ -9021,6 +9126,17 @@ var tryCatchInEffectGen = createDiagnostic({
9021
9126
  apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
9022
9127
  const ts = yield* service(TypeScriptApi);
9023
9128
  const typeParser = yield* service(TypeParser);
9129
+ const alternatives = typeParser.supportedEffect() === "v4" ? [
9130
+ "Effect.try",
9131
+ "Effect.tryPromise",
9132
+ "Effect.catch",
9133
+ "Effect.catchTag"
9134
+ ] : [
9135
+ "Effect.try",
9136
+ "Effect.tryPromise",
9137
+ "Effect.catchAll",
9138
+ "Effect.catchTag"
9139
+ ];
9024
9140
  const nodeToVisit = [];
9025
9141
  const appendNodeToVisit = (node) => {
9026
9142
  nodeToVisit.push(node);
@@ -9046,7 +9162,7 @@ var tryCatchInEffectGen = createDiagnostic({
9046
9162
  map4(() => {
9047
9163
  report({
9048
9164
  location: node,
9049
- 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).",
9165
+ messageText: `Avoid using try/catch inside Effect generators. Use Effect's error handling mechanisms instead (e.g. ${alternatives.join(", ")}).`,
9050
9166
  fixes: []
9051
9167
  });
9052
9168
  }),
@@ -9068,6 +9184,7 @@ var unknownInEffectCatch = createDiagnostic({
9068
9184
  const ts = yield* service(TypeScriptApi);
9069
9185
  const typeParser = yield* service(TypeParser);
9070
9186
  const typeChecker = yield* service(TypeCheckerApi);
9187
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9071
9188
  const nodeToVisit = [];
9072
9189
  const appendNodeToVisit = (node) => {
9073
9190
  nodeToVisit.push(node);
@@ -9088,24 +9205,26 @@ var unknownInEffectCatch = createDiagnostic({
9088
9205
  if (isEffectWithCatch) {
9089
9206
  const signature = typeChecker.getResolvedSignature(node);
9090
9207
  if (signature) {
9091
- const objectType = typeChecker.getParameterType(signature, 0);
9092
- const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
9093
- if (catchFunctionSymbol) {
9094
- const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
9095
- const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
9096
- if (signatures.length > 0) {
9097
- const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
9098
- if (returnType && (returnType.flags & ts.TypeFlags.Unknown || returnType.flags & ts.TypeFlags.Any)) {
9099
- const nodeText = sourceFile.text.substring(
9100
- ts.getTokenPosOfNode(node.expression, sourceFile),
9101
- node.expression.end
9102
- );
9103
- report({
9104
- location: node.expression,
9105
- messageText: `The 'catch' callback in ${nodeText} returns 'unknown'. The catch callback should be used to provide typed errors.
9208
+ const parameterType = typeChecker.getParameterType(signature, 0);
9209
+ for (const objectType of typeCheckerUtils.unrollUnionMembers(parameterType)) {
9210
+ const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
9211
+ if (catchFunctionSymbol) {
9212
+ const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
9213
+ const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
9214
+ if (signatures.length > 0) {
9215
+ const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
9216
+ if (returnType && (returnType.flags & ts.TypeFlags.Unknown || returnType.flags & ts.TypeFlags.Any)) {
9217
+ const nodeText = sourceFile.text.substring(
9218
+ ts.getTokenPosOfNode(node.expression, sourceFile),
9219
+ node.expression.end
9220
+ );
9221
+ report({
9222
+ location: node.expression,
9223
+ messageText: `The 'catch' callback in ${nodeText} returns 'unknown'. The catch callback should be used to provide typed errors.
9106
9224
  Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
9107
- fixes: []
9108
- });
9225
+ fixes: []
9226
+ });
9227
+ }
9109
9228
  }
9110
9229
  }
9111
9230
  }