@effect/language-service 0.63.2 → 0.64.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.
package/index.js CHANGED
@@ -751,6 +751,13 @@ var make2 = (compare) => (self, that) => self === that ? 0 : compare(self, that)
751
751
  var string2 = /* @__PURE__ */ make2((self, that) => self < that ? -1 : 1);
752
752
  var number2 = /* @__PURE__ */ make2((self, that) => self < that ? -1 : 1);
753
753
  var reverse = (O) => make2((self, that) => O(that, self));
754
+ var combine2 = /* @__PURE__ */ dual(2, (self, that) => make2((a1, a2) => {
755
+ const out = self(a1, a2);
756
+ if (out !== 0) {
757
+ return out;
758
+ }
759
+ return that(a1, a2);
760
+ }));
754
761
  var mapInput = /* @__PURE__ */ dual(2, (self, f) => make2((b1, b2) => self(f(b1), f(b2))));
755
762
 
756
763
  // node_modules/.pnpm/effect@3.19.13/node_modules/effect/dist/esm/Option.js
@@ -5033,6 +5040,12 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5033
5040
  );
5034
5041
  const extendsCauseYieldableError = cachedBy(
5035
5042
  fn("TypeParser.extendsCauseYieldableError")(function* (givenType) {
5043
+ if (givenType.flags & ts.TypeFlags.Never) {
5044
+ return yield* typeParserIssue("Type is never", givenType);
5045
+ }
5046
+ if (givenType.flags & ts.TypeFlags.Any) {
5047
+ return yield* typeParserIssue("Type is any", givenType);
5048
+ }
5036
5049
  const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")();
5037
5050
  for (const [symbol3, sourceFile] of symbols) {
5038
5051
  const causeFile = yield* pipe(isCauseTypeSourceFile(sourceFile), orElse2(() => void_));
@@ -5127,18 +5140,19 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5127
5140
  );
5128
5141
  const effectType = cachedBy(
5129
5142
  fn("TypeParser.effectType")(function* (type, atLocation) {
5130
- let result = typeParserIssue("Type has no effect variance struct", type, atLocation);
5131
5143
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
5132
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
5144
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
5133
5145
  );
5146
+ if (propertiesSymbols.length === 0) {
5147
+ return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
5148
+ }
5134
5149
  propertiesSymbols.sort(
5135
5150
  (a, b) => ts.symbolName(b).indexOf("EffectTypeId") - ts.symbolName(a).indexOf("EffectTypeId")
5136
5151
  );
5137
- for (const propertySymbol of propertiesSymbols) {
5152
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
5138
5153
  const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
5139
- result = pipe(result, orElse2(() => effectVarianceStruct(propertyType, atLocation)));
5140
- }
5141
- return yield* result;
5154
+ return effectVarianceStruct(propertyType, atLocation);
5155
+ }));
5142
5156
  }),
5143
5157
  "TypeParser.effectType",
5144
5158
  (type) => type
@@ -5177,22 +5191,18 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5177
5191
  fn("TypeParser.layerType")(function* (type, atLocation) {
5178
5192
  yield* pipeableType(type, atLocation);
5179
5193
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
5180
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
5194
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
5181
5195
  );
5196
+ if (propertiesSymbols.length === 0) {
5197
+ return yield* typeParserIssue("Type has no layer variance struct", type, atLocation);
5198
+ }
5182
5199
  propertiesSymbols.sort(
5183
5200
  (a, b) => ts.symbolName(b).indexOf("LayerTypeId") - ts.symbolName(a).indexOf("LayerTypeId")
5184
5201
  );
5185
- for (const propertySymbol of propertiesSymbols) {
5202
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
5186
5203
  const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
5187
- const varianceArgs = yield* option(layerVarianceStruct(
5188
- propertyType,
5189
- atLocation
5190
- ));
5191
- if (isSome2(varianceArgs)) {
5192
- return varianceArgs.value;
5193
- }
5194
- }
5195
- return yield* typeParserIssue("Type has no layer variance struct", type, atLocation);
5204
+ return layerVarianceStruct(propertyType, atLocation);
5205
+ }));
5196
5206
  }),
5197
5207
  "TypeParser.layerType",
5198
5208
  (type) => type
@@ -5489,20 +5499,16 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5489
5499
  const ast = typeChecker.getPropertyOfType(type, "ast");
5490
5500
  if (!ast) return yield* typeParserIssue("Has no 'ast' property", type, atLocation);
5491
5501
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
5492
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
5502
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
5493
5503
  );
5504
+ if (propertiesSymbols.length === 0) {
5505
+ return yield* typeParserIssue("Type has no schema variance struct", type, atLocation);
5506
+ }
5494
5507
  propertiesSymbols.sort((a, b) => ts.symbolName(b).indexOf("TypeId") - ts.symbolName(a).indexOf("TypeId"));
5495
- for (const propertySymbol of propertiesSymbols) {
5508
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
5496
5509
  const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
5497
- const varianceArgs = yield* option(effectSchemaVarianceStruct(
5498
- propertyType,
5499
- atLocation
5500
- ));
5501
- if (isSome2(varianceArgs)) {
5502
- return varianceArgs.value;
5503
- }
5504
- }
5505
- return yield* typeParserIssue("Type has no schema variance struct", type, atLocation);
5510
+ return effectSchemaVarianceStruct(propertyType, atLocation);
5511
+ }));
5506
5512
  }),
5507
5513
  "TypeParser.effectSchemaType",
5508
5514
  (type) => type
@@ -5538,33 +5544,54 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5538
5544
  fn("TypeParser.contextTag")(function* (type, atLocation) {
5539
5545
  yield* pipeableType(type, atLocation);
5540
5546
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
5541
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
5547
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
5542
5548
  );
5549
+ if (propertiesSymbols.length === 0) {
5550
+ return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
5551
+ }
5543
5552
  propertiesSymbols.sort((a, b) => ts.symbolName(b).indexOf("TypeId") - ts.symbolName(a).indexOf("TypeId"));
5544
- for (const propertySymbol of propertiesSymbols) {
5553
+ return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
5545
5554
  const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
5546
- const varianceArgs = yield* option(contextTagVarianceStruct(
5547
- propertyType,
5548
- atLocation
5549
- ));
5550
- if (isSome2(varianceArgs)) {
5551
- return varianceArgs.value;
5552
- }
5553
- }
5554
- return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
5555
+ return contextTagVarianceStruct(propertyType, atLocation);
5556
+ }));
5555
5557
  }),
5556
5558
  "TypeParser.contextTag",
5557
5559
  (type) => type
5558
5560
  );
5561
+ const effectFunctionImportedName = cachedBy(
5562
+ fn("TypeParser.effectFunctionImportedName")(function* (sourceFile) {
5563
+ return tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Function");
5564
+ }),
5565
+ "TypeParser.effectFunctionImportedName",
5566
+ (node) => node
5567
+ );
5559
5568
  const pipeCall = cachedBy(
5560
5569
  function(node) {
5561
5570
  if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && ts.idText(node.expression.name) === "pipe") {
5562
- return succeed({
5563
- node,
5564
- subject: node.expression.expression,
5565
- args: Array.from(node.arguments),
5566
- kind: "pipeable"
5567
- });
5571
+ const baseExpression = node.expression.expression;
5572
+ return pipe(
5573
+ effectFunctionImportedName(tsUtils.getSourceFileOfNode(node)),
5574
+ flatMap4((functionIdentifier) => {
5575
+ if (functionIdentifier && ts.isIdentifier(baseExpression) && ts.idText(baseExpression) === functionIdentifier) {
5576
+ if (node.arguments.length === 0) {
5577
+ return typeParserIssue("Node is not a pipe call", void 0, node);
5578
+ }
5579
+ const [subject, ...args2] = node.arguments;
5580
+ return succeed({
5581
+ node,
5582
+ subject,
5583
+ args: args2,
5584
+ kind: "pipe"
5585
+ });
5586
+ }
5587
+ return succeed({
5588
+ node,
5589
+ subject: baseExpression,
5590
+ args: Array.from(node.arguments),
5591
+ kind: "pipeable"
5592
+ });
5593
+ })
5594
+ );
5568
5595
  }
5569
5596
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && ts.idText(node.expression) === "pipe" && node.arguments.length > 0) {
5570
5597
  const [subject, ...args2] = node.arguments;
@@ -5579,17 +5606,10 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5579
5606
  fn("TypeParser.scopeType")(function* (type, atLocation) {
5580
5607
  yield* pipeableType(type, atLocation);
5581
5608
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
5582
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration && ts.isPropertySignature(_.valueDeclaration) && ts.isComputedPropertyName(_.valueDeclaration.name)
5583
- );
5584
- propertiesSymbols.sort(
5585
- (a, b) => ts.symbolName(b).indexOf("ScopeTypeId") - ts.symbolName(a).indexOf("ScopeTypeId")
5609
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
5586
5610
  );
5587
- for (const propertySymbol of propertiesSymbols) {
5588
- const computedPropertyExpression = propertySymbol.valueDeclaration.name;
5589
- const symbol3 = typeChecker.getSymbolAtLocation(computedPropertyExpression.expression);
5590
- if (symbol3 && ts.symbolName(symbol3) === "ScopeTypeId") {
5591
- return type;
5592
- }
5611
+ if (propertiesSymbols.some((s) => ts.symbolName(s).indexOf("ScopeTypeId") !== -1)) {
5612
+ return type;
5593
5613
  }
5594
5614
  return yield* typeParserIssue("Type has no scope type id", type, atLocation);
5595
5615
  }),
@@ -6095,12 +6115,38 @@ function make7(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
6095
6115
  "TypeParser.extendsEffectSqlModelClass",
6096
6116
  (atLocation) => atLocation
6097
6117
  );
6118
+ const isEffectLayerTypeSourceFile = cachedBy(
6119
+ fn("TypeParser.isEffectLayerTypeSourceFile")(function* (sourceFile) {
6120
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
6121
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
6122
+ const layerTypeSymbol = typeChecker.tryGetMemberInModuleExports("Layer", moduleSymbol);
6123
+ if (!layerTypeSymbol) return yield* typeParserIssue("Layer type not found", void 0, sourceFile);
6124
+ const type = typeChecker.getDeclaredTypeOfSymbol(layerTypeSymbol);
6125
+ yield* layerType(type, sourceFile);
6126
+ return sourceFile;
6127
+ }),
6128
+ "TypeParser.isEffectLayerTypeSourceFile",
6129
+ (sourceFile) => sourceFile
6130
+ );
6131
+ const isNodeReferenceToEffectLayerModuleApi = (memberName) => cachedBy(
6132
+ fn("TypeParser.isNodeReferenceToEffectLayerModuleApi")(function* (node) {
6133
+ return yield* isNodeReferenceToExportOfPackageModule(
6134
+ node,
6135
+ "effect",
6136
+ isEffectLayerTypeSourceFile,
6137
+ memberName
6138
+ );
6139
+ }),
6140
+ `TypeParser.isNodeReferenceToEffectLayerModuleApi(${memberName})`,
6141
+ (node) => node
6142
+ );
6098
6143
  return {
6099
6144
  isNodeReferenceToEffectModuleApi,
6100
6145
  isNodeReferenceToEffectSchemaModuleApi,
6101
6146
  isNodeReferenceToEffectDataModuleApi,
6102
6147
  isNodeReferenceToEffectContextModuleApi,
6103
6148
  isNodeReferenceToEffectSqlModelModuleApi,
6149
+ isNodeReferenceToEffectLayerModuleApi,
6104
6150
  effectType,
6105
6151
  strictEffectType,
6106
6152
  layerType,
@@ -6415,9 +6461,11 @@ var parse2 = fn("writeTagClassAccessors.parse")(function* (node) {
6415
6461
  const typeParser = yield* service(TypeParser);
6416
6462
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
6417
6463
  if (!ts.isClassDeclaration(node)) return yield* fail3("not a class declaration");
6418
- const { Service, accessors: accessors2, className } = yield* pipe(
6419
- typeParser.extendsEffectService(node),
6420
- orElse2(() => map8(typeParser.extendsEffectTag(node), (_) => ({ accessors: true, ..._ }))),
6464
+ const { Service, accessors: accessors2, className, kind } = yield* pipe(
6465
+ map8(typeParser.extendsEffectService(node), (_) => ({ kind: "effectService", ..._ })),
6466
+ orElse2(
6467
+ () => map8(typeParser.extendsEffectTag(node), (_) => ({ kind: "effectTag", accessors: true, ..._ }))
6468
+ ),
6421
6469
  orElse2(() => fail3("not a class extending Effect.Service call"))
6422
6470
  );
6423
6471
  if (accessors2 !== true) return yield* fail3("accessors are not enabled in the Effect.Service call");
@@ -6439,7 +6487,7 @@ var parse2 = fn("writeTagClassAccessors.parse")(function* (node) {
6439
6487
  const hash2 = involvedMembers.map(({ property, propertyType }) => {
6440
6488
  return ts.symbolName(property) + ": " + typeChecker.typeToString(propertyType);
6441
6489
  }).concat([ts.idText(className)]).join("\n");
6442
- return { Service, className, atLocation: node, hash: cyrb53(hash2), involvedMembers };
6490
+ return { Service, className, atLocation: node, hash: cyrb53(hash2), involvedMembers, kind };
6443
6491
  });
6444
6492
  var writeTagClassAccessors = createRefactor({
6445
6493
  name: "writeTagClassAccessors",
@@ -7426,6 +7474,100 @@ var anyUnknownInErrorContext = createDiagnostic({
7426
7474
  })
7427
7475
  });
7428
7476
 
7477
+ // src/diagnostics/catchAllToMapError.ts
7478
+ var catchAllToMapError = createDiagnostic({
7479
+ name: "catchAllToMapError",
7480
+ code: 39,
7481
+ description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
7482
+ severity: "suggestion",
7483
+ apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
7484
+ const ts = yield* service(TypeScriptApi);
7485
+ const typeParser = yield* service(TypeParser);
7486
+ const getFunctionBody = (node) => {
7487
+ if (ts.isArrowFunction(node)) {
7488
+ return node.body;
7489
+ }
7490
+ if (ts.isFunctionExpression(node)) {
7491
+ return node.body;
7492
+ }
7493
+ return void 0;
7494
+ };
7495
+ const getEffectFailCallInfo = (body) => {
7496
+ return gen(function* () {
7497
+ if (ts.isCallExpression(body)) {
7498
+ const isFailCall = yield* pipe(
7499
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
7500
+ option
7501
+ );
7502
+ if (isSome2(isFailCall) && body.arguments.length >= 1) {
7503
+ return some2({ failCall: body, failArg: body.arguments[0] });
7504
+ }
7505
+ }
7506
+ if (ts.isBlock(body)) {
7507
+ const statements = body.statements;
7508
+ if (statements.length === 1) {
7509
+ const stmt = statements[0];
7510
+ if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
7511
+ const isFailCall = yield* pipe(
7512
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(stmt.expression.expression),
7513
+ option
7514
+ );
7515
+ if (isSome2(isFailCall) && stmt.expression.arguments.length >= 1) {
7516
+ return some2({ failCall: stmt.expression, failArg: stmt.expression.arguments[0] });
7517
+ }
7518
+ }
7519
+ }
7520
+ }
7521
+ return none2();
7522
+ });
7523
+ };
7524
+ const nodeToVisit = [];
7525
+ const appendNodeToVisit = (node) => {
7526
+ nodeToVisit.push(node);
7527
+ return void 0;
7528
+ };
7529
+ ts.forEachChild(sourceFile, appendNodeToVisit);
7530
+ while (nodeToVisit.length > 0) {
7531
+ const node = nodeToVisit.shift();
7532
+ ts.forEachChild(node, appendNodeToVisit);
7533
+ if (ts.isCallExpression(node)) {
7534
+ const isCatchAllCall = yield* pipe(
7535
+ typeParser.isNodeReferenceToEffectModuleApi("catchAll")(node.expression),
7536
+ option
7537
+ );
7538
+ if (isSome2(isCatchAllCall)) {
7539
+ const callback = node.arguments[0];
7540
+ if (!callback) continue;
7541
+ const functionBody = getFunctionBody(callback);
7542
+ if (!functionBody) continue;
7543
+ const failCallInfo = yield* getEffectFailCallInfo(functionBody);
7544
+ if (isNone2(failCallInfo)) continue;
7545
+ const { failArg, failCall } = failCallInfo.value;
7546
+ report({
7547
+ location: node.expression,
7548
+ messageText: `You can use Effect.mapError instead of Effect.catchAll + Effect.fail to transform the error type.`,
7549
+ fixes: [{
7550
+ fixName: "catchAllToMapError_fix",
7551
+ description: "Replace with Effect.mapError",
7552
+ apply: gen(function* () {
7553
+ const changeTracker = yield* service(ChangeTracker);
7554
+ if (ts.isPropertyAccessExpression(node.expression)) {
7555
+ changeTracker.replaceNode(
7556
+ sourceFile,
7557
+ node.expression.name,
7558
+ ts.factory.createIdentifier("mapError")
7559
+ );
7560
+ }
7561
+ changeTracker.replaceNode(sourceFile, failCall, failArg);
7562
+ })
7563
+ }]
7564
+ });
7565
+ }
7566
+ }
7567
+ }
7568
+ })
7569
+ });
7570
+
7429
7571
  // src/diagnostics/catchUnfailableEffect.ts
7430
7572
  var catchUnfailableEffect = createDiagnostic({
7431
7573
  name: "catchUnfailableEffect",
@@ -7922,6 +8064,65 @@ var genericEffectServices = createDiagnostic({
7922
8064
  })
7923
8065
  });
7924
8066
 
8067
+ // src/diagnostics/globalErrorInEffectCatch.ts
8068
+ var globalErrorInEffectCatch = createDiagnostic({
8069
+ name: "globalErrorInEffectCatch",
8070
+ code: 36,
8071
+ description: "Warns when catch callbacks return global Error type instead of typed errors",
8072
+ severity: "warning",
8073
+ apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
8074
+ const ts = yield* service(TypeScriptApi);
8075
+ const typeParser = yield* service(TypeParser);
8076
+ const typeChecker = yield* service(TypeCheckerApi);
8077
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
8078
+ const nodeToVisit = [];
8079
+ const appendNodeToVisit = (node) => {
8080
+ nodeToVisit.push(node);
8081
+ return void 0;
8082
+ };
8083
+ ts.forEachChild(sourceFile, appendNodeToVisit);
8084
+ while (nodeToVisit.length > 0) {
8085
+ const node = nodeToVisit.shift();
8086
+ ts.forEachChild(node, appendNodeToVisit);
8087
+ if (ts.isCallExpression(node)) {
8088
+ const isEffectWithCatch = yield* pipe(
8089
+ typeParser.isNodeReferenceToEffectModuleApi("tryPromise")(node.expression),
8090
+ orElse2(() => typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression)),
8091
+ orElse2(() => typeParser.isNodeReferenceToEffectModuleApi("tryMap")(node.expression)),
8092
+ orElse2(() => typeParser.isNodeReferenceToEffectModuleApi("tryMapPromise")(node.expression)),
8093
+ orElse2(() => void_)
8094
+ );
8095
+ if (isEffectWithCatch) {
8096
+ const signature = typeChecker.getResolvedSignature(node);
8097
+ if (signature) {
8098
+ const objectType = typeChecker.getParameterType(signature, 0);
8099
+ const catchFunctionSymbol = typeChecker.getPropertyOfType(objectType, "catch");
8100
+ if (catchFunctionSymbol) {
8101
+ const catchFunctionType = typeChecker.getTypeOfSymbolAtLocation(catchFunctionSymbol, node);
8102
+ const signatures = typeChecker.getSignaturesOfType(catchFunctionType, ts.SignatureKind.Call);
8103
+ if (signatures.length > 0) {
8104
+ const returnType = typeChecker.getReturnTypeOfSignature(signatures[0]);
8105
+ if (returnType && typeCheckerUtils.isGlobalErrorType(returnType)) {
8106
+ const nodeText = sourceFile.text.substring(
8107
+ ts.getTokenPosOfNode(node.expression, sourceFile),
8108
+ node.expression.end
8109
+ );
8110
+ report({
8111
+ location: node.expression,
8112
+ messageText: `The 'catch' callback in ${nodeText} returns the global Error type. It's not recommended to use the global Error type in Effect failures as they can get merged together.
8113
+ Instead, use tagged errors or custom errors with a discriminator property to get properly type-checked errors.`,
8114
+ fixes: []
8115
+ });
8116
+ }
8117
+ }
8118
+ }
8119
+ }
8120
+ }
8121
+ }
8122
+ }
8123
+ })
8124
+ });
8125
+
7925
8126
  // src/diagnostics/globalErrorInEffectFailure.ts
7926
8127
  var globalErrorInEffectFailure = createDiagnostic({
7927
8128
  name: "globalErrorInEffectFailure",
@@ -7952,7 +8153,7 @@ var globalErrorInEffectFailure = createDiagnostic({
7952
8153
  return sync(
7953
8154
  () => report({
7954
8155
  location: node,
7955
- messageText: `Effect.fail is called with the global Error type. It's not recommended to use the global Error type in Effect failures as they can get merged together. Instead, use tagged errors (Data.TaggedError) or custom errors with a discriminator property to get properly type-checked errors.`,
8156
+ messageText: `Effect.fail is called with the global Error type. It's not recommended to use the global Error type in Effect failures as they can get merged together. Instead, use tagged errors or custom errors with a discriminator property to get properly type-checked errors.`,
7956
8157
  fixes: []
7957
8158
  })
7958
8159
  );
@@ -8107,6 +8308,119 @@ var importFromBarrel = createDiagnostic({
8107
8308
  })
8108
8309
  });
8109
8310
 
8311
+ // src/diagnostics/layerMergeAllWithDependencies.ts
8312
+ var layerMergeAllWithDependencies = createDiagnostic({
8313
+ name: "layerMergeAllWithDependencies",
8314
+ code: 37,
8315
+ description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
8316
+ severity: "warning",
8317
+ apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
8318
+ const ts = yield* service(TypeScriptApi);
8319
+ const typeChecker = yield* service(TypeCheckerApi);
8320
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
8321
+ const typeParser = yield* service(TypeParser);
8322
+ const tsUtils = yield* service(TypeScriptUtils);
8323
+ const layerModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
8324
+ sourceFile,
8325
+ "effect",
8326
+ "Layer"
8327
+ ) || "Layer";
8328
+ const nodeToVisit = [];
8329
+ const appendNodeToVisit = (node) => {
8330
+ nodeToVisit.push(node);
8331
+ return void 0;
8332
+ };
8333
+ ts.forEachChild(sourceFile, appendNodeToVisit);
8334
+ while (nodeToVisit.length > 0) {
8335
+ const node = nodeToVisit.shift();
8336
+ if (ts.isCallExpression(node)) {
8337
+ const checkLayerMergeAll = yield* pipe(
8338
+ typeParser.isNodeReferenceToEffectLayerModuleApi("mergeAll")(node.expression),
8339
+ orElse2(() => void_)
8340
+ );
8341
+ if (checkLayerMergeAll) {
8342
+ const layerArgs = node.arguments;
8343
+ if (layerArgs.length > 1) {
8344
+ const layerInfos = [];
8345
+ const actuallyProvidedMap = /* @__PURE__ */ new Map();
8346
+ for (const arg of layerArgs) {
8347
+ const argType = typeCheckerUtils.getTypeAtLocation(arg);
8348
+ if (!argType) continue;
8349
+ const layerTypeParsedOption = yield* option(typeParser.layerType(argType, arg));
8350
+ if (isNone2(layerTypeParsedOption)) continue;
8351
+ const layerTypeParsed = layerTypeParsedOption.value;
8352
+ const providedMembers = typeCheckerUtils.unrollUnionMembers(layerTypeParsed.ROut);
8353
+ for (const providedType of providedMembers) {
8354
+ if (providedType.flags & ts.TypeFlags.Never) continue;
8355
+ const isPassThrough = typeChecker.isTypeAssignableTo(providedType, layerTypeParsed.RIn);
8356
+ if (!isPassThrough) {
8357
+ actuallyProvidedMap.set(providedType, arg);
8358
+ }
8359
+ }
8360
+ layerInfos.push({
8361
+ arg,
8362
+ requirementsType: layerTypeParsed.RIn
8363
+ });
8364
+ }
8365
+ const providerToConsumers = /* @__PURE__ */ new Map();
8366
+ for (const layer of layerInfos) {
8367
+ for (const [providedType, providerArg] of actuallyProvidedMap) {
8368
+ if (providerArg === layer.arg) continue;
8369
+ if (typeChecker.isTypeAssignableTo(providedType, layer.requirementsType)) {
8370
+ const consumers = providerToConsumers.get(providerArg) || [];
8371
+ consumers.push({ consumer: layer.arg, providedType });
8372
+ providerToConsumers.set(providerArg, consumers);
8373
+ }
8374
+ }
8375
+ }
8376
+ for (const [providerArg, consumers] of providerToConsumers) {
8377
+ const providedTypes = Array.from(new Set(consumers.map((c) => typeChecker.typeToString(c.providedType)))).join(", ");
8378
+ report({
8379
+ location: providerArg,
8380
+ messageText: `This layer provides ${providedTypes} which is required by another layer in the same Layer.mergeAll call. Layer.mergeAll creates layers in parallel, so dependencies between layers will not be satisfied. Consider moving this layer into a Layer.provideMerge after the Layer.mergeAll.`,
8381
+ fixes: [{
8382
+ fixName: "layerMergeAllWithDependencies_fix",
8383
+ description: "Move layer to Layer.provideMerge",
8384
+ apply: gen(function* () {
8385
+ const changeTracker = yield* service(ChangeTracker);
8386
+ const providerIndex = layerArgs.indexOf(providerArg);
8387
+ if (providerIndex === -1) return;
8388
+ const providerArgNode = providerArg;
8389
+ if (providerIndex === 0 && layerArgs.length > 1) {
8390
+ changeTracker.deleteRange(sourceFile, {
8391
+ pos: providerArgNode.pos,
8392
+ end: layerArgs[1].pos
8393
+ });
8394
+ } else if (providerIndex > 0) {
8395
+ changeTracker.deleteRange(sourceFile, {
8396
+ pos: layerArgs[providerIndex - 1].end,
8397
+ end: providerArgNode.end
8398
+ });
8399
+ }
8400
+ const provideMergeCall = ts.factory.createCallExpression(
8401
+ ts.factory.createPropertyAccessExpression(
8402
+ ts.factory.createIdentifier(layerModuleIdentifier),
8403
+ ts.factory.createIdentifier("provideMerge")
8404
+ ),
8405
+ void 0,
8406
+ [providerArgNode]
8407
+ );
8408
+ changeTracker.insertNodeAt(sourceFile, node.end, provideMergeCall, {
8409
+ prefix: ".pipe("
8410
+ });
8411
+ changeTracker.insertText(sourceFile, node.end, ")");
8412
+ })
8413
+ }]
8414
+ });
8415
+ }
8416
+ }
8417
+ }
8418
+ }
8419
+ ts.forEachChild(node, appendNodeToVisit);
8420
+ }
8421
+ })
8422
+ });
8423
+
8110
8424
  // src/diagnostics/leakingRequirements.ts
8111
8425
  var leakingRequirements = createDiagnostic({
8112
8426
  name: "leakingRequirements",
@@ -8205,6 +8519,7 @@ var leakingRequirements = createDiagnostic({
8205
8519
  location: node,
8206
8520
  messageText: `This Service is leaking the ${requirements.map((_) => typeChecker.typeToString(_)).join(" | ")} requirement.
8207
8521
  If these requirements cannot be cached and are expected to be provided per method invocation (e.g. HttpServerRequest), you can either safely disable this diagnostic for this line through quickfixes or mark the service declaration with a JSDoc @effect-leakable-service.
8522
+ Services should usually be collected in the layer creation body, and then provided at each method that requires them.
8208
8523
  More info at https://effect.website/docs/requirements-management/layers/#avoiding-requirement-leakage`,
8209
8524
  fixes: []
8210
8525
  });
@@ -8614,6 +8929,55 @@ var missingEffectServiceDependency = createDiagnostic({
8614
8929
  })
8615
8930
  });
8616
8931
 
8932
+ // src/diagnostics/missingLayerContext.ts
8933
+ var missingLayerContext = createDiagnostic({
8934
+ name: "missingLayerContext",
8935
+ code: 38,
8936
+ description: "Reports missing service requirements in Layer context channel",
8937
+ severity: "error",
8938
+ apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
8939
+ const typeChecker = yield* service(TypeCheckerApi);
8940
+ const typeParser = yield* service(TypeParser);
8941
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
8942
+ const checkForMissingContextTypes = (node, expectedType, valueNode, realType) => pipe(
8943
+ all(
8944
+ typeParser.layerType(expectedType, node),
8945
+ typeParser.layerType(realType, valueNode)
8946
+ ),
8947
+ map8(
8948
+ ([expectedLayer, realLayer]) => typeCheckerUtils.getMissingTypeEntriesInTargetType(
8949
+ realLayer.RIn,
8950
+ expectedLayer.RIn
8951
+ )
8952
+ )
8953
+ );
8954
+ const sortTypes = sort(typeCheckerUtils.deterministicTypeOrder);
8955
+ const entries2 = getEffectLspPatchSourceFileMetadata(sourceFile)?.relationErrors || typeCheckerUtils.expectedAndRealType(sourceFile);
8956
+ for (const [node, expectedType, valueNode, realType] of entries2) {
8957
+ if (expectedType !== realType) {
8958
+ yield* pipe(
8959
+ checkForMissingContextTypes(
8960
+ node,
8961
+ expectedType,
8962
+ valueNode,
8963
+ realType
8964
+ ),
8965
+ map8(
8966
+ (missingTypes) => missingTypes.length > 0 ? report(
8967
+ {
8968
+ location: node,
8969
+ messageText: `Missing '${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Layer context.`,
8970
+ fixes: []
8971
+ }
8972
+ ) : void 0
8973
+ ),
8974
+ ignore
8975
+ );
8976
+ }
8977
+ }
8978
+ })
8979
+ });
8980
+
8617
8981
  // src/diagnostics/missingReturnYieldStar.ts
8618
8982
  var missingReturnYieldStar = createDiagnostic({
8619
8983
  name: "missingReturnYieldStar",
@@ -10069,9 +10433,10 @@ var unsupportedServiceAccessors = createDiagnostic({
10069
10433
  );
10070
10434
  if (missingMembers.length > 0) {
10071
10435
  const memberNames = missingMembers.map(({ property }) => `'${ts.symbolName(property)}'`).join(", ");
10436
+ const suggestedFix = parseResult.kind === "effectTag" ? "\nEffect.Tag does not allow to disable accessors, so you may want to use Context.Tag instead." : "";
10072
10437
  report({
10073
10438
  location: parseResult.className,
10074
- messageText: `Even if accessors are enabled, accessors for ${memberNames} won't be available because the signature have generic type parameters or multiple call signatures.`,
10439
+ messageText: `Even if accessors are enabled, accessors for ${memberNames} won't be available because the signature have generic type parameters or multiple call signatures.${suggestedFix}`,
10075
10440
  fixes: [{
10076
10441
  fixName: "unsupportedServiceAccessors_enableCodegen",
10077
10442
  description: "Enable accessors codegen",
@@ -10092,6 +10457,7 @@ var unsupportedServiceAccessors = createDiagnostic({
10092
10457
  // src/diagnostics.ts
10093
10458
  var diagnostics = [
10094
10459
  anyUnknownInErrorContext,
10460
+ catchAllToMapError,
10095
10461
  catchUnfailableEffect,
10096
10462
  classSelfMismatch,
10097
10463
  duplicatePackage,
@@ -10099,6 +10465,7 @@ var diagnostics = [
10099
10465
  missingEffectContext,
10100
10466
  missingEffectError,
10101
10467
  missingEffectServiceDependency,
10468
+ missingLayerContext,
10102
10469
  floatingEffect,
10103
10470
  missingStarInYieldEffectGen,
10104
10471
  unnecessaryEffectGen,
@@ -10126,7 +10493,9 @@ var diagnostics = [
10126
10493
  runEffectInsideEffect,
10127
10494
  schemaUnionOfLiterals,
10128
10495
  schemaStructWithTag,
10129
- globalErrorInEffectFailure
10496
+ globalErrorInEffectCatch,
10497
+ globalErrorInEffectFailure,
10498
+ layerMergeAllWithDependencies
10130
10499
  ];
10131
10500
 
10132
10501
  // src/completions/effectDiagnosticsComment.ts
@@ -11010,13 +11379,6 @@ var addImportCodeAction = fn("getImportFromNamespaceCodeActions")(function* (for
11010
11379
  preferences: preferences || {}
11011
11380
  },
11012
11381
  (changeTracker) => {
11013
- if (effectAutoImport.introducedPrefix) {
11014
- changeTracker.insertText(
11015
- sourceFile,
11016
- effectReplaceSpan.start,
11017
- effectAutoImport.introducedPrefix + "."
11018
- );
11019
- }
11020
11382
  description = addImport(
11021
11383
  ts,
11022
11384
  sourceFile,
@@ -11024,6 +11386,13 @@ var addImportCodeAction = fn("getImportFromNamespaceCodeActions")(function* (for
11024
11386
  preferences,
11025
11387
  effectAutoImport
11026
11388
  ).description;
11389
+ if (effectAutoImport.introducedPrefix) {
11390
+ changeTracker.insertText(
11391
+ sourceFile,
11392
+ effectReplaceSpan.start,
11393
+ effectAutoImport.introducedPrefix + "."
11394
+ );
11395
+ }
11027
11396
  }
11028
11397
  );
11029
11398
  return [
@@ -15714,6 +16083,7 @@ var extractLayerGraph = fn("extractLayerGraph")(function* (node, opts) {
15714
16083
  const extractNodeInfo = fn("extractNodeInfo")(function* (node2) {
15715
16084
  let provides = [];
15716
16085
  let requires = [];
16086
+ let actualProvides = [];
15717
16087
  let layerType = void 0;
15718
16088
  let layerTypes = void 0;
15719
16089
  if (nodeInPipeContext.has(node2)) {
@@ -15736,12 +16106,13 @@ var extractLayerGraph = fn("extractLayerGraph")(function* (node, opts) {
15736
16106
  if (layerTypes) {
15737
16107
  provides = typeCheckerUtils.unrollUnionMembers(layerTypes.ROut).filter((_) => !(_.flags & ts.TypeFlags.Never));
15738
16108
  requires = typeCheckerUtils.unrollUnionMembers(layerTypes.RIn).filter((_) => !(_.flags & ts.TypeFlags.Never));
16109
+ actualProvides = provides.filter((_) => !typeChecker.isTypeAssignableTo(_, layerTypes.RIn));
15739
16110
  }
15740
16111
  let displayNode = node2;
15741
16112
  if (node2.parent && ts.isVariableDeclaration(node2.parent) && node2.parent.initializer === node2) {
15742
16113
  displayNode = node2.parent.name;
15743
16114
  }
15744
- return { node: node2, displayNode, layerType, layerTypes, provides, requires };
16115
+ return { node: node2, displayNode, layerType, layerTypes, provides, actualProvides, requires };
15745
16116
  });
15746
16117
  const addNode2 = fn("addNode")(function* (node2, nodeInfo) {
15747
16118
  const graphNode = addNode(mutableGraph, nodeInfo ? nodeInfo : yield* extractNodeInfo(node2));
@@ -15988,10 +16359,10 @@ var extractOutlineGraph = fn("extractOutlineGraph")(function* (layerGraph) {
15988
16359
  node: leafNode.node,
15989
16360
  displayNode: leafNode.displayNode,
15990
16361
  requires: leafNode.requires,
15991
- provides: leafNode.provides
16362
+ provides: leafNode.provides,
16363
+ actualProvides: leafNode.actualProvides
15992
16364
  });
15993
- for (const providedType of leafNode.provides) {
15994
- if (leafNode.requires.indexOf(providedType) > -1) continue;
16365
+ for (const providedType of leafNode.actualProvides) {
15995
16366
  const previousProviders = providers.get(providedType) || [];
15996
16367
  providers.set(providedType, [...previousProviders, nodeIndex]);
15997
16368
  }
@@ -16087,17 +16458,21 @@ var convertOutlineGraphToLayerMagic = fn("convertOutlineGraphToLayerMagic")(
16087
16458
  reverse(number2),
16088
16459
  (_) => _.provides.length
16089
16460
  );
16461
+ const orderByRequiredCount = mapInput(
16462
+ reverse(number2),
16463
+ (_) => _.requires.length
16464
+ );
16465
+ const layerOrder = combine2(orderByProvidedCount, orderByRequiredCount);
16090
16466
  const reversedGraph = mutate2(outlineGraph, reverse4);
16091
16467
  const rootIndexes = fromIterable(indices(externals(reversedGraph, { direction: "incoming" })));
16092
16468
  const allNodes = fromIterable(
16093
- values2(dfsPostOrderWithOrder(reversedGraph, { start: rootIndexes, order: orderByProvidedCount }))
16469
+ values2(dfsPostOrderWithOrder(reversedGraph, { start: rootIndexes, order: layerOrder }))
16094
16470
  );
16095
16471
  for (const nodeInfo of allNodes) {
16096
16472
  if (!ts.isExpression(nodeInfo.node)) continue;
16097
- const reallyProvidedTypes = nodeInfo.provides.filter((_) => nodeInfo.requires.indexOf(_) === -1);
16098
- const shouldMerge = reallyProvidedTypes.some((_) => missingOutputTypes.has(_));
16473
+ const shouldMerge = nodeInfo.actualProvides.some((_) => missingOutputTypes.has(_));
16099
16474
  if (shouldMerge) {
16100
- reallyProvidedTypes.forEach((_) => missingOutputTypes.delete(_));
16475
+ nodeInfo.actualProvides.forEach((_) => missingOutputTypes.delete(_));
16101
16476
  }
16102
16477
  nodeInfo.provides.forEach((_) => currentRequiredTypes.delete(_));
16103
16478
  nodeInfo.requires.forEach((_) => currentRequiredTypes.add(_));