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