@effect/language-service 0.68.0 → 0.69.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.
@@ -4855,6 +4855,104 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
4855
4855
  })
4856
4856
  });
4857
4857
 
4858
+ // src/diagnostics/effectFnIife.ts
4859
+ var effectFnIife = createDiagnostic({
4860
+ name: "effectFnIife",
4861
+ code: 46,
4862
+ description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
4863
+ severity: "warning",
4864
+ apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
4865
+ const ts = yield* service(TypeScriptApi);
4866
+ const typeParser = yield* service(TypeParser);
4867
+ const tsUtils = yield* service(TypeScriptUtils);
4868
+ const sourceEffectModuleName = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
4869
+ sourceFile,
4870
+ "effect",
4871
+ "Effect"
4872
+ ) || "Effect";
4873
+ const nodeToVisit = [];
4874
+ const appendNodeToVisit = (node) => {
4875
+ nodeToVisit.push(node);
4876
+ return void 0;
4877
+ };
4878
+ ts.forEachChild(sourceFile, appendNodeToVisit);
4879
+ while (nodeToVisit.length > 0) {
4880
+ const node = nodeToVisit.shift();
4881
+ ts.forEachChild(node, appendNodeToVisit);
4882
+ if (!ts.isCallExpression(node)) continue;
4883
+ const innerCall = node.expression;
4884
+ if (!ts.isCallExpression(innerCall)) continue;
4885
+ const parsed = yield* pipe(
4886
+ typeParser.effectFnGen(innerCall),
4887
+ map4((result) => ({
4888
+ kind: "fn",
4889
+ effectModule: result.effectModule,
4890
+ generatorFunction: result.generatorFunction,
4891
+ pipeArguments: result.pipeArguments
4892
+ })),
4893
+ orElse2(
4894
+ () => pipe(
4895
+ typeParser.effectFnUntracedGen(innerCall),
4896
+ map4((result) => ({
4897
+ kind: "fnUntraced",
4898
+ effectModule: result.effectModule,
4899
+ generatorFunction: result.generatorFunction,
4900
+ pipeArguments: result.pipeArguments
4901
+ }))
4902
+ )
4903
+ ),
4904
+ orElse2(
4905
+ () => pipe(
4906
+ typeParser.effectFn(innerCall),
4907
+ map4((result) => ({
4908
+ kind: "fn",
4909
+ effectModule: result.effectModule,
4910
+ generatorFunction: void 0,
4911
+ pipeArguments: result.pipeArguments
4912
+ }))
4913
+ )
4914
+ ),
4915
+ option
4916
+ );
4917
+ if (isNone2(parsed)) continue;
4918
+ const { effectModule, generatorFunction, kind, pipeArguments: pipeArguments2 } = parsed.value;
4919
+ const effectModuleName = ts.isIdentifier(effectModule) ? ts.idText(effectModule) : sourceEffectModuleName;
4920
+ const fixes = [];
4921
+ if (generatorFunction && generatorFunction.parameters.length === 0) {
4922
+ fixes.push({
4923
+ fixName: "effectFnIife_toEffectGen",
4924
+ description: "Convert to Effect.gen",
4925
+ apply: gen(function* () {
4926
+ const changeTracker = yield* service(ChangeTracker);
4927
+ const effectGenCall = ts.factory.createCallExpression(
4928
+ ts.factory.createPropertyAccessExpression(
4929
+ ts.factory.createIdentifier(effectModuleName),
4930
+ "gen"
4931
+ ),
4932
+ void 0,
4933
+ [generatorFunction]
4934
+ );
4935
+ let replacementNode = effectGenCall;
4936
+ if (pipeArguments2.length > 0) {
4937
+ replacementNode = ts.factory.createCallExpression(
4938
+ ts.factory.createPropertyAccessExpression(effectGenCall, "pipe"),
4939
+ void 0,
4940
+ [...pipeArguments2]
4941
+ );
4942
+ }
4943
+ changeTracker.replaceNode(sourceFile, node, replacementNode);
4944
+ })
4945
+ });
4946
+ }
4947
+ report({
4948
+ location: node,
4949
+ messageText: `${effectModuleName}.${kind} returns a reusable function that can take arguments, but here it's called immediately. Use Effect.gen instead (optionally with Effect.withSpan for tracing).`,
4950
+ fixes
4951
+ });
4952
+ }
4953
+ })
4954
+ });
4955
+
4858
4956
  // src/diagnostics/effectFnOpportunity.ts
4859
4957
  var effectFnOpportunity = createDiagnostic({
4860
4958
  name: "effectFnOpportunity",
@@ -5120,9 +5218,11 @@ var effectFnOpportunity = createDiagnostic({
5120
5218
  });
5121
5219
  }
5122
5220
  const pipeArgsSuffix = pipeArguments2.length > 0 ? ` Effect.fn also accepts the piped transformations as additional arguments.` : ``;
5221
+ const suggestConsultingQuickFixes = ` Your editor quickfixes or the "effect-language-service" cli can show you how to convert to Effect.fn or Effect.fnUntraced.`;
5222
+ const orFnUntraced = target.value.generatorFunction ? `, or Effect.fnUntraced` : ``;
5123
5223
  report({
5124
5224
  location: nameIdentifier ?? targetNode,
5125
- messageText: target.value.generatorFunction ? `This function could benefit from Effect.fn's automatic tracing and concise syntax, or Effect.fnUntraced to get just a more concise syntax.${pipeArgsSuffix}` : `This function could benefit from Effect.fn's automatic tracing and concise syntax.${pipeArgsSuffix}`,
5225
+ messageText: `This function could benefit from Effect.fn's automatic tracing and concise syntax${orFnUntraced}.${pipeArgsSuffix}${suggestConsultingQuickFixes}`,
5126
5226
  fixes
5127
5227
  });
5128
5228
  }
@@ -9155,6 +9255,7 @@ var diagnostics = [
9155
9255
  globalErrorInEffectFailure,
9156
9256
  layerMergeAllWithDependencies,
9157
9257
  effectMapVoid,
9258
+ effectFnIife,
9158
9259
  effectFnOpportunity,
9159
9260
  redundantSchemaTagIdentifier,
9160
9261
  schemaSyncInEffect,