@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/README.md
CHANGED
|
@@ -47,6 +47,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
|
|
|
47
47
|
- Unnecessary usages of `Effect.gen` or `pipe()`
|
|
48
48
|
- Warn when importing from a barrel file instead of from the module directly
|
|
49
49
|
- Warn on usage of try/catch inside `Effect.gen` and family
|
|
50
|
+
- Detect unnecessary pipe chains like `X.pipe(Y).pipe(Z)`
|
|
50
51
|
|
|
51
52
|
### Completions
|
|
52
53
|
|
|
@@ -67,6 +68,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
|
|
|
67
68
|
- Toggle return type signature: With a single refactor, adds or removes type annotations from the definition.
|
|
68
69
|
- Remove unnecessary `Effect.gen` definitions that contains a single `yield` statement.
|
|
69
70
|
- Wrap an `Effect` expression with `Effect.gen`
|
|
71
|
+
- Toggle between pipe styles `X.pipe(Y)` and `pipe(X, Y)`
|
|
70
72
|
|
|
71
73
|
### Miscellaneous
|
|
72
74
|
- "Go to definition" for RpcClient will resolve to the Rpc definition
|
|
@@ -119,8 +121,9 @@ Your `tsconfig.json` should look like this:
|
|
|
119
121
|
|
|
120
122
|
To get diagnostics you need to install `ts-patch` which will make it possible to run `tspc`.
|
|
121
123
|
|
|
122
|
-
Running `tspc` in your project will now also run the plugin and give you the diagnostics at compile time.
|
|
123
|
-
Effect diagnostics will be shown only after standard TypeScript diagnostics have been satisfied.
|
|
124
|
+
Running `tspc` in your project will now also run the plugin and give you the error diagnostics at compile time.
|
|
125
|
+
Effect error diagnostics will be shown only after standard TypeScript diagnostics have been satisfied.
|
|
126
|
+
Beware that setting noEmit will completely skip the effect diagnostics.
|
|
124
127
|
|
|
125
128
|
```ts
|
|
126
129
|
$ npx tspc
|
package/cli.js
CHANGED
|
@@ -31428,11 +31428,16 @@ function make62(ts2, typeChecker) {
|
|
|
31428
31428
|
const pipeCall = cachedBy(
|
|
31429
31429
|
function(node) {
|
|
31430
31430
|
if (ts2.isCallExpression(node) && ts2.isPropertyAccessExpression(node.expression) && ts2.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
|
|
31431
|
-
return succeed17({
|
|
31431
|
+
return succeed17({
|
|
31432
|
+
node,
|
|
31433
|
+
subject: node.expression.expression,
|
|
31434
|
+
args: Array.from(node.arguments),
|
|
31435
|
+
kind: "pipeable"
|
|
31436
|
+
});
|
|
31432
31437
|
}
|
|
31433
31438
|
if (ts2.isCallExpression(node) && ts2.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
|
|
31434
31439
|
const [subject, ...args3] = node.arguments;
|
|
31435
|
-
return succeed17({ node, subject, args: args3 });
|
|
31440
|
+
return succeed17({ node, subject, args: args3, kind: "pipe" });
|
|
31436
31441
|
}
|
|
31437
31442
|
return typeParserIssue("Node is not a pipe call", void 0, node);
|
|
31438
31443
|
},
|
|
@@ -31471,6 +31476,7 @@ function make62(ts2, typeChecker) {
|
|
|
31471
31476
|
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
31472
31477
|
effectSchemaType,
|
|
31473
31478
|
contextTag,
|
|
31479
|
+
pipeableType,
|
|
31474
31480
|
pipeCall,
|
|
31475
31481
|
scopeType
|
|
31476
31482
|
};
|
|
@@ -32404,10 +32410,77 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
32404
32410
|
})
|
|
32405
32411
|
});
|
|
32406
32412
|
|
|
32413
|
+
// src/diagnostics/strictBooleanExpressions.ts
|
|
32414
|
+
var strictBooleanExpressions = createDiagnostic({
|
|
32415
|
+
name: "strictBooleanExpressions",
|
|
32416
|
+
code: 17,
|
|
32417
|
+
severity: "off",
|
|
32418
|
+
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
32419
|
+
const ts2 = yield* service2(TypeScriptApi);
|
|
32420
|
+
const typeChecker = yield* service2(TypeCheckerApi);
|
|
32421
|
+
const conditionChecks = /* @__PURE__ */ new WeakMap();
|
|
32422
|
+
const nodeToVisit = [];
|
|
32423
|
+
const appendNodeToVisit = (node) => {
|
|
32424
|
+
nodeToVisit.push(node);
|
|
32425
|
+
return void 0;
|
|
32426
|
+
};
|
|
32427
|
+
ts2.forEachChild(sourceFile, appendNodeToVisit);
|
|
32428
|
+
while (nodeToVisit.length > 0) {
|
|
32429
|
+
const node = nodeToVisit.shift();
|
|
32430
|
+
ts2.forEachChild(node, appendNodeToVisit);
|
|
32431
|
+
const nodes = [];
|
|
32432
|
+
if (ts2.isIfStatement(node)) {
|
|
32433
|
+
conditionChecks.set(node, true);
|
|
32434
|
+
nodes.push(node.expression);
|
|
32435
|
+
} else if (ts2.isWhileStatement(node)) {
|
|
32436
|
+
conditionChecks.set(node, true);
|
|
32437
|
+
nodes.push(node.expression);
|
|
32438
|
+
} else if (ts2.isConditionalExpression(node)) {
|
|
32439
|
+
conditionChecks.set(node, true);
|
|
32440
|
+
nodes.push(node.condition);
|
|
32441
|
+
} else if (ts2.isPrefixUnaryExpression(node) && node.operator === ts2.SyntaxKind.ExclamationToken) {
|
|
32442
|
+
conditionChecks.set(node, true);
|
|
32443
|
+
nodes.push(node.operand);
|
|
32444
|
+
} else if (ts2.isBinaryExpression(node) && node.operatorToken.kind === ts2.SyntaxKind.BarBarToken) {
|
|
32445
|
+
if (conditionChecks.has(node.parent)) conditionChecks.set(node, true);
|
|
32446
|
+
nodes.push(node.left);
|
|
32447
|
+
nodes.push(node.right);
|
|
32448
|
+
} else if (ts2.isBinaryExpression(node) && node.operatorToken.kind === ts2.SyntaxKind.AmpersandAmpersandToken) {
|
|
32449
|
+
if (conditionChecks.has(node.parent)) conditionChecks.set(node, true);
|
|
32450
|
+
nodes.push(node.left);
|
|
32451
|
+
nodes.push(node.right);
|
|
32452
|
+
}
|
|
32453
|
+
for (const nodeToCheck of nodes) {
|
|
32454
|
+
if (!nodeToCheck) continue;
|
|
32455
|
+
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
32456
|
+
const nodeType = typeChecker.getTypeAtLocation(nodeToCheck);
|
|
32457
|
+
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
32458
|
+
let typesToCheck = [constrainedType || nodeType];
|
|
32459
|
+
while (typesToCheck.length > 0) {
|
|
32460
|
+
const type2 = typesToCheck.pop();
|
|
32461
|
+
if (type2.isUnion()) {
|
|
32462
|
+
typesToCheck = typesToCheck.concat(type2.types);
|
|
32463
|
+
continue;
|
|
32464
|
+
}
|
|
32465
|
+
if (type2.flags & ts2.TypeFlags.Boolean) continue;
|
|
32466
|
+
if (type2.flags & ts2.TypeFlags.Never) continue;
|
|
32467
|
+
if (type2.flags & ts2.TypeFlags.BooleanLiteral) continue;
|
|
32468
|
+
const typeName = typeChecker.typeToString(type2);
|
|
32469
|
+
report({
|
|
32470
|
+
node: nodeToCheck,
|
|
32471
|
+
messageText: `Unexpected \`${typeName}\` type in condition, expected strictly a boolean instead.`,
|
|
32472
|
+
fixes: []
|
|
32473
|
+
});
|
|
32474
|
+
}
|
|
32475
|
+
}
|
|
32476
|
+
}
|
|
32477
|
+
})
|
|
32478
|
+
});
|
|
32479
|
+
|
|
32407
32480
|
// src/diagnostics/tryCatchInEffectGen.ts
|
|
32408
32481
|
var tryCatchInEffectGen = createDiagnostic({
|
|
32409
32482
|
name: "tryCatchInEffectGen",
|
|
32410
|
-
code:
|
|
32483
|
+
code: 15,
|
|
32411
32484
|
severity: "suggestion",
|
|
32412
32485
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
32413
32486
|
const ts2 = yield* service2(TypeScriptApi);
|
|
@@ -32537,6 +32610,80 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
32537
32610
|
})
|
|
32538
32611
|
});
|
|
32539
32612
|
|
|
32613
|
+
// src/diagnostics/unnecessaryPipeChain.ts
|
|
32614
|
+
var unnecessaryPipeChain = createDiagnostic({
|
|
32615
|
+
name: "unnecessaryPipeChain",
|
|
32616
|
+
code: 16,
|
|
32617
|
+
severity: "suggestion",
|
|
32618
|
+
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
32619
|
+
const ts2 = yield* service2(TypeScriptApi);
|
|
32620
|
+
const typeParser = yield* service2(TypeParser);
|
|
32621
|
+
const nodeToVisit = [];
|
|
32622
|
+
const appendNodeToVisit = (node) => {
|
|
32623
|
+
nodeToVisit.push(node);
|
|
32624
|
+
return void 0;
|
|
32625
|
+
};
|
|
32626
|
+
ts2.forEachChild(sourceFile, appendNodeToVisit);
|
|
32627
|
+
while (nodeToVisit.length > 0) {
|
|
32628
|
+
const node = nodeToVisit.shift();
|
|
32629
|
+
ts2.forEachChild(node, appendNodeToVisit);
|
|
32630
|
+
if (ts2.isCallExpression(node)) {
|
|
32631
|
+
yield* pipe(
|
|
32632
|
+
typeParser.pipeCall(node),
|
|
32633
|
+
flatMap18(
|
|
32634
|
+
(pipeCall) => map33(typeParser.pipeCall(pipeCall.subject), (innerCall) => ({ pipeCall, innerCall }))
|
|
32635
|
+
),
|
|
32636
|
+
map33(({ innerCall, pipeCall }) => {
|
|
32637
|
+
report({
|
|
32638
|
+
node,
|
|
32639
|
+
messageText: `Chained pipe calls can be simplified to a single pipe call`,
|
|
32640
|
+
fixes: [{
|
|
32641
|
+
fixName: "unnecessaryPipeChain_fix",
|
|
32642
|
+
description: "Rewrite as single pipe call",
|
|
32643
|
+
apply: gen3(function* () {
|
|
32644
|
+
const changeTracker = yield* service2(
|
|
32645
|
+
ChangeTracker
|
|
32646
|
+
);
|
|
32647
|
+
switch (innerCall.kind) {
|
|
32648
|
+
case "pipe": {
|
|
32649
|
+
changeTracker.replaceNode(
|
|
32650
|
+
sourceFile,
|
|
32651
|
+
node,
|
|
32652
|
+
ts2.factory.createCallExpression(
|
|
32653
|
+
ts2.factory.createIdentifier("pipe"),
|
|
32654
|
+
void 0,
|
|
32655
|
+
[innerCall.subject, ...innerCall.args, ...pipeCall.args]
|
|
32656
|
+
)
|
|
32657
|
+
);
|
|
32658
|
+
break;
|
|
32659
|
+
}
|
|
32660
|
+
case "pipeable": {
|
|
32661
|
+
changeTracker.replaceNode(
|
|
32662
|
+
sourceFile,
|
|
32663
|
+
node,
|
|
32664
|
+
ts2.factory.createCallExpression(
|
|
32665
|
+
ts2.factory.createPropertyAccessExpression(
|
|
32666
|
+
innerCall.subject,
|
|
32667
|
+
"pipe"
|
|
32668
|
+
),
|
|
32669
|
+
void 0,
|
|
32670
|
+
[...innerCall.args, ...pipeCall.args]
|
|
32671
|
+
)
|
|
32672
|
+
);
|
|
32673
|
+
break;
|
|
32674
|
+
}
|
|
32675
|
+
}
|
|
32676
|
+
})
|
|
32677
|
+
}]
|
|
32678
|
+
});
|
|
32679
|
+
}),
|
|
32680
|
+
ignore3
|
|
32681
|
+
);
|
|
32682
|
+
}
|
|
32683
|
+
}
|
|
32684
|
+
})
|
|
32685
|
+
});
|
|
32686
|
+
|
|
32540
32687
|
// src/diagnostics.ts
|
|
32541
32688
|
var diagnostics = [
|
|
32542
32689
|
duplicatePackage,
|
|
@@ -32553,7 +32700,9 @@ var diagnostics = [
|
|
|
32553
32700
|
tryCatchInEffectGen,
|
|
32554
32701
|
importFromBarrel,
|
|
32555
32702
|
scopeInLayerEffect,
|
|
32556
|
-
effectInVoidSuccess
|
|
32703
|
+
effectInVoidSuccess,
|
|
32704
|
+
unnecessaryPipeChain,
|
|
32705
|
+
strictBooleanExpressions
|
|
32557
32706
|
];
|
|
32558
32707
|
|
|
32559
32708
|
// src/cli.ts
|