@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/README.md +5 -2
- package/cli.js +153 -4
- package/cli.js.map +1 -1
- package/index.js +215 -5
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +153 -4
- package/transform.js.map +1 -1
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({
|
|
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:
|
|
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
|