@effect/language-service 0.69.2 → 0.71.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 +2 -1
- package/cli.js +103 -24
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +102 -23
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +102 -23
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +102 -23
- package/transform.js.map +1 -1
package/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -5484,6 +5484,57 @@ var effectMapVoid = createDiagnostic({
|
|
|
5484
5484
|
})
|
|
5485
5485
|
});
|
|
5486
5486
|
|
|
5487
|
+
// src/diagnostics/effectSucceedWithVoid.ts
|
|
5488
|
+
var effectSucceedWithVoid = createDiagnostic({
|
|
5489
|
+
name: "effectSucceedWithVoid",
|
|
5490
|
+
code: 47,
|
|
5491
|
+
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
5492
|
+
severity: "suggestion",
|
|
5493
|
+
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
5494
|
+
const ts = yield* service(TypeScriptApi);
|
|
5495
|
+
const typeParser = yield* service(TypeParser);
|
|
5496
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
5497
|
+
const nodeToVisit = [];
|
|
5498
|
+
const appendNodeToVisit = (node) => {
|
|
5499
|
+
nodeToVisit.push(node);
|
|
5500
|
+
return void 0;
|
|
5501
|
+
};
|
|
5502
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
5503
|
+
while (nodeToVisit.length > 0) {
|
|
5504
|
+
const node = nodeToVisit.shift();
|
|
5505
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
5506
|
+
if (ts.isCallExpression(node)) {
|
|
5507
|
+
const isSucceedCall = yield* pipe(
|
|
5508
|
+
typeParser.isNodeReferenceToEffectModuleApi("succeed")(node.expression),
|
|
5509
|
+
option
|
|
5510
|
+
);
|
|
5511
|
+
if (isSome2(isSucceedCall)) {
|
|
5512
|
+
const argument = node.arguments[0];
|
|
5513
|
+
if (!argument) continue;
|
|
5514
|
+
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
5515
|
+
report({
|
|
5516
|
+
location: node,
|
|
5517
|
+
messageText: "Effect.void can be used instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
5518
|
+
fixes: [{
|
|
5519
|
+
fixName: "effectSucceedWithVoid_fix",
|
|
5520
|
+
description: "Replace with Effect.void",
|
|
5521
|
+
apply: gen(function* () {
|
|
5522
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5523
|
+
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
5524
|
+
const newNode = ts.factory.createPropertyAccessExpression(
|
|
5525
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
5526
|
+
ts.factory.createIdentifier("void")
|
|
5527
|
+
);
|
|
5528
|
+
changeTracker.replaceNode(sourceFile, node, newNode);
|
|
5529
|
+
})
|
|
5530
|
+
}]
|
|
5531
|
+
});
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
})
|
|
5536
|
+
});
|
|
5537
|
+
|
|
5487
5538
|
// src/diagnostics/floatingEffect.ts
|
|
5488
5539
|
var floatingEffect = createDiagnostic({
|
|
5489
5540
|
name: "floatingEffect",
|
|
@@ -5627,8 +5678,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
5627
5678
|
);
|
|
5628
5679
|
report({
|
|
5629
5680
|
location: node.expression,
|
|
5630
|
-
messageText: `The 'catch' callback in ${nodeText} returns
|
|
5631
|
-
Instead, use tagged errors or custom errors with a discriminator property to get properly type-checked errors.`,
|
|
5681
|
+
messageText: `The 'catch' callback in ${nodeText} returns global 'Error', which loses type safety as untagged errors merge together. Consider using a tagged error and optionally wrapping the original in a 'cause' property.`,
|
|
5632
5682
|
fixes: []
|
|
5633
5683
|
});
|
|
5634
5684
|
}
|
|
@@ -5645,7 +5695,7 @@ Instead, use tagged errors or custom errors with a discriminator property to get
|
|
|
5645
5695
|
var globalErrorInEffectFailure = createDiagnostic({
|
|
5646
5696
|
name: "globalErrorInEffectFailure",
|
|
5647
5697
|
code: 35,
|
|
5648
|
-
description: "Warns when
|
|
5698
|
+
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
5649
5699
|
severity: "warning",
|
|
5650
5700
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
5651
5701
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5660,27 +5710,35 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
5660
5710
|
while (nodeToVisit.length > 0) {
|
|
5661
5711
|
const node = nodeToVisit.shift();
|
|
5662
5712
|
ts.forEachChild(node, appendNodeToVisit);
|
|
5663
|
-
if (ts.
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5713
|
+
if (ts.isNewExpression(node)) {
|
|
5714
|
+
const newExpressionType = typeCheckerUtils.getTypeAtLocation(node);
|
|
5715
|
+
if (!newExpressionType || !typeCheckerUtils.isGlobalErrorType(newExpressionType)) {
|
|
5716
|
+
continue;
|
|
5717
|
+
}
|
|
5718
|
+
let current = node.parent;
|
|
5719
|
+
while (current) {
|
|
5720
|
+
const currentType = typeCheckerUtils.getTypeAtLocation(current);
|
|
5721
|
+
if (currentType) {
|
|
5722
|
+
const effectTypeResult = yield* pipe(
|
|
5723
|
+
typeParser.effectType(currentType, current),
|
|
5724
|
+
option
|
|
5725
|
+
);
|
|
5726
|
+
if (effectTypeResult._tag === "Some") {
|
|
5727
|
+
const effectType = effectTypeResult.value;
|
|
5728
|
+
const failureMembers = typeCheckerUtils.unrollUnionMembers(effectType.E);
|
|
5729
|
+
const hasGlobalError = failureMembers.some((member) => typeCheckerUtils.isGlobalErrorType(member));
|
|
5730
|
+
if (hasGlobalError) {
|
|
5731
|
+
report({
|
|
5732
|
+
location: node,
|
|
5733
|
+
messageText: `Global 'Error' loses type safety as untagged errors merge together in the Effect failure channel. Consider using a tagged error and optionally wrapping the original in a 'cause' property.`,
|
|
5734
|
+
fixes: []
|
|
5735
|
+
});
|
|
5678
5736
|
}
|
|
5737
|
+
break;
|
|
5679
5738
|
}
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
);
|
|
5739
|
+
}
|
|
5740
|
+
current = current.parent;
|
|
5741
|
+
}
|
|
5684
5742
|
}
|
|
5685
5743
|
}
|
|
5686
5744
|
})
|
|
@@ -6269,9 +6327,29 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
6269
6327
|
transformations: flow2.transformations.slice(0, firstPipeableIndex)
|
|
6270
6328
|
});
|
|
6271
6329
|
const afterTransformations = flow2.transformations.slice(pipeableEndIndex);
|
|
6330
|
+
const getOriginalSubjectNode = () => {
|
|
6331
|
+
if (firstPipeableIndex === 0) {
|
|
6332
|
+
return flow2.subject.node;
|
|
6333
|
+
}
|
|
6334
|
+
let current = flow2.node;
|
|
6335
|
+
for (let i = flow2.transformations.length; i > firstPipeableIndex; i--) {
|
|
6336
|
+
const t = flow2.transformations[i - 1];
|
|
6337
|
+
if (t.kind === "call" && ts.isCallExpression(current) && current.arguments.length > 0) {
|
|
6338
|
+
current = current.arguments[0];
|
|
6339
|
+
} else {
|
|
6340
|
+
return void 0;
|
|
6341
|
+
}
|
|
6342
|
+
}
|
|
6343
|
+
return current;
|
|
6344
|
+
};
|
|
6345
|
+
const originalSubjectNode = getOriginalSubjectNode();
|
|
6346
|
+
const subjectText = originalSubjectNode ? sourceFile.text.slice(
|
|
6347
|
+
ts.getTokenPosOfNode(originalSubjectNode, sourceFile),
|
|
6348
|
+
originalSubjectNode.end
|
|
6349
|
+
).trim() : "";
|
|
6272
6350
|
report({
|
|
6273
6351
|
location: flow2.node,
|
|
6274
|
-
messageText: `Nested function calls can be converted to pipeable style for better readability.`,
|
|
6352
|
+
messageText: `Nested function calls can be converted to pipeable style for better readability; consider using ${subjectText}.pipe(...) instead.`,
|
|
6275
6353
|
fixes: [{
|
|
6276
6354
|
fixName: "missedPipeableOpportunity_fix",
|
|
6277
6355
|
description: "Convert to pipe style",
|
|
@@ -9359,6 +9437,7 @@ var diagnostics = [
|
|
|
9359
9437
|
globalErrorInEffectFailure,
|
|
9360
9438
|
layerMergeAllWithDependencies,
|
|
9361
9439
|
effectMapVoid,
|
|
9440
|
+
effectSucceedWithVoid,
|
|
9362
9441
|
effectFnIife,
|
|
9363
9442
|
effectFnOpportunity,
|
|
9364
9443
|
redundantSchemaTagIdentifier,
|