@effect/language-service 0.55.2 → 0.55.3
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/cli.js +171 -13
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +166 -4
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +253 -27
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +171 -13
- package/transform.js.map +1 -1
package/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -870,8 +870,9 @@ var contAll = Symbol.for("Nano.contAll");
|
|
|
870
870
|
var NanoYield = Symbol.for("Nano.yield");
|
|
871
871
|
var args = Symbol.for("Nano.args");
|
|
872
872
|
var NanoDefectException = class {
|
|
873
|
-
constructor(message) {
|
|
873
|
+
constructor(message, lastSpan) {
|
|
874
874
|
this.message = message;
|
|
875
|
+
this.lastSpan = lastSpan;
|
|
875
876
|
}
|
|
876
877
|
_tag = "@effect/language-service/NanoDefectException";
|
|
877
878
|
};
|
|
@@ -929,6 +930,7 @@ var NanoFiber = class {
|
|
|
929
930
|
_services = {};
|
|
930
931
|
_cache = {};
|
|
931
932
|
_perf = false;
|
|
933
|
+
_lastSpan = "";
|
|
932
934
|
runLoop(nano) {
|
|
933
935
|
let current = nano;
|
|
934
936
|
while (true) {
|
|
@@ -959,17 +961,21 @@ var WithSpanProto = {
|
|
|
959
961
|
[evaluate](fiber) {
|
|
960
962
|
const [fa, name] = this[args];
|
|
961
963
|
if (!fiber._perf) return fa;
|
|
964
|
+
const previousSpan = fiber._lastSpan;
|
|
965
|
+
fiber._lastSpan = name;
|
|
962
966
|
const start = performance.now();
|
|
963
967
|
timingsCount[name] = (timingsCount[name] || 0) + 1;
|
|
964
968
|
return match(fa, {
|
|
965
969
|
onSuccess: (_) => {
|
|
966
970
|
const end = performance.now();
|
|
967
971
|
timings[name] = (timings[name] || 0) + (end - start);
|
|
972
|
+
fiber._lastSpan = previousSpan;
|
|
968
973
|
return succeed(_);
|
|
969
974
|
},
|
|
970
975
|
onFailure: (_) => {
|
|
971
976
|
const end = performance.now();
|
|
972
977
|
timings[name] = (timings[name] || 0) + (end - start);
|
|
978
|
+
fiber._lastSpan = previousSpan;
|
|
973
979
|
return fail(_);
|
|
974
980
|
}
|
|
975
981
|
});
|
|
@@ -980,19 +986,16 @@ var withSpan = (name) => (fa) => {
|
|
|
980
986
|
nano[args] = [fa, name];
|
|
981
987
|
return nano;
|
|
982
988
|
};
|
|
983
|
-
var unsafeRun = (nano) => {
|
|
984
|
-
const fiber = new NanoFiber();
|
|
985
|
-
const result = fiber.runLoop(nano);
|
|
986
|
-
if (result._tag === "Success") {
|
|
987
|
-
return right2(result.value);
|
|
988
|
-
}
|
|
989
|
-
return left2(result.value);
|
|
990
|
-
};
|
|
991
989
|
var run = (nano) => {
|
|
990
|
+
const fiber = new NanoFiber();
|
|
992
991
|
try {
|
|
993
|
-
|
|
992
|
+
const result = fiber.runLoop(nano);
|
|
993
|
+
if (result._tag === "Success") {
|
|
994
|
+
return right2(result.value);
|
|
995
|
+
}
|
|
996
|
+
return left2(result.value);
|
|
994
997
|
} catch (e) {
|
|
995
|
-
return left2(new NanoDefectException(e));
|
|
998
|
+
return left2(new NanoDefectException(e, fiber._lastSpan));
|
|
996
999
|
}
|
|
997
1000
|
};
|
|
998
1001
|
var OnSuccessProto = {
|
|
@@ -1099,7 +1102,7 @@ var ServiceProto = {
|
|
|
1099
1102
|
return cont2 ? cont2[contA](value, fiber) : fiber.yieldWith(succeed(value));
|
|
1100
1103
|
}
|
|
1101
1104
|
const cont = fiber.getCont(contE);
|
|
1102
|
-
return cont ? cont[contE](tag, fiber) : fiber.yieldWith(fail(new NanoDefectException(`Service ${tag.key} not found
|
|
1105
|
+
return cont ? cont[contE](tag, fiber) : fiber.yieldWith(fail(new NanoDefectException(`Service ${tag.key} not found`, fiber._lastSpan)));
|
|
1103
1106
|
}
|
|
1104
1107
|
};
|
|
1105
1108
|
var service = (tag) => {
|
|
@@ -1767,6 +1770,30 @@ function makeTypeScriptUtils(ts) {
|
|
|
1767
1770
|
}
|
|
1768
1771
|
return node;
|
|
1769
1772
|
}
|
|
1773
|
+
function isOuterExpression(node, kinds = ts.OuterExpressionKinds.All) {
|
|
1774
|
+
switch (node.kind) {
|
|
1775
|
+
case ts.SyntaxKind.ParenthesizedExpression:
|
|
1776
|
+
return (kinds & ts.OuterExpressionKinds.Parentheses) !== 0;
|
|
1777
|
+
case ts.SyntaxKind.TypeAssertionExpression:
|
|
1778
|
+
case ts.SyntaxKind.AsExpression:
|
|
1779
|
+
return (kinds & ts.OuterExpressionKinds.TypeAssertions) !== 0;
|
|
1780
|
+
case ts.SyntaxKind.SatisfiesExpression:
|
|
1781
|
+
return (kinds & (ts.OuterExpressionKinds.TypeAssertions | ts.OuterExpressionKinds.Satisfies)) !== 0;
|
|
1782
|
+
case ts.SyntaxKind.ExpressionWithTypeArguments:
|
|
1783
|
+
return (kinds & ts.OuterExpressionKinds.ExpressionsWithTypeArguments) !== 0;
|
|
1784
|
+
case ts.SyntaxKind.NonNullExpression:
|
|
1785
|
+
return (kinds & ts.OuterExpressionKinds.NonNullAssertions) !== 0;
|
|
1786
|
+
case ts.SyntaxKind.PartiallyEmittedExpression:
|
|
1787
|
+
return (kinds & ts.OuterExpressionKinds.PartiallyEmittedExpressions) !== 0;
|
|
1788
|
+
}
|
|
1789
|
+
return false;
|
|
1790
|
+
}
|
|
1791
|
+
function skipOuterExpressions(node, kinds = ts.OuterExpressionKinds.All) {
|
|
1792
|
+
while (isOuterExpression(node, kinds)) {
|
|
1793
|
+
node = node.expression;
|
|
1794
|
+
}
|
|
1795
|
+
return node;
|
|
1796
|
+
}
|
|
1770
1797
|
return {
|
|
1771
1798
|
findNodeAtPositionIncludingTrivia,
|
|
1772
1799
|
parsePackageContentNameAndVersionFromScope,
|
|
@@ -1787,7 +1814,9 @@ function makeTypeScriptUtils(ts) {
|
|
|
1787
1814
|
createEffectGenCallExpressionWithBlock,
|
|
1788
1815
|
createReturnYieldStarStatement,
|
|
1789
1816
|
parseAccessedExpressionForCompletion,
|
|
1790
|
-
getSourceFileOfNode
|
|
1817
|
+
getSourceFileOfNode,
|
|
1818
|
+
isOuterExpression,
|
|
1819
|
+
skipOuterExpressions
|
|
1791
1820
|
};
|
|
1792
1821
|
}
|
|
1793
1822
|
|
|
@@ -1872,6 +1901,14 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
1872
1901
|
result = node2;
|
|
1873
1902
|
return;
|
|
1874
1903
|
}
|
|
1904
|
+
if (ts.isPropertyAssignment(node2)) {
|
|
1905
|
+
const realStart = ts.getTokenPosOfNode(node2, sourceFile);
|
|
1906
|
+
const starts = sourceFile.getLineStarts().filter((start) => start >= node2.pos && start <= realStart);
|
|
1907
|
+
if (starts.length > 0) {
|
|
1908
|
+
result = node2;
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1875
1912
|
if (result) return;
|
|
1876
1913
|
if (node2.parent) find(node2.parent);
|
|
1877
1914
|
}
|
|
@@ -3566,6 +3603,103 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3566
3603
|
};
|
|
3567
3604
|
}
|
|
3568
3605
|
|
|
3606
|
+
// src/diagnostics/anyUnknownInErrorContext.ts
|
|
3607
|
+
var anyUnknownInErrorContext = createDiagnostic({
|
|
3608
|
+
name: "anyUnknownInErrorContext",
|
|
3609
|
+
code: 28,
|
|
3610
|
+
severity: "off",
|
|
3611
|
+
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
3612
|
+
const ts = yield* service(TypeScriptApi);
|
|
3613
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3614
|
+
const typeParser = yield* service(TypeParser);
|
|
3615
|
+
const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
|
|
3616
|
+
const matchingNodes = [];
|
|
3617
|
+
const nodeToVisit = [sourceFile];
|
|
3618
|
+
const appendNodeToVisit = (node) => {
|
|
3619
|
+
nodeToVisit.push(node);
|
|
3620
|
+
return void 0;
|
|
3621
|
+
};
|
|
3622
|
+
while (nodeToVisit.length > 0) {
|
|
3623
|
+
const node = nodeToVisit.pop();
|
|
3624
|
+
if (ts.isTypeNode(node)) continue;
|
|
3625
|
+
if (ts.isTypeAliasDeclaration(node)) continue;
|
|
3626
|
+
if (ts.isInterfaceDeclaration(node)) continue;
|
|
3627
|
+
if (ts.isAsExpression(node) && node.type && node.type.kind === ts.SyntaxKind.AnyKeyword) {
|
|
3628
|
+
continue;
|
|
3629
|
+
}
|
|
3630
|
+
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
3631
|
+
if (node.type) {
|
|
3632
|
+
const type2 = typeChecker.getTypeAtLocation(node.type);
|
|
3633
|
+
const expectedEffect = yield* pipe(
|
|
3634
|
+
typeParser.strictEffectType(type2, node.type),
|
|
3635
|
+
orElse2(() => void_)
|
|
3636
|
+
);
|
|
3637
|
+
if (expectedEffect) continue;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3641
|
+
if (!ts.isExpression(node)) continue;
|
|
3642
|
+
let type = typeChecker.getTypeAtLocation(node);
|
|
3643
|
+
if (ts.isCallExpression(node)) {
|
|
3644
|
+
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
3645
|
+
if (resolvedSignature) {
|
|
3646
|
+
type = typeChecker.getReturnTypeOfSignature(resolvedSignature);
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
if (!type) continue;
|
|
3650
|
+
yield* pipe(
|
|
3651
|
+
typeParser.strictEffectType(type, node),
|
|
3652
|
+
map4((effect) => {
|
|
3653
|
+
const { E, R } = effect;
|
|
3654
|
+
const hasAnyUnknownR = isAnyOrUnknown(R);
|
|
3655
|
+
const hasAnyUnknownE = isAnyOrUnknown(E);
|
|
3656
|
+
if (hasAnyUnknownR || hasAnyUnknownE) {
|
|
3657
|
+
const channels = [];
|
|
3658
|
+
if (hasAnyUnknownR) {
|
|
3659
|
+
const typeName = R.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3660
|
+
channels.push(`${typeName} in the requirements channel`);
|
|
3661
|
+
}
|
|
3662
|
+
if (hasAnyUnknownE) {
|
|
3663
|
+
const typeName = E.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3664
|
+
channels.push(`${typeName} in the error channel`);
|
|
3665
|
+
}
|
|
3666
|
+
const nodeStart = ts.getTokenPosOfNode(node, sourceFile);
|
|
3667
|
+
const nodeEnd = node.end;
|
|
3668
|
+
for (let i = matchingNodes.length - 1; i >= 0; i--) {
|
|
3669
|
+
const existing = matchingNodes[i];
|
|
3670
|
+
const existingStart = ts.getTokenPosOfNode(existing.node, sourceFile);
|
|
3671
|
+
const existingEnd = existing.node.end;
|
|
3672
|
+
if (existingStart <= nodeStart && existingEnd >= nodeEnd) {
|
|
3673
|
+
matchingNodes.splice(i, 1);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
const suggestions = [`This Effect has ${channels.join(" and ")} which is not recommended.`];
|
|
3677
|
+
if (hasAnyUnknownR) {
|
|
3678
|
+
suggestions.push(`Only service identifiers should appear in the requirements channel.`);
|
|
3679
|
+
}
|
|
3680
|
+
if (hasAnyUnknownE) {
|
|
3681
|
+
suggestions.push(
|
|
3682
|
+
`Having an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example.`
|
|
3683
|
+
);
|
|
3684
|
+
}
|
|
3685
|
+
channels.push(`If you plan to later on manually cast the type, you can safely disable this diagnostic.`);
|
|
3686
|
+
const messageText = suggestions.join("\n");
|
|
3687
|
+
matchingNodes.push({ messageText, node, type });
|
|
3688
|
+
}
|
|
3689
|
+
}),
|
|
3690
|
+
ignore
|
|
3691
|
+
);
|
|
3692
|
+
}
|
|
3693
|
+
for (const { messageText, node } of matchingNodes) {
|
|
3694
|
+
report({
|
|
3695
|
+
location: node,
|
|
3696
|
+
messageText,
|
|
3697
|
+
fixes: []
|
|
3698
|
+
});
|
|
3699
|
+
}
|
|
3700
|
+
})
|
|
3701
|
+
});
|
|
3702
|
+
|
|
3569
3703
|
// src/diagnostics/catchUnfailableEffect.ts
|
|
3570
3704
|
var catchUnfailableEffect = createDiagnostic({
|
|
3571
3705
|
name: "catchUnfailableEffect",
|
|
@@ -5424,6 +5558,26 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5424
5558
|
const ts = yield* service(TypeScriptApi);
|
|
5425
5559
|
const typeParser = yield* service(TypeParser);
|
|
5426
5560
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5561
|
+
function isAllowedConstructor(node) {
|
|
5562
|
+
if (node.body && node.body.statements.length === 1) {
|
|
5563
|
+
const expressionStatement = node.body.statements[0];
|
|
5564
|
+
if (ts.isExpressionStatement(expressionStatement)) {
|
|
5565
|
+
const maybeCallSuper = expressionStatement.expression;
|
|
5566
|
+
if (ts.isCallExpression(maybeCallSuper)) {
|
|
5567
|
+
if (maybeCallSuper.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
5568
|
+
const expectedNames = node.parameters.map((_) => _.name).filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5569
|
+
if (expectedNames.length === 2 && expectedNames.length === node.parameters.length) {
|
|
5570
|
+
const givenNames = maybeCallSuper.arguments.filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5571
|
+
if (givenNames.length === expectedNames.length && givenNames.every((name, index) => name === expectedNames[index])) {
|
|
5572
|
+
return true;
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
return false;
|
|
5580
|
+
}
|
|
5427
5581
|
const nodeToVisit = [];
|
|
5428
5582
|
const appendNodeToVisit = (node) => {
|
|
5429
5583
|
nodeToVisit.push(node);
|
|
@@ -5455,6 +5609,9 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5455
5609
|
const members = node.members;
|
|
5456
5610
|
for (const member of members) {
|
|
5457
5611
|
if (ts.isConstructorDeclaration(member)) {
|
|
5612
|
+
if (isAllowedConstructor(member)) {
|
|
5613
|
+
continue;
|
|
5614
|
+
}
|
|
5458
5615
|
const fixAsStaticNew = {
|
|
5459
5616
|
fixName: "overriddenSchemaConstructor_static",
|
|
5460
5617
|
description: "Rewrite using the static 'new' pattern",
|
|
@@ -6252,6 +6409,7 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
6252
6409
|
|
|
6253
6410
|
// src/diagnostics.ts
|
|
6254
6411
|
var diagnostics = [
|
|
6412
|
+
anyUnknownInErrorContext,
|
|
6255
6413
|
catchUnfailableEffect,
|
|
6256
6414
|
classSelfMismatch,
|
|
6257
6415
|
duplicatePackage,
|