@effect/language-service 0.51.1 → 0.52.1

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.
@@ -2455,9 +2455,10 @@ var nanoLayer3 = (fa) => gen(function* () {
2455
2455
  const tsUtils = yield* service(TypeScriptUtils);
2456
2456
  const typeChecker = yield* service(TypeCheckerApi);
2457
2457
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
2458
+ const program = yield* service(TypeScriptProgram);
2458
2459
  return yield* pipe(
2459
2460
  fa,
2460
- provideService(TypeParser, make2(ts, tsUtils, typeChecker, typeCheckerUtils))
2461
+ provideService(TypeParser, make2(ts, tsUtils, typeChecker, typeCheckerUtils, program))
2461
2462
  );
2462
2463
  });
2463
2464
  var TypeParserIssue = class _TypeParserIssue {
@@ -2467,7 +2468,92 @@ var TypeParserIssue = class _TypeParserIssue {
2467
2468
  function typeParserIssue(_message, _type, _node) {
2468
2469
  return TypeParserIssue.issue;
2469
2470
  }
2470
- function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2471
+ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2472
+ const getSourceFilePackageInfo = cachedBy(
2473
+ fn("TypeParser.getSourceFilePackageInfo")(function* (sourceFile) {
2474
+ return tsUtils.resolveModuleWithPackageInfoFromSourceFile(program, sourceFile);
2475
+ }),
2476
+ `TypeParser.getSourceFilePackageInfo`,
2477
+ (sourceFile) => sourceFile
2478
+ );
2479
+ const getSourceFilesDeclaringSymbolModule = (packageName) => cachedBy(
2480
+ fn("TypeParser.getSourceFilesDeclaringSymbolModule")(function* (symbol3) {
2481
+ const result = [];
2482
+ if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
2483
+ for (const sourceFile of symbol3.declarations) {
2484
+ if (!ts.isSourceFile(sourceFile)) continue;
2485
+ const packageInfo = yield* getSourceFilePackageInfo(sourceFile);
2486
+ if (!packageInfo || packageInfo.name.toLowerCase() !== packageName.toLowerCase()) continue;
2487
+ result.push(sourceFile);
2488
+ }
2489
+ if (result.length > 0) {
2490
+ return result;
2491
+ }
2492
+ return yield* typeParserIssue(`Symbol has no source file declarations`, void 0, void 0);
2493
+ }),
2494
+ `TypeParser.getSourceFilesDeclaringSymbolModule(${packageName})`,
2495
+ (symbol3) => symbol3
2496
+ );
2497
+ const isSymbolReferenceToPackageModule = (givenSymbol, packageName, checkSourceFile) => {
2498
+ let symbol3 = givenSymbol;
2499
+ while (symbol3.flags & ts.SymbolFlags.Alias) {
2500
+ symbol3 = typeChecker.getAliasedSymbol(symbol3);
2501
+ }
2502
+ return pipe(
2503
+ getSourceFilesDeclaringSymbolModule(packageName)(symbol3),
2504
+ flatMap2(
2505
+ (sourceFiles) => firstSuccessOf(
2506
+ sourceFiles.map((_) => checkSourceFile(_))
2507
+ )
2508
+ )
2509
+ );
2510
+ };
2511
+ const isNodeReferenceToPackageModule = (givenNode, packageName, isCorrectSourceFile) => {
2512
+ const symbol3 = typeChecker.getSymbolAtLocation(givenNode);
2513
+ if (!symbol3) return typeParserIssue("Node has no symbol", void 0, givenNode);
2514
+ return isSymbolReferenceToPackageModule(symbol3, packageName, isCorrectSourceFile);
2515
+ };
2516
+ const getSourceFilesDeclaringSymbolExportedUnderPackageModule = (packageName, memberName) => cachedBy(
2517
+ fn("TypeParser.getSourceFilesDeclaringSymbolUnderPackageExportedMember")(function* (symbol3) {
2518
+ const result = [];
2519
+ if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
2520
+ for (const declaration of symbol3.declarations) {
2521
+ const sourceFile = tsUtils.getSourceFileOfNode(declaration);
2522
+ if (!sourceFile) continue;
2523
+ const packageInfo = yield* getSourceFilePackageInfo(sourceFile);
2524
+ if (!packageInfo || packageInfo.name.toLowerCase() !== packageName.toLowerCase()) continue;
2525
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2526
+ if (!moduleSymbol) continue;
2527
+ const memberSymbol = typeChecker.tryGetMemberInModuleExports(memberName, moduleSymbol);
2528
+ if (memberSymbol && memberSymbol === symbol3) result.push({ memberSymbol, moduleSymbol, sourceFile });
2529
+ }
2530
+ if (result.length > 0) {
2531
+ return result;
2532
+ }
2533
+ return yield* typeParserIssue(`Symbol has no declarations`, void 0, void 0);
2534
+ }),
2535
+ `TypeParser.getSourceFilesDeclaringSymbolUnderPackageExportedMember(${packageName}, ${memberName})`,
2536
+ (sym) => sym
2537
+ );
2538
+ const isSymbolExportOfPackageModule = (givenSymbol, packageName, memberName, checkSourceFile) => {
2539
+ let symbol3 = givenSymbol;
2540
+ while (symbol3.flags & ts.SymbolFlags.Alias) {
2541
+ symbol3 = typeChecker.getAliasedSymbol(symbol3);
2542
+ }
2543
+ return pipe(
2544
+ getSourceFilesDeclaringSymbolExportedUnderPackageModule(packageName, memberName)(symbol3),
2545
+ flatMap2(
2546
+ (sourceFiles) => firstSuccessOf(
2547
+ sourceFiles.map((_) => checkSourceFile(_.sourceFile, _.moduleSymbol, _.memberSymbol))
2548
+ )
2549
+ )
2550
+ );
2551
+ };
2552
+ const isNodeReferenceToExportOfPackageModule = (givenNode, packageName, isCorrectSourceFile, memberName) => {
2553
+ const symbol3 = typeChecker.getSymbolAtLocation(givenNode);
2554
+ if (!symbol3) return typeParserIssue("Node has no symbol", void 0, givenNode);
2555
+ return isSymbolExportOfPackageModule(symbol3, packageName, memberName, isCorrectSourceFile);
2556
+ };
2471
2557
  function covariantTypeArgument(type) {
2472
2558
  const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
2473
2559
  if (signatures.length !== 1) {
@@ -2573,6 +2659,26 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2573
2659
  "TypeParser.strictEffectType",
2574
2660
  (type) => type
2575
2661
  );
2662
+ const isEffectTypeSourceFile = cachedBy(
2663
+ fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
2664
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2665
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2666
+ const effectTypeSymbol = typeChecker.tryGetMemberInModuleExports("Effect", moduleSymbol);
2667
+ if (!effectTypeSymbol) return yield* typeParserIssue("Effect type not found", void 0, sourceFile);
2668
+ const type = typeChecker.getDeclaredTypeOfSymbol(effectTypeSymbol);
2669
+ yield* effectType(type, sourceFile);
2670
+ return sourceFile;
2671
+ }),
2672
+ "TypeParser.isEffectTypeSourceFile",
2673
+ (sourceFile) => sourceFile
2674
+ );
2675
+ const isNodeReferenceToEffectModuleApi = (memberName) => cachedBy(
2676
+ fn("TypeParser.isNodeReferenceToEffectModuleApi")(function* (node) {
2677
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectTypeSourceFile, memberName);
2678
+ }),
2679
+ `TypeParser.isNodeReferenceToEffectModuleApi(${memberName})`,
2680
+ (node) => node
2681
+ );
2576
2682
  const layerType = cachedBy(
2577
2683
  fn("TypeParser.layerType")(function* (type, atLocation) {
2578
2684
  yield* pipeableType(type, atLocation);
@@ -2629,36 +2735,6 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2629
2735
  "TypeParser.effectSubtype",
2630
2736
  (type) => type
2631
2737
  );
2632
- const importedSchemaModule = cachedBy(
2633
- fn("TypeParser.importedSchemaModule")(function* (node) {
2634
- if (!ts.isIdentifier(node)) {
2635
- return yield* typeParserIssue("Node is not an expression", void 0, node);
2636
- }
2637
- const type = typeChecker.getTypeAtLocation(node);
2638
- const propertySymbol = typeChecker.getPropertyOfType(type, "Class");
2639
- if (!propertySymbol) {
2640
- return yield* typeParserIssue("Type has no 'Class' property", type, node);
2641
- }
2642
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2643
- if (!sourceFile) {
2644
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2645
- }
2646
- const schemaIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2647
- sourceFile,
2648
- "effect",
2649
- "Schema"
2650
- );
2651
- if (!schemaIdentifier) {
2652
- return yield* typeParserIssue("Schema module not found", void 0, node);
2653
- }
2654
- if (ts.idText(node) !== schemaIdentifier) {
2655
- return yield* typeParserIssue("Node is not a schema module reference", void 0, node);
2656
- }
2657
- return node;
2658
- }),
2659
- "TypeParser.importedSchemaModule",
2660
- (node) => node
2661
- );
2662
2738
  const importedContextModule = cachedBy(
2663
2739
  fn("TypeParser.importedContextModule")(function* (node) {
2664
2740
  const type = typeChecker.getTypeAtLocation(node);
@@ -2689,22 +2765,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2689
2765
  "TypeParser.importedContextModule",
2690
2766
  (node) => node
2691
2767
  );
2692
- const importedEffectModule = cachedBy(
2693
- fn("TypeParser.importedEffectModule")(function* (node) {
2694
- const type = typeChecker.getTypeAtLocation(node);
2695
- const propertySymbol = typeChecker.getPropertyOfType(type, "never");
2696
- if (!propertySymbol) {
2697
- return yield* typeParserIssue("Type has no 'never' property", type, node);
2698
- }
2699
- if (!ts.isExpression(node)) {
2700
- return yield* typeParserIssue("Node is not an expression", type, node);
2701
- }
2702
- const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, node);
2703
- yield* effectType(propertyType, node);
2704
- return node;
2705
- }),
2706
- "TypeParser.importedEffectModule",
2707
- (node) => node
2768
+ const importedEffectModule = (node) => pipe(
2769
+ isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2770
+ map4(() => node)
2708
2771
  );
2709
2772
  const importedDataModule = cachedBy(
2710
2773
  fn("TypeParser.importedDataModule")(function* (node) {
@@ -2755,14 +2818,11 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2755
2818
  return typeParserIssue("Node is not a property access expression", void 0, node);
2756
2819
  }
2757
2820
  const propertyAccess = node.expression;
2758
- if (!(ts.isIdentifier(propertyAccess.name) && ts.idText(propertyAccess.name) === "gen")) {
2759
- return typeParserIssue("Call expression name is not 'gen'", void 0, node);
2760
- }
2761
2821
  return pipe(
2762
- importedEffectModule(propertyAccess.expression),
2763
- map4((effectModule) => ({
2822
+ isNodeReferenceToEffectModuleApi("gen")(propertyAccess),
2823
+ map4(() => ({
2764
2824
  node,
2765
- effectModule,
2825
+ effectModule: propertyAccess.expression,
2766
2826
  generatorFunction,
2767
2827
  body: generatorFunction.body
2768
2828
  }))
@@ -2798,18 +2858,11 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2798
2858
  );
2799
2859
  }
2800
2860
  const propertyAccess = node.expression;
2801
- if (!(ts.isIdentifier(propertyAccess.name) && ts.idText(propertyAccess.name) === "fnUntraced")) {
2802
- return typeParserIssue(
2803
- "Call expression name is not 'fnUntraced'",
2804
- void 0,
2805
- node
2806
- );
2807
- }
2808
2861
  return pipe(
2809
- importedEffectModule(propertyAccess.expression),
2810
- map4((effectModule) => ({
2862
+ isNodeReferenceToEffectModuleApi("fnUntraced")(propertyAccess),
2863
+ map4(() => ({
2811
2864
  node,
2812
- effectModule,
2865
+ effectModule: propertyAccess.expression,
2813
2866
  generatorFunction,
2814
2867
  body: generatorFunction.body
2815
2868
  }))
@@ -2850,19 +2903,12 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2850
2903
  );
2851
2904
  }
2852
2905
  const propertyAccess = expressionToTest;
2853
- if (!(ts.isIdentifier(propertyAccess.name) && ts.idText(propertyAccess.name) === "fn")) {
2854
- return typeParserIssue(
2855
- "Call expression name is not 'fn'",
2856
- void 0,
2857
- node
2858
- );
2859
- }
2860
2906
  return pipe(
2861
- importedEffectModule(propertyAccess.expression),
2862
- map4((effectModule) => ({
2907
+ isNodeReferenceToEffectModuleApi("fn")(propertyAccess),
2908
+ map4(() => ({
2863
2909
  node,
2864
2910
  generatorFunction,
2865
- effectModule,
2911
+ effectModule: propertyAccess.expression,
2866
2912
  body: generatorFunction.body
2867
2913
  }))
2868
2914
  );
@@ -2964,6 +3010,26 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
2964
3010
  "TypeParser.effectSchemaType",
2965
3011
  (type) => type
2966
3012
  );
3013
+ const isEffectSchemaTypeSourceFile = cachedBy(
3014
+ fn("TypeParser.isEffectSchemaTypeSourceFile")(function* (sourceFile) {
3015
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
3016
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
3017
+ const typeSymbol = typeChecker.tryGetMemberInModuleExports("Schema", moduleSymbol);
3018
+ if (!typeSymbol) return yield* typeParserIssue("Schema type not found", void 0, sourceFile);
3019
+ const type = typeChecker.getDeclaredTypeOfSymbol(typeSymbol);
3020
+ yield* effectSchemaType(type, sourceFile);
3021
+ return sourceFile;
3022
+ }),
3023
+ "TypeParser.isEffectSchemaTypeSourceFile",
3024
+ (sourceFile) => sourceFile
3025
+ );
3026
+ const isNodeReferenceToEffectSchemaModuleApi = (memberName) => cachedBy(
3027
+ fn("TypeParser.isNodeReferenceToEffectSchemaModuleApi")(function* (node) {
3028
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectSchemaTypeSourceFile, memberName);
3029
+ }),
3030
+ `TypeParser.isNodeReferenceToEffectSchemaModuleApi(${memberName})`,
3031
+ (node) => node
3032
+ );
2967
3033
  const contextTagVarianceStruct = (type, atLocation) => map4(
2968
3034
  all(
2969
3035
  varianceStructInvariantType(type, atLocation, "_Identifier"),
@@ -3090,22 +3156,15 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3090
3156
  if (ts.isCallExpression(expression)) {
3091
3157
  const schemaCall = expression.expression;
3092
3158
  if (ts.isCallExpression(schemaCall) && schemaCall.typeArguments && schemaCall.typeArguments.length > 0) {
3093
- const selfTypeNode = schemaCall.typeArguments[0];
3094
- const schemaIdentifier = schemaCall.expression;
3095
- if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "Class") {
3096
- const expressionType = typeChecker.getTypeAtLocation(expression);
3097
- const parsedSchemaModule = yield* pipe(
3098
- effectSchemaType(expressionType, expression),
3099
- flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
3100
- option
3101
- );
3102
- if (isSome2(parsedSchemaModule)) {
3103
- return {
3104
- className: atLocation.name,
3105
- selfTypeNode,
3106
- Schema: parsedSchemaModule.value
3107
- };
3108
- }
3159
+ const isEffectSchemaModuleApi = yield* pipe(
3160
+ isNodeReferenceToEffectSchemaModuleApi("Class")(schemaCall.expression),
3161
+ option
3162
+ );
3163
+ if (isSome2(isEffectSchemaModuleApi)) {
3164
+ return {
3165
+ className: atLocation.name,
3166
+ selfTypeNode: schemaCall.typeArguments[0]
3167
+ };
3109
3168
  }
3110
3169
  }
3111
3170
  }
@@ -3134,23 +3193,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3134
3193
  const schemaTaggedClassTCall = expression.expression;
3135
3194
  if (ts.isCallExpression(schemaTaggedClassTCall) && schemaTaggedClassTCall.typeArguments && schemaTaggedClassTCall.typeArguments.length > 0) {
3136
3195
  const selfTypeNode = schemaTaggedClassTCall.typeArguments[0];
3137
- const schemaIdentifier = schemaTaggedClassTCall.expression;
3138
- if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedClass") {
3139
- const expressionType = typeChecker.getTypeAtLocation(expression);
3140
- const parsedSchemaModule = yield* pipe(
3141
- effectSchemaType(expressionType, expression),
3142
- flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
3143
- option
3144
- );
3145
- if (isSome2(parsedSchemaModule)) {
3146
- return {
3147
- className: atLocation.name,
3148
- selfTypeNode,
3149
- keyStringLiteral: schemaTaggedClassTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedClassTCall.arguments[0]) ? schemaTaggedClassTCall.arguments[0] : void 0,
3150
- tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0,
3151
- Schema: parsedSchemaModule.value
3152
- };
3153
- }
3196
+ const isEffectSchemaModuleApi = yield* pipe(
3197
+ isNodeReferenceToEffectSchemaModuleApi("TaggedClass")(schemaTaggedClassTCall.expression),
3198
+ option
3199
+ );
3200
+ if (isSome2(isEffectSchemaModuleApi)) {
3201
+ return {
3202
+ className: atLocation.name,
3203
+ selfTypeNode,
3204
+ keyStringLiteral: schemaTaggedClassTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedClassTCall.arguments[0]) ? schemaTaggedClassTCall.arguments[0] : void 0,
3205
+ tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0
3206
+ };
3154
3207
  }
3155
3208
  }
3156
3209
  }
@@ -3179,23 +3232,17 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3179
3232
  const schemaTaggedErrorTCall = expression.expression;
3180
3233
  if (ts.isCallExpression(schemaTaggedErrorTCall) && schemaTaggedErrorTCall.typeArguments && schemaTaggedErrorTCall.typeArguments.length > 0) {
3181
3234
  const selfTypeNode = schemaTaggedErrorTCall.typeArguments[0];
3182
- const schemaIdentifier = schemaTaggedErrorTCall.expression;
3183
- if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedError") {
3184
- const expressionType = typeChecker.getTypeAtLocation(expression);
3185
- const parsedSchemaModule = yield* pipe(
3186
- effectSchemaType(expressionType, expression),
3187
- flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
3188
- option
3189
- );
3190
- if (isSome2(parsedSchemaModule)) {
3191
- return {
3192
- className: atLocation.name,
3193
- selfTypeNode,
3194
- keyStringLiteral: schemaTaggedErrorTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedErrorTCall.arguments[0]) ? schemaTaggedErrorTCall.arguments[0] : void 0,
3195
- tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0,
3196
- Schema: parsedSchemaModule.value
3197
- };
3198
- }
3235
+ const isEffectSchemaModuleApi = yield* pipe(
3236
+ isNodeReferenceToEffectSchemaModuleApi("TaggedError")(schemaTaggedErrorTCall.expression),
3237
+ option
3238
+ );
3239
+ if (isSome2(isEffectSchemaModuleApi)) {
3240
+ return {
3241
+ className: atLocation.name,
3242
+ selfTypeNode,
3243
+ keyStringLiteral: schemaTaggedErrorTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedErrorTCall.arguments[0]) ? schemaTaggedErrorTCall.arguments[0] : void 0,
3244
+ tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0
3245
+ };
3199
3246
  }
3200
3247
  }
3201
3248
  }
@@ -3207,8 +3254,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3207
3254
  "TypeParser.extendsSchemaTaggedError",
3208
3255
  (atLocation) => atLocation
3209
3256
  );
3210
- const extendsDataTaggedError = cachedBy(
3211
- fn("TypeParser.extendsDataTaggedError")(function* (atLocation) {
3257
+ const extendsSchemaTaggedRequest = cachedBy(
3258
+ fn("TypeParser.extendsSchemaTaggedRequest")(function* (atLocation) {
3212
3259
  if (!atLocation.name) {
3213
3260
  return yield* typeParserIssue("Class has no name", void 0, atLocation);
3214
3261
  }
@@ -3221,18 +3268,19 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3221
3268
  if (ts.isExpressionWithTypeArguments(typeX)) {
3222
3269
  const expression = typeX.expression;
3223
3270
  if (ts.isCallExpression(expression)) {
3224
- const dataTaggedErrorCall = expression;
3225
- const dataIdentifier = dataTaggedErrorCall.expression;
3226
- if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedError") {
3227
- const parsedDataModule = yield* pipe(
3228
- importedDataModule(dataIdentifier.expression),
3271
+ const schemaTaggedRequestTCall = expression.expression;
3272
+ if (ts.isCallExpression(schemaTaggedRequestTCall) && schemaTaggedRequestTCall.typeArguments && schemaTaggedRequestTCall.typeArguments.length > 0) {
3273
+ const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3274
+ const isEffectSchemaModuleApi = yield* pipe(
3275
+ isNodeReferenceToEffectSchemaModuleApi("TaggedRequest")(schemaTaggedRequestTCall.expression),
3229
3276
  option
3230
3277
  );
3231
- if (isSome2(parsedDataModule)) {
3278
+ if (isSome2(isEffectSchemaModuleApi)) {
3232
3279
  return {
3233
3280
  className: atLocation.name,
3234
- keyStringLiteral: dataTaggedErrorCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedErrorCall.arguments[0]) ? dataTaggedErrorCall.arguments[0] : void 0,
3235
- Data: parsedDataModule.value
3281
+ selfTypeNode,
3282
+ tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0,
3283
+ keyStringLiteral: schemaTaggedRequestTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedRequestTCall.arguments[0]) ? schemaTaggedRequestTCall.arguments[0] : void 0
3236
3284
  };
3237
3285
  }
3238
3286
  }
@@ -3240,13 +3288,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3240
3288
  }
3241
3289
  }
3242
3290
  }
3243
- return yield* typeParserIssue("Class does not extend Data.TaggedError", void 0, atLocation);
3291
+ return yield* typeParserIssue("Class does not extend Schema.TaggedRequest", void 0, atLocation);
3244
3292
  }),
3245
- "TypeParser.extendsDataTaggedError",
3293
+ "TypeParser.extendsSchemaTaggedRequest",
3246
3294
  (atLocation) => atLocation
3247
3295
  );
3248
- const extendsDataTaggedClass = cachedBy(
3249
- fn("TypeParser.extendsDataTaggedClass")(function* (atLocation) {
3296
+ const extendsDataTaggedError = cachedBy(
3297
+ fn("TypeParser.extendsDataTaggedError")(function* (atLocation) {
3250
3298
  if (!atLocation.name) {
3251
3299
  return yield* typeParserIssue("Class has no name", void 0, atLocation);
3252
3300
  }
@@ -3259,9 +3307,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3259
3307
  if (ts.isExpressionWithTypeArguments(typeX)) {
3260
3308
  const expression = typeX.expression;
3261
3309
  if (ts.isCallExpression(expression)) {
3262
- const dataTaggedClassCall = expression;
3263
- const dataIdentifier = dataTaggedClassCall.expression;
3264
- if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedClass") {
3310
+ const dataTaggedErrorCall = expression;
3311
+ const dataIdentifier = dataTaggedErrorCall.expression;
3312
+ if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedError") {
3265
3313
  const parsedDataModule = yield* pipe(
3266
3314
  importedDataModule(dataIdentifier.expression),
3267
3315
  option
@@ -3269,7 +3317,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3269
3317
  if (isSome2(parsedDataModule)) {
3270
3318
  return {
3271
3319
  className: atLocation.name,
3272
- keyStringLiteral: dataTaggedClassCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedClassCall.arguments[0]) ? dataTaggedClassCall.arguments[0] : void 0,
3320
+ keyStringLiteral: dataTaggedErrorCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedErrorCall.arguments[0]) ? dataTaggedErrorCall.arguments[0] : void 0,
3273
3321
  Data: parsedDataModule.value
3274
3322
  };
3275
3323
  }
@@ -3278,13 +3326,13 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3278
3326
  }
3279
3327
  }
3280
3328
  }
3281
- return yield* typeParserIssue("Class does not extend Data.TaggedClass", void 0, atLocation);
3329
+ return yield* typeParserIssue("Class does not extend Data.TaggedError", void 0, atLocation);
3282
3330
  }),
3283
- "TypeParser.extendsDataTaggedClass",
3331
+ "TypeParser.extendsDataTaggedError",
3284
3332
  (atLocation) => atLocation
3285
3333
  );
3286
- const extendsSchemaTaggedRequest = cachedBy(
3287
- fn("TypeParser.extendsSchemaTaggedRequest")(function* (atLocation) {
3334
+ const extendsDataTaggedClass = cachedBy(
3335
+ fn("TypeParser.extendsDataTaggedClass")(function* (atLocation) {
3288
3336
  if (!atLocation.name) {
3289
3337
  return yield* typeParserIssue("Class has no name", void 0, atLocation);
3290
3338
  }
@@ -3297,35 +3345,28 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3297
3345
  if (ts.isExpressionWithTypeArguments(typeX)) {
3298
3346
  const expression = typeX.expression;
3299
3347
  if (ts.isCallExpression(expression)) {
3300
- const schemaTaggedRequestTCall = expression.expression;
3301
- if (ts.isCallExpression(schemaTaggedRequestTCall) && schemaTaggedRequestTCall.typeArguments && schemaTaggedRequestTCall.typeArguments.length > 0) {
3302
- const selfTypeNode = schemaTaggedRequestTCall.typeArguments[0];
3303
- const schemaIdentifier = schemaTaggedRequestTCall.expression;
3304
- if (ts.isPropertyAccessExpression(schemaIdentifier) && ts.isIdentifier(schemaIdentifier.name) && ts.idText(schemaIdentifier.name) === "TaggedRequest") {
3305
- const expressionType = typeChecker.getTypeAtLocation(expression);
3306
- const parsedSchemaModule = yield* pipe(
3307
- effectSchemaType(expressionType, expression),
3308
- flatMap2(() => importedSchemaModule(schemaIdentifier.expression)),
3309
- option
3310
- );
3311
- if (isSome2(parsedSchemaModule)) {
3312
- return {
3313
- className: atLocation.name,
3314
- selfTypeNode,
3315
- tagStringLiteral: expression.arguments.length > 0 && ts.isStringLiteral(expression.arguments[0]) ? expression.arguments[0] : void 0,
3316
- keyStringLiteral: schemaTaggedRequestTCall.arguments.length > 0 && ts.isStringLiteral(schemaTaggedRequestTCall.arguments[0]) ? schemaTaggedRequestTCall.arguments[0] : void 0,
3317
- Schema: parsedSchemaModule.value
3318
- };
3319
- }
3348
+ const dataTaggedClassCall = expression;
3349
+ const dataIdentifier = dataTaggedClassCall.expression;
3350
+ if (ts.isPropertyAccessExpression(dataIdentifier) && ts.isIdentifier(dataIdentifier.name) && ts.idText(dataIdentifier.name) === "TaggedClass") {
3351
+ const parsedDataModule = yield* pipe(
3352
+ importedDataModule(dataIdentifier.expression),
3353
+ option
3354
+ );
3355
+ if (isSome2(parsedDataModule)) {
3356
+ return {
3357
+ className: atLocation.name,
3358
+ keyStringLiteral: dataTaggedClassCall.arguments.length > 0 && ts.isStringLiteral(dataTaggedClassCall.arguments[0]) ? dataTaggedClassCall.arguments[0] : void 0,
3359
+ Data: parsedDataModule.value
3360
+ };
3320
3361
  }
3321
3362
  }
3322
3363
  }
3323
3364
  }
3324
3365
  }
3325
3366
  }
3326
- return yield* typeParserIssue("Class does not extend Schema.TaggedRequest", void 0, atLocation);
3367
+ return yield* typeParserIssue("Class does not extend Data.TaggedClass", void 0, atLocation);
3327
3368
  }),
3328
- "TypeParser.extendsSchemaTaggedRequest",
3369
+ "TypeParser.extendsDataTaggedClass",
3329
3370
  (atLocation) => atLocation
3330
3371
  );
3331
3372
  const extendsContextTag = cachedBy(
@@ -3385,6 +3426,10 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3385
3426
  if (!heritageClauses) {
3386
3427
  return yield* typeParserIssue("Class has no heritage clauses", void 0, atLocation);
3387
3428
  }
3429
+ const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3430
+ if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3431
+ const type = typeChecker.getTypeOfSymbol(classSym);
3432
+ const tagType = yield* contextTag(type, atLocation);
3388
3433
  for (const heritageClause of heritageClauses) {
3389
3434
  for (const typeX of heritageClause.types) {
3390
3435
  if (ts.isExpressionWithTypeArguments(typeX)) {
@@ -3394,26 +3439,19 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3394
3439
  if (ts.isCallExpression(effectTagCall) && wholeCall.typeArguments && wholeCall.typeArguments.length > 0) {
3395
3440
  const effectTagIdentifier = effectTagCall.expression;
3396
3441
  const selfTypeNode = wholeCall.typeArguments[0];
3397
- if (ts.isPropertyAccessExpression(effectTagIdentifier) && ts.isIdentifier(effectTagIdentifier.name) && ts.idText(effectTagIdentifier.name) === "Tag") {
3398
- const parsedEffectModule = yield* pipe(
3399
- importedEffectModule(effectTagIdentifier.expression),
3400
- option
3401
- );
3402
- if (isSome2(parsedEffectModule)) {
3403
- const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3404
- if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3405
- const type = typeChecker.getTypeOfSymbol(classSym);
3406
- const tagType = yield* contextTag(type, atLocation);
3407
- return {
3408
- className: atLocation.name,
3409
- selfTypeNode,
3410
- keyStringLiteral: ts.isStringLiteral(effectTagCall.arguments[0]) ? effectTagCall.arguments[0] : void 0,
3411
- args: effectTagCall.arguments,
3412
- Identifier: tagType.Identifier,
3413
- Service: tagType.Service,
3414
- Tag: parsedEffectModule.value
3415
- };
3416
- }
3442
+ const isEffectTag = yield* pipe(
3443
+ isNodeReferenceToEffectModuleApi("Tag")(effectTagIdentifier),
3444
+ option
3445
+ );
3446
+ if (isSome2(isEffectTag)) {
3447
+ return {
3448
+ className: atLocation.name,
3449
+ selfTypeNode,
3450
+ keyStringLiteral: ts.isStringLiteral(effectTagCall.arguments[0]) ? effectTagCall.arguments[0] : void 0,
3451
+ args: effectTagCall.arguments,
3452
+ Identifier: tagType.Identifier,
3453
+ Service: tagType.Service
3454
+ };
3417
3455
  }
3418
3456
  }
3419
3457
  }
@@ -3443,13 +3481,16 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3443
3481
  if (ts.isCallExpression(effectServiceCall) && effectServiceCall.typeArguments && effectServiceCall.typeArguments.length > 0) {
3444
3482
  const effectServiceIdentifier = effectServiceCall.expression;
3445
3483
  const selfTypeNode = effectServiceCall.typeArguments[0];
3446
- if (ts.isPropertyAccessExpression(effectServiceIdentifier) && ts.isIdentifier(effectServiceIdentifier.name) && ts.idText(effectServiceIdentifier.name) === "Service") {
3484
+ const isEffectService = yield* pipe(
3485
+ isNodeReferenceToEffectModuleApi("Service")(effectServiceIdentifier),
3486
+ option
3487
+ );
3488
+ if (isSome2(isEffectService)) {
3447
3489
  const classSym = typeChecker.getSymbolAtLocation(atLocation.name);
3448
3490
  if (!classSym) return yield* typeParserIssue("Class has no symbol", void 0, atLocation);
3449
3491
  const type = typeChecker.getTypeOfSymbol(classSym);
3450
3492
  const parsedContextTag = yield* pipe(
3451
- importedEffectModule(effectServiceIdentifier.expression),
3452
- flatMap2(() => contextTag(type, atLocation)),
3493
+ contextTag(type, atLocation),
3453
3494
  option
3454
3495
  );
3455
3496
  if (isSome2(parsedContextTag)) {
@@ -3491,6 +3532,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3491
3532
  (atLocation) => atLocation
3492
3533
  );
3493
3534
  return {
3535
+ isNodeReferenceToEffectModuleApi,
3494
3536
  effectType,
3495
3537
  strictEffectType,
3496
3538
  layerType,
@@ -3519,6 +3561,80 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils) {
3519
3561
  };
3520
3562
  }
3521
3563
 
3564
+ // src/diagnostics/catchUnfailableEffect.ts
3565
+ var catchUnfailableEffect = createDiagnostic({
3566
+ name: "catchUnfailableEffect",
3567
+ code: 2,
3568
+ severity: "suggestion",
3569
+ apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
3570
+ const ts = yield* service(TypeScriptApi);
3571
+ const typeParser = yield* service(TypeParser);
3572
+ const typeChecker = yield* service(TypeCheckerApi);
3573
+ const nodeToVisit = [];
3574
+ const appendNodeToVisit = (node) => {
3575
+ nodeToVisit.push(node);
3576
+ return void 0;
3577
+ };
3578
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3579
+ while (nodeToVisit.length > 0) {
3580
+ const node = nodeToVisit.shift();
3581
+ ts.forEachChild(node, appendNodeToVisit);
3582
+ if (ts.isCallExpression(node)) {
3583
+ const catchFunctions = ["catchAll", "catch", "catchIf", "catchSome", "catchTag", "catchTags"];
3584
+ const isCatchCall = yield* pipe(
3585
+ firstSuccessOf(
3586
+ catchFunctions.map((catchFn) => typeParser.isNodeReferenceToEffectModuleApi(catchFn)(node.expression))
3587
+ ),
3588
+ option
3589
+ );
3590
+ if (isSome2(isCatchCall)) {
3591
+ const parent = node.parent;
3592
+ if (parent && ts.isCallExpression(parent)) {
3593
+ const pipeCallResult = yield* pipe(
3594
+ typeParser.pipeCall(parent),
3595
+ option
3596
+ );
3597
+ if (isSome2(pipeCallResult)) {
3598
+ const { args: args2, node: pipeCallNode, subject } = pipeCallResult.value;
3599
+ const argIndex = args2.findIndex((arg) => arg === node);
3600
+ if (argIndex !== -1) {
3601
+ let effectTypeToCheck;
3602
+ if (argIndex === 0) {
3603
+ effectTypeToCheck = typeChecker.getTypeAtLocation(subject);
3604
+ } else {
3605
+ const signature = typeChecker.getResolvedSignature(pipeCallNode);
3606
+ if (signature) {
3607
+ const typeArguments = typeChecker.getTypeArgumentsForResolvedSignature(signature);
3608
+ if (typeArguments && typeArguments.length > argIndex) {
3609
+ effectTypeToCheck = typeArguments[argIndex];
3610
+ }
3611
+ }
3612
+ }
3613
+ if (effectTypeToCheck) {
3614
+ const effectType = yield* pipe(
3615
+ typeParser.effectType(effectTypeToCheck, node),
3616
+ option
3617
+ );
3618
+ if (isSome2(effectType)) {
3619
+ const { E } = effectType.value;
3620
+ if (E.flags & ts.TypeFlags.Never) {
3621
+ report({
3622
+ location: node.expression,
3623
+ messageText: `Looks like the previous effect never fails, so probably this error handling will never be triggered.`,
3624
+ fixes: []
3625
+ });
3626
+ }
3627
+ }
3628
+ }
3629
+ }
3630
+ }
3631
+ }
3632
+ }
3633
+ }
3634
+ }
3635
+ })
3636
+ });
3637
+
3522
3638
  // src/diagnostics/classSelfMismatch.ts
3523
3639
  var classSelfMismatch = createDiagnostic({
3524
3640
  name: "classSelfMismatch",
@@ -4778,11 +4894,11 @@ var multipleEffectProvide = createDiagnostic({
4778
4894
  "Layer"
4779
4895
  ) || "Layer";
4780
4896
  const parseEffectProvideLayer = (node) => {
4781
- if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && ts.idText(node.expression.name) === "provide" && node.arguments.length > 0) {
4897
+ if (ts.isCallExpression(node) && node.arguments.length > 0) {
4782
4898
  const layer = node.arguments[0];
4783
4899
  const type = typeChecker.getTypeAtLocation(layer);
4784
4900
  return pipe(
4785
- typeParser.importedEffectModule(node.expression.expression),
4901
+ typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression),
4786
4902
  flatMap2(() => typeParser.layerType(type, layer)),
4787
4903
  map4(() => ({ layer, node })),
4788
4904
  orElse2(() => void_)
@@ -5631,10 +5747,10 @@ var strictEffectProvide = createDiagnostic({
5631
5747
  const typeChecker = yield* service(TypeCheckerApi);
5632
5748
  const typeParser = yield* service(TypeParser);
5633
5749
  const parseEffectProvideWithLayer = (node) => gen(function* () {
5634
- if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || !ts.isIdentifier(node.expression.name) || ts.idText(node.expression.name) !== "provide" || node.arguments.length === 0) {
5750
+ if (!ts.isCallExpression(node) || node.arguments.length === 0) {
5635
5751
  return yield* typeParserIssue("Not an Effect.provide call");
5636
5752
  }
5637
- yield* typeParser.importedEffectModule(node.expression.expression);
5753
+ yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
5638
5754
  return yield* firstSuccessOf(
5639
5755
  node.arguments.map((arg) => {
5640
5756
  const argType = typeChecker.getTypeAtLocation(arg);
@@ -5929,6 +6045,7 @@ var unsupportedServiceAccessors = createDiagnostic({
5929
6045
 
5930
6046
  // src/diagnostics.ts
5931
6047
  var diagnostics = [
6048
+ catchUnfailableEffect,
5932
6049
  classSelfMismatch,
5933
6050
  duplicatePackage,
5934
6051
  effectGenUsesAdapter,