@effect/language-service 0.57.0 → 0.57.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/cli.js CHANGED
@@ -35528,6 +35528,11 @@ var runEffectInsideEffect = createDiagnostic({
35528
35528
  apply: fn2("runEffectInsideEffect.apply")(function* (sourceFile, report) {
35529
35529
  const ts = yield* service2(TypeScriptApi);
35530
35530
  const typeParser = yield* service2(TypeParser);
35531
+ const tsUtils = yield* service2(TypeScriptUtils);
35532
+ const parseEffectMethod = (node, methodName) => pipe(
35533
+ typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
35534
+ map34(() => ({ node, methodName }))
35535
+ );
35531
35536
  const nodeToVisit = [];
35532
35537
  const appendNodeToVisit = (node) => {
35533
35538
  nodeToVisit.push(node);
@@ -35538,11 +35543,12 @@ var runEffectInsideEffect = createDiagnostic({
35538
35543
  const node = nodeToVisit.shift();
35539
35544
  ts.forEachChild(node, appendNodeToVisit);
35540
35545
  if (!ts.isCallExpression(node)) continue;
35546
+ if (node.arguments.length === 0) continue;
35541
35547
  const isEffectRunCall = yield* pipe(
35542
- typeParser.isNodeReferenceToEffectModuleApi("runPromise")(node.expression),
35543
- orElse14(() => typeParser.isNodeReferenceToEffectModuleApi("runSync")(node.expression)),
35544
- orElse14(() => typeParser.isNodeReferenceToEffectModuleApi("runFork")(node.expression)),
35545
- orElse14(() => typeParser.isNodeReferenceToEffectModuleApi("runCallback")(node.expression)),
35548
+ parseEffectMethod(node.expression, "runPromise"),
35549
+ orElse14(() => parseEffectMethod(node.expression, "runSync")),
35550
+ orElse14(() => parseEffectMethod(node.expression, "runFork")),
35551
+ orElse14(() => parseEffectMethod(node.expression, "runCallback")),
35546
35552
  option4
35547
35553
  );
35548
35554
  if (isNone2(isEffectRunCall)) continue;
@@ -35562,18 +35568,90 @@ var runEffectInsideEffect = createDiagnostic({
35562
35568
  orElse14(() => typeParser.effectFnGen(possiblyEffectGen)),
35563
35569
  option4
35564
35570
  );
35565
- if (isSome2(isInEffectGen)) {
35571
+ if (isSome2(isInEffectGen) && isInEffectGen.value.body.statements.length > 0) {
35566
35572
  const nodeText = sourceFile.text.substring(
35567
35573
  ts.getTokenPosOfNode(node.expression, sourceFile),
35568
35574
  node.expression.end
35569
35575
  );
35570
- const messageText = nodeIntroduceScope && nodeIntroduceScope !== isInEffectGen.value.generatorFunction ? `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
35571
- Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.run* with the extracted runtime instead.` : `Using ${nodeText} inside an Effect is not recommended. Effects inside generators can usually just be yielded.`;
35572
- report({
35573
- location: node.expression,
35574
- messageText,
35575
- fixes: []
35576
- });
35576
+ if (nodeIntroduceScope && nodeIntroduceScope !== isInEffectGen.value.generatorFunction) {
35577
+ const fixAddRuntime = gen3(function* () {
35578
+ const changeTracker = yield* service2(ChangeTracker);
35579
+ const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
35580
+ const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
35581
+ let runtimeIdentifier = void 0;
35582
+ for (const statement of isInEffectGen.value.generatorFunction.body.statements) {
35583
+ if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
35584
+ const declaration = statement.declarationList.declarations[0];
35585
+ if (declaration.initializer && ts.isYieldExpression(declaration.initializer) && declaration.initializer.asteriskToken && declaration.initializer.expression) {
35586
+ const yieldedExpression = declaration.initializer.expression;
35587
+ if (ts.isCallExpression(yieldedExpression)) {
35588
+ const maybeEffectRuntime = yield* pipe(
35589
+ typeParser.isNodeReferenceToEffectModuleApi("runtime")(yieldedExpression.expression),
35590
+ option4
35591
+ );
35592
+ if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
35593
+ runtimeIdentifier = ts.idText(declaration.name);
35594
+ }
35595
+ }
35596
+ }
35597
+ }
35598
+ }
35599
+ if (!runtimeIdentifier) {
35600
+ changeTracker.insertNodeAt(
35601
+ sourceFile,
35602
+ isInEffectGen.value.body.statements[0].pos,
35603
+ ts.factory.createVariableStatement(
35604
+ void 0,
35605
+ ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
35606
+ "effectRuntime",
35607
+ void 0,
35608
+ void 0,
35609
+ ts.factory.createYieldExpression(
35610
+ ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
35611
+ ts.factory.createCallExpression(
35612
+ ts.factory.createPropertyAccessExpression(
35613
+ ts.factory.createIdentifier(effectModuleIdentifier),
35614
+ "runtime"
35615
+ ),
35616
+ [ts.factory.createTypeReferenceNode("never")],
35617
+ []
35618
+ )
35619
+ )
35620
+ )], ts.NodeFlags.Const)
35621
+ ),
35622
+ {
35623
+ prefix: "\n",
35624
+ suffix: "\n"
35625
+ }
35626
+ );
35627
+ }
35628
+ changeTracker.deleteRange(sourceFile, {
35629
+ pos: ts.getTokenPosOfNode(node.expression, sourceFile),
35630
+ end: node.arguments[0].pos
35631
+ });
35632
+ changeTracker.insertText(
35633
+ sourceFile,
35634
+ node.arguments[0].pos,
35635
+ `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
35636
+ );
35637
+ });
35638
+ report({
35639
+ location: node.expression,
35640
+ messageText: `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
35641
+ Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
35642
+ fixes: [{
35643
+ fixName: "runEffectInsideEffect_fix",
35644
+ description: "Use a runtime to run the Effect",
35645
+ apply: fixAddRuntime
35646
+ }]
35647
+ });
35648
+ } else {
35649
+ report({
35650
+ location: node.expression,
35651
+ messageText: `Using ${nodeText} inside an Effect is not recommended. Effects inside generators can usually just be yielded.`,
35652
+ fixes: []
35653
+ });
35654
+ }
35577
35655
  }
35578
35656
  currentParent = currentParent.parent;
35579
35657
  }