@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
|
@@ -5488,6 +5488,57 @@ var effectMapVoid = createDiagnostic({
|
|
|
5488
5488
|
})
|
|
5489
5489
|
});
|
|
5490
5490
|
|
|
5491
|
+
// src/diagnostics/effectSucceedWithVoid.ts
|
|
5492
|
+
var effectSucceedWithVoid = createDiagnostic({
|
|
5493
|
+
name: "effectSucceedWithVoid",
|
|
5494
|
+
code: 47,
|
|
5495
|
+
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
5496
|
+
severity: "suggestion",
|
|
5497
|
+
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
5498
|
+
const ts = yield* service(TypeScriptApi);
|
|
5499
|
+
const typeParser = yield* service(TypeParser);
|
|
5500
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
5501
|
+
const nodeToVisit = [];
|
|
5502
|
+
const appendNodeToVisit = (node) => {
|
|
5503
|
+
nodeToVisit.push(node);
|
|
5504
|
+
return void 0;
|
|
5505
|
+
};
|
|
5506
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
5507
|
+
while (nodeToVisit.length > 0) {
|
|
5508
|
+
const node = nodeToVisit.shift();
|
|
5509
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
5510
|
+
if (ts.isCallExpression(node)) {
|
|
5511
|
+
const isSucceedCall = yield* pipe(
|
|
5512
|
+
typeParser.isNodeReferenceToEffectModuleApi("succeed")(node.expression),
|
|
5513
|
+
option
|
|
5514
|
+
);
|
|
5515
|
+
if (isSome2(isSucceedCall)) {
|
|
5516
|
+
const argument = node.arguments[0];
|
|
5517
|
+
if (!argument) continue;
|
|
5518
|
+
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
5519
|
+
report({
|
|
5520
|
+
location: node,
|
|
5521
|
+
messageText: "Effect.void can be used instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
5522
|
+
fixes: [{
|
|
5523
|
+
fixName: "effectSucceedWithVoid_fix",
|
|
5524
|
+
description: "Replace with Effect.void",
|
|
5525
|
+
apply: gen(function* () {
|
|
5526
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
5527
|
+
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
5528
|
+
const newNode = ts.factory.createPropertyAccessExpression(
|
|
5529
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
5530
|
+
ts.factory.createIdentifier("void")
|
|
5531
|
+
);
|
|
5532
|
+
changeTracker.replaceNode(sourceFile, node, newNode);
|
|
5533
|
+
})
|
|
5534
|
+
}]
|
|
5535
|
+
});
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
})
|
|
5540
|
+
});
|
|
5541
|
+
|
|
5491
5542
|
// src/diagnostics/floatingEffect.ts
|
|
5492
5543
|
var floatingEffect = createDiagnostic({
|
|
5493
5544
|
name: "floatingEffect",
|
|
@@ -5631,8 +5682,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
5631
5682
|
);
|
|
5632
5683
|
report({
|
|
5633
5684
|
location: node.expression,
|
|
5634
|
-
messageText: `The 'catch' callback in ${nodeText} returns
|
|
5635
|
-
Instead, use tagged errors or custom errors with a discriminator property to get properly type-checked errors.`,
|
|
5685
|
+
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.`,
|
|
5636
5686
|
fixes: []
|
|
5637
5687
|
});
|
|
5638
5688
|
}
|
|
@@ -5649,7 +5699,7 @@ Instead, use tagged errors or custom errors with a discriminator property to get
|
|
|
5649
5699
|
var globalErrorInEffectFailure = createDiagnostic({
|
|
5650
5700
|
name: "globalErrorInEffectFailure",
|
|
5651
5701
|
code: 35,
|
|
5652
|
-
description: "Warns when
|
|
5702
|
+
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
5653
5703
|
severity: "warning",
|
|
5654
5704
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
5655
5705
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -5664,27 +5714,35 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
5664
5714
|
while (nodeToVisit.length > 0) {
|
|
5665
5715
|
const node = nodeToVisit.shift();
|
|
5666
5716
|
ts.forEachChild(node, appendNodeToVisit);
|
|
5667
|
-
if (ts.
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5717
|
+
if (ts.isNewExpression(node)) {
|
|
5718
|
+
const newExpressionType = typeCheckerUtils.getTypeAtLocation(node);
|
|
5719
|
+
if (!newExpressionType || !typeCheckerUtils.isGlobalErrorType(newExpressionType)) {
|
|
5720
|
+
continue;
|
|
5721
|
+
}
|
|
5722
|
+
let current = node.parent;
|
|
5723
|
+
while (current) {
|
|
5724
|
+
const currentType = typeCheckerUtils.getTypeAtLocation(current);
|
|
5725
|
+
if (currentType) {
|
|
5726
|
+
const effectTypeResult = yield* pipe(
|
|
5727
|
+
typeParser.effectType(currentType, current),
|
|
5728
|
+
option
|
|
5729
|
+
);
|
|
5730
|
+
if (effectTypeResult._tag === "Some") {
|
|
5731
|
+
const effectType = effectTypeResult.value;
|
|
5732
|
+
const failureMembers = typeCheckerUtils.unrollUnionMembers(effectType.E);
|
|
5733
|
+
const hasGlobalError = failureMembers.some((member) => typeCheckerUtils.isGlobalErrorType(member));
|
|
5734
|
+
if (hasGlobalError) {
|
|
5735
|
+
report({
|
|
5736
|
+
location: node,
|
|
5737
|
+
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.`,
|
|
5738
|
+
fixes: []
|
|
5739
|
+
});
|
|
5682
5740
|
}
|
|
5741
|
+
break;
|
|
5683
5742
|
}
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
);
|
|
5743
|
+
}
|
|
5744
|
+
current = current.parent;
|
|
5745
|
+
}
|
|
5688
5746
|
}
|
|
5689
5747
|
}
|
|
5690
5748
|
})
|
|
@@ -6273,9 +6331,29 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
6273
6331
|
transformations: flow2.transformations.slice(0, firstPipeableIndex)
|
|
6274
6332
|
});
|
|
6275
6333
|
const afterTransformations = flow2.transformations.slice(pipeableEndIndex);
|
|
6334
|
+
const getOriginalSubjectNode = () => {
|
|
6335
|
+
if (firstPipeableIndex === 0) {
|
|
6336
|
+
return flow2.subject.node;
|
|
6337
|
+
}
|
|
6338
|
+
let current = flow2.node;
|
|
6339
|
+
for (let i = flow2.transformations.length; i > firstPipeableIndex; i--) {
|
|
6340
|
+
const t = flow2.transformations[i - 1];
|
|
6341
|
+
if (t.kind === "call" && ts.isCallExpression(current) && current.arguments.length > 0) {
|
|
6342
|
+
current = current.arguments[0];
|
|
6343
|
+
} else {
|
|
6344
|
+
return void 0;
|
|
6345
|
+
}
|
|
6346
|
+
}
|
|
6347
|
+
return current;
|
|
6348
|
+
};
|
|
6349
|
+
const originalSubjectNode = getOriginalSubjectNode();
|
|
6350
|
+
const subjectText = originalSubjectNode ? sourceFile.text.slice(
|
|
6351
|
+
ts.getTokenPosOfNode(originalSubjectNode, sourceFile),
|
|
6352
|
+
originalSubjectNode.end
|
|
6353
|
+
).trim() : "";
|
|
6276
6354
|
report({
|
|
6277
6355
|
location: flow2.node,
|
|
6278
|
-
messageText: `Nested function calls can be converted to pipeable style for better readability.`,
|
|
6356
|
+
messageText: `Nested function calls can be converted to pipeable style for better readability; consider using ${subjectText}.pipe(...) instead.`,
|
|
6279
6357
|
fixes: [{
|
|
6280
6358
|
fixName: "missedPipeableOpportunity_fix",
|
|
6281
6359
|
description: "Convert to pipe style",
|
|
@@ -9363,6 +9441,7 @@ var diagnostics = [
|
|
|
9363
9441
|
globalErrorInEffectFailure,
|
|
9364
9442
|
layerMergeAllWithDependencies,
|
|
9365
9443
|
effectMapVoid,
|
|
9444
|
+
effectSucceedWithVoid,
|
|
9366
9445
|
effectFnIife,
|
|
9367
9446
|
effectFnOpportunity,
|
|
9368
9447
|
redundantSchemaTagIdentifier,
|