@effect/language-service 0.25.1 → 0.27.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/index.js CHANGED
@@ -2674,11 +2674,16 @@ function make3(ts, typeChecker) {
2674
2674
  const pipeCall = cachedBy(
2675
2675
  function(node) {
2676
2676
  if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
2677
- return succeed({ node, subject: node.expression.expression, args: Array.from(node.arguments) });
2677
+ return succeed({
2678
+ node,
2679
+ subject: node.expression.expression,
2680
+ args: Array.from(node.arguments),
2681
+ kind: "pipeable"
2682
+ });
2678
2683
  }
2679
2684
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
2680
2685
  const [subject, ...args2] = node.arguments;
2681
- return succeed({ node, subject, args: args2 });
2686
+ return succeed({ node, subject, args: args2, kind: "pipe" });
2682
2687
  }
2683
2688
  return typeParserIssue("Node is not a pipe call", void 0, node);
2684
2689
  },
@@ -2717,6 +2722,7 @@ function make3(ts, typeChecker) {
2717
2722
  unnecessaryEffectGen: unnecessaryEffectGen2,
2718
2723
  effectSchemaType,
2719
2724
  contextTag,
2725
+ pipeableType,
2720
2726
  pipeCall,
2721
2727
  scopeType
2722
2728
  };
@@ -3602,10 +3608,77 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
3602
3608
  })
3603
3609
  });
3604
3610
 
3611
+ // src/diagnostics/strictBooleanExpressions.ts
3612
+ var strictBooleanExpressions = createDiagnostic({
3613
+ name: "strictBooleanExpressions",
3614
+ code: 17,
3615
+ severity: "off",
3616
+ apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
3617
+ const ts = yield* service(TypeScriptApi);
3618
+ const typeChecker = yield* service(TypeCheckerApi);
3619
+ const conditionChecks = /* @__PURE__ */ new WeakMap();
3620
+ const nodeToVisit = [];
3621
+ const appendNodeToVisit = (node) => {
3622
+ nodeToVisit.push(node);
3623
+ return void 0;
3624
+ };
3625
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3626
+ while (nodeToVisit.length > 0) {
3627
+ const node = nodeToVisit.shift();
3628
+ ts.forEachChild(node, appendNodeToVisit);
3629
+ const nodes = [];
3630
+ if (ts.isIfStatement(node)) {
3631
+ conditionChecks.set(node, true);
3632
+ nodes.push(node.expression);
3633
+ } else if (ts.isWhileStatement(node)) {
3634
+ conditionChecks.set(node, true);
3635
+ nodes.push(node.expression);
3636
+ } else if (ts.isConditionalExpression(node)) {
3637
+ conditionChecks.set(node, true);
3638
+ nodes.push(node.condition);
3639
+ } else if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
3640
+ conditionChecks.set(node, true);
3641
+ nodes.push(node.operand);
3642
+ } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
3643
+ if (conditionChecks.has(node.parent)) conditionChecks.set(node, true);
3644
+ nodes.push(node.left);
3645
+ nodes.push(node.right);
3646
+ } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
3647
+ if (conditionChecks.has(node.parent)) conditionChecks.set(node, true);
3648
+ nodes.push(node.left);
3649
+ nodes.push(node.right);
3650
+ }
3651
+ for (const nodeToCheck of nodes) {
3652
+ if (!nodeToCheck) continue;
3653
+ if (!conditionChecks.has(nodeToCheck.parent)) continue;
3654
+ const nodeType = typeChecker.getTypeAtLocation(nodeToCheck);
3655
+ const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
3656
+ let typesToCheck = [constrainedType || nodeType];
3657
+ while (typesToCheck.length > 0) {
3658
+ const type = typesToCheck.pop();
3659
+ if (type.isUnion()) {
3660
+ typesToCheck = typesToCheck.concat(type.types);
3661
+ continue;
3662
+ }
3663
+ if (type.flags & ts.TypeFlags.Boolean) continue;
3664
+ if (type.flags & ts.TypeFlags.Never) continue;
3665
+ if (type.flags & ts.TypeFlags.BooleanLiteral) continue;
3666
+ const typeName = typeChecker.typeToString(type);
3667
+ report({
3668
+ node: nodeToCheck,
3669
+ messageText: `Unexpected \`${typeName}\` type in condition, expected strictly a boolean instead.`,
3670
+ fixes: []
3671
+ });
3672
+ }
3673
+ }
3674
+ }
3675
+ })
3676
+ });
3677
+
3605
3678
  // src/diagnostics/tryCatchInEffectGen.ts
3606
3679
  var tryCatchInEffectGen = createDiagnostic({
3607
3680
  name: "tryCatchInEffectGen",
3608
- code: 12,
3681
+ code: 15,
3609
3682
  severity: "suggestion",
3610
3683
  apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
3611
3684
  const ts = yield* service(TypeScriptApi);
@@ -3735,6 +3808,80 @@ var unnecessaryPipe = createDiagnostic({
3735
3808
  })
3736
3809
  });
3737
3810
 
3811
+ // src/diagnostics/unnecessaryPipeChain.ts
3812
+ var unnecessaryPipeChain = createDiagnostic({
3813
+ name: "unnecessaryPipeChain",
3814
+ code: 16,
3815
+ severity: "suggestion",
3816
+ apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
3817
+ const ts = yield* service(TypeScriptApi);
3818
+ const typeParser = yield* service(TypeParser);
3819
+ const nodeToVisit = [];
3820
+ const appendNodeToVisit = (node) => {
3821
+ nodeToVisit.push(node);
3822
+ return void 0;
3823
+ };
3824
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3825
+ while (nodeToVisit.length > 0) {
3826
+ const node = nodeToVisit.shift();
3827
+ ts.forEachChild(node, appendNodeToVisit);
3828
+ if (ts.isCallExpression(node)) {
3829
+ yield* pipe(
3830
+ typeParser.pipeCall(node),
3831
+ flatMap2(
3832
+ (pipeCall) => map4(typeParser.pipeCall(pipeCall.subject), (innerCall) => ({ pipeCall, innerCall }))
3833
+ ),
3834
+ map4(({ innerCall, pipeCall }) => {
3835
+ report({
3836
+ node,
3837
+ messageText: `Chained pipe calls can be simplified to a single pipe call`,
3838
+ fixes: [{
3839
+ fixName: "unnecessaryPipeChain_fix",
3840
+ description: "Rewrite as single pipe call",
3841
+ apply: gen(function* () {
3842
+ const changeTracker = yield* service(
3843
+ ChangeTracker
3844
+ );
3845
+ switch (innerCall.kind) {
3846
+ case "pipe": {
3847
+ changeTracker.replaceNode(
3848
+ sourceFile,
3849
+ node,
3850
+ ts.factory.createCallExpression(
3851
+ ts.factory.createIdentifier("pipe"),
3852
+ void 0,
3853
+ [innerCall.subject, ...innerCall.args, ...pipeCall.args]
3854
+ )
3855
+ );
3856
+ break;
3857
+ }
3858
+ case "pipeable": {
3859
+ changeTracker.replaceNode(
3860
+ sourceFile,
3861
+ node,
3862
+ ts.factory.createCallExpression(
3863
+ ts.factory.createPropertyAccessExpression(
3864
+ innerCall.subject,
3865
+ "pipe"
3866
+ ),
3867
+ void 0,
3868
+ [...innerCall.args, ...pipeCall.args]
3869
+ )
3870
+ );
3871
+ break;
3872
+ }
3873
+ }
3874
+ })
3875
+ }]
3876
+ });
3877
+ }),
3878
+ ignore
3879
+ );
3880
+ }
3881
+ }
3882
+ })
3883
+ });
3884
+
3738
3885
  // src/diagnostics.ts
3739
3886
  var diagnostics = [
3740
3887
  duplicatePackage,
@@ -3751,7 +3898,9 @@ var diagnostics = [
3751
3898
  tryCatchInEffectGen,
3752
3899
  importFromBarrel,
3753
3900
  scopeInLayerEffect,
3754
- effectInVoidSuccess
3901
+ effectInVoidSuccess,
3902
+ unnecessaryPipeChain,
3903
+ strictBooleanExpressions
3755
3904
  ];
3756
3905
 
3757
3906
  // src/completions/effectDiagnosticsComment.ts
@@ -9928,6 +10077,66 @@ var toggleLazyConst = createRefactor({
9928
10077
  })
9929
10078
  });
9930
10079
 
10080
+ // src/refactors/togglePipeStyle.ts
10081
+ var togglePipeStyle = createRefactor({
10082
+ name: "togglePipeStyle",
10083
+ description: "Toggle pipe style",
10084
+ apply: fn("togglePipeStyle.apply")(function* (sourceFile, textRange) {
10085
+ const ts = yield* service(TypeScriptApi);
10086
+ const typeChecker = yield* service(TypeCheckerApi);
10087
+ const typeParser = yield* service(TypeParser);
10088
+ const togglePipeStyle2 = (node) => gen(function* () {
10089
+ const pipeCall = yield* typeParser.pipeCall(node);
10090
+ switch (pipeCall.kind) {
10091
+ case "pipe": {
10092
+ yield* typeParser.pipeableType(typeChecker.getTypeAtLocation(pipeCall.subject), pipeCall.subject);
10093
+ return {
10094
+ kind: "refactor.rewrite.effect.togglePipeStyle",
10095
+ description: "Rewrite as X.pipe(Y, Z, ...)",
10096
+ apply: gen(function* () {
10097
+ const changeTracker = yield* service(ChangeTracker);
10098
+ changeTracker.replaceNode(
10099
+ sourceFile,
10100
+ node,
10101
+ ts.factory.createCallExpression(
10102
+ ts.factory.createPropertyAccessExpression(
10103
+ pipeCall.subject,
10104
+ "pipe"
10105
+ ),
10106
+ void 0,
10107
+ pipeCall.args
10108
+ )
10109
+ );
10110
+ })
10111
+ };
10112
+ }
10113
+ case "pipeable":
10114
+ return {
10115
+ kind: "refactor.rewrite.effect.togglePipeStyle",
10116
+ description: "Rewrite as pipe(X, Y, Z, ...)",
10117
+ apply: gen(function* () {
10118
+ const changeTracker = yield* service(ChangeTracker);
10119
+ changeTracker.replaceNode(
10120
+ sourceFile,
10121
+ node,
10122
+ ts.factory.createCallExpression(
10123
+ ts.factory.createIdentifier("pipe"),
10124
+ void 0,
10125
+ [pipeCall.subject].concat(pipeCall.args)
10126
+ )
10127
+ );
10128
+ })
10129
+ };
10130
+ }
10131
+ });
10132
+ const ancestorNodes = yield* getAncestorNodesInRange(sourceFile, textRange);
10133
+ return yield* pipe(
10134
+ firstSuccessOf(ancestorNodes.map(togglePipeStyle2)),
10135
+ orElse2(() => fail(new RefactorNotApplicableError()))
10136
+ );
10137
+ })
10138
+ });
10139
+
9931
10140
  // src/refactors/toggleReturnTypeAnnotation.ts
9932
10141
  var toggleReturnTypeAnnotation = createRefactor({
9933
10142
  name: "toggleReturnTypeAnnotation",
@@ -10644,7 +10853,8 @@ var refactors = [
10644
10853
  toggleTypeAnnotation,
10645
10854
  wrapWithEffectGen,
10646
10855
  wrapWithPipe,
10647
- effectGenToFn
10856
+ effectGenToFn,
10857
+ togglePipeStyle
10648
10858
  ];
10649
10859
 
10650
10860
  // src/index.ts