@effect/language-service 0.55.2 → 0.55.4
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 +183 -21
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +178 -12
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +267 -37
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +183 -21
- 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
|
}
|
|
@@ -2483,6 +2524,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2483
2524
|
const getSourceFilesDeclaringSymbolModule = (packageName) => cachedBy(
|
|
2484
2525
|
fn("TypeParser.getSourceFilesDeclaringSymbolModule")(function* (symbol3) {
|
|
2485
2526
|
const result = [];
|
|
2527
|
+
if (!symbol3) return result;
|
|
2486
2528
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
2487
2529
|
for (const sourceFile of symbol3.declarations) {
|
|
2488
2530
|
if (!ts.isSourceFile(sourceFile)) continue;
|
|
@@ -2520,6 +2562,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2520
2562
|
const getSourceFilesDeclaringSymbolExportedUnderPackageModule = (packageName, memberName) => cachedBy(
|
|
2521
2563
|
fn("TypeParser.getSourceFilesDeclaringSymbolUnderPackageExportedMember")(function* (symbol3) {
|
|
2522
2564
|
const result = [];
|
|
2565
|
+
if (!symbol3) return result;
|
|
2523
2566
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
2524
2567
|
for (const declaration of symbol3.declarations) {
|
|
2525
2568
|
const sourceFile = tsUtils.getSourceFileOfNode(declaration);
|
|
@@ -2741,14 +2784,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2741
2784
|
);
|
|
2742
2785
|
const importedContextModule = cachedBy(
|
|
2743
2786
|
fn("TypeParser.importedContextModule")(function* (node) {
|
|
2787
|
+
if (!ts.isIdentifier(node)) {
|
|
2788
|
+
return yield* typeParserIssue("Node is not an identifier", void 0, node);
|
|
2789
|
+
}
|
|
2744
2790
|
const type = typeChecker.getTypeAtLocation(node);
|
|
2745
2791
|
const propertySymbol = typeChecker.getPropertyOfType(type, "Tag");
|
|
2746
2792
|
if (!propertySymbol) {
|
|
2747
2793
|
return yield* typeParserIssue("Type has no 'Tag' property", type, node);
|
|
2748
2794
|
}
|
|
2749
|
-
if (!ts.isIdentifier(node)) {
|
|
2750
|
-
return yield* typeParserIssue("Node is not an identifier", type, node);
|
|
2751
|
-
}
|
|
2752
2795
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2753
2796
|
if (!sourceFile) {
|
|
2754
2797
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -2775,14 +2818,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2775
2818
|
);
|
|
2776
2819
|
const importedDataModule = cachedBy(
|
|
2777
2820
|
fn("TypeParser.importedDataModule")(function* (node) {
|
|
2821
|
+
if (!ts.isIdentifier(node)) {
|
|
2822
|
+
return yield* typeParserIssue("Node is not an expression", void 0, node);
|
|
2823
|
+
}
|
|
2778
2824
|
const type = typeChecker.getTypeAtLocation(node);
|
|
2779
2825
|
const propertySymbol = typeChecker.getPropertyOfType(type, "TaggedError");
|
|
2780
2826
|
if (!propertySymbol) {
|
|
2781
2827
|
return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
|
|
2782
2828
|
}
|
|
2783
|
-
if (!ts.isIdentifier(node)) {
|
|
2784
|
-
return yield* typeParserIssue("Node is not an expression", type, node);
|
|
2785
|
-
}
|
|
2786
2829
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2787
2830
|
if (!sourceFile) {
|
|
2788
2831
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -3566,6 +3609,103 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3566
3609
|
};
|
|
3567
3610
|
}
|
|
3568
3611
|
|
|
3612
|
+
// src/diagnostics/anyUnknownInErrorContext.ts
|
|
3613
|
+
var anyUnknownInErrorContext = createDiagnostic({
|
|
3614
|
+
name: "anyUnknownInErrorContext",
|
|
3615
|
+
code: 28,
|
|
3616
|
+
severity: "off",
|
|
3617
|
+
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
3618
|
+
const ts = yield* service(TypeScriptApi);
|
|
3619
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3620
|
+
const typeParser = yield* service(TypeParser);
|
|
3621
|
+
const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
|
|
3622
|
+
const matchingNodes = [];
|
|
3623
|
+
const nodeToVisit = [sourceFile];
|
|
3624
|
+
const appendNodeToVisit = (node) => {
|
|
3625
|
+
nodeToVisit.push(node);
|
|
3626
|
+
return void 0;
|
|
3627
|
+
};
|
|
3628
|
+
while (nodeToVisit.length > 0) {
|
|
3629
|
+
const node = nodeToVisit.pop();
|
|
3630
|
+
if (ts.isTypeNode(node)) continue;
|
|
3631
|
+
if (ts.isTypeAliasDeclaration(node)) continue;
|
|
3632
|
+
if (ts.isInterfaceDeclaration(node)) continue;
|
|
3633
|
+
if (ts.isAsExpression(node) && node.type && node.type.kind === ts.SyntaxKind.AnyKeyword) {
|
|
3634
|
+
continue;
|
|
3635
|
+
}
|
|
3636
|
+
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
3637
|
+
if (node.type) {
|
|
3638
|
+
const type2 = typeChecker.getTypeAtLocation(node.type);
|
|
3639
|
+
const expectedEffect = yield* pipe(
|
|
3640
|
+
typeParser.strictEffectType(type2, node.type),
|
|
3641
|
+
orElse2(() => void_)
|
|
3642
|
+
);
|
|
3643
|
+
if (expectedEffect) continue;
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3647
|
+
if (!ts.isExpression(node)) continue;
|
|
3648
|
+
let type = typeChecker.getTypeAtLocation(node);
|
|
3649
|
+
if (ts.isCallExpression(node)) {
|
|
3650
|
+
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
3651
|
+
if (resolvedSignature) {
|
|
3652
|
+
type = typeChecker.getReturnTypeOfSignature(resolvedSignature);
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
if (!type) continue;
|
|
3656
|
+
yield* pipe(
|
|
3657
|
+
typeParser.strictEffectType(type, node),
|
|
3658
|
+
map4((effect) => {
|
|
3659
|
+
const { E, R } = effect;
|
|
3660
|
+
const hasAnyUnknownR = isAnyOrUnknown(R);
|
|
3661
|
+
const hasAnyUnknownE = isAnyOrUnknown(E);
|
|
3662
|
+
if (hasAnyUnknownR || hasAnyUnknownE) {
|
|
3663
|
+
const channels = [];
|
|
3664
|
+
if (hasAnyUnknownR) {
|
|
3665
|
+
const typeName = R.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3666
|
+
channels.push(`${typeName} in the requirements channel`);
|
|
3667
|
+
}
|
|
3668
|
+
if (hasAnyUnknownE) {
|
|
3669
|
+
const typeName = E.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3670
|
+
channels.push(`${typeName} in the error channel`);
|
|
3671
|
+
}
|
|
3672
|
+
const nodeStart = ts.getTokenPosOfNode(node, sourceFile);
|
|
3673
|
+
const nodeEnd = node.end;
|
|
3674
|
+
for (let i = matchingNodes.length - 1; i >= 0; i--) {
|
|
3675
|
+
const existing = matchingNodes[i];
|
|
3676
|
+
const existingStart = ts.getTokenPosOfNode(existing.node, sourceFile);
|
|
3677
|
+
const existingEnd = existing.node.end;
|
|
3678
|
+
if (existingStart <= nodeStart && existingEnd >= nodeEnd) {
|
|
3679
|
+
matchingNodes.splice(i, 1);
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
const suggestions = [`This Effect has ${channels.join(" and ")} which is not recommended.`];
|
|
3683
|
+
if (hasAnyUnknownR) {
|
|
3684
|
+
suggestions.push(`Only service identifiers should appear in the requirements channel.`);
|
|
3685
|
+
}
|
|
3686
|
+
if (hasAnyUnknownE) {
|
|
3687
|
+
suggestions.push(
|
|
3688
|
+
`Having an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example.`
|
|
3689
|
+
);
|
|
3690
|
+
}
|
|
3691
|
+
channels.push(`If you plan to later on manually cast the type, you can safely disable this diagnostic.`);
|
|
3692
|
+
const messageText = suggestions.join("\n");
|
|
3693
|
+
matchingNodes.push({ messageText, node, type });
|
|
3694
|
+
}
|
|
3695
|
+
}),
|
|
3696
|
+
ignore
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
for (const { messageText, node } of matchingNodes) {
|
|
3700
|
+
report({
|
|
3701
|
+
location: node,
|
|
3702
|
+
messageText,
|
|
3703
|
+
fixes: []
|
|
3704
|
+
});
|
|
3705
|
+
}
|
|
3706
|
+
})
|
|
3707
|
+
});
|
|
3708
|
+
|
|
3569
3709
|
// src/diagnostics/catchUnfailableEffect.ts
|
|
3570
3710
|
var catchUnfailableEffect = createDiagnostic({
|
|
3571
3711
|
name: "catchUnfailableEffect",
|
|
@@ -4327,9 +4467,10 @@ var leakingRequirements = createDiagnostic({
|
|
|
4327
4467
|
(type) => {
|
|
4328
4468
|
let symbol3 = type.symbol;
|
|
4329
4469
|
if (symbol3 && symbol3.flags & ts.SymbolFlags.Alias) {
|
|
4330
|
-
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
4470
|
+
symbol3 = typeChecker.getAliasedSymbol(symbol3) || symbol3;
|
|
4331
4471
|
}
|
|
4332
|
-
|
|
4472
|
+
if (!symbol3) return false;
|
|
4473
|
+
return !(symbol3?.declarations || []).some((declaration) => {
|
|
4333
4474
|
const declarationSource = tsUtils.getSourceFileOfNode(declaration);
|
|
4334
4475
|
if (!declarationSource) return false;
|
|
4335
4476
|
return declarationSource.text.substring(declaration.pos, declaration.end).toLowerCase().indexOf(
|
|
@@ -5424,6 +5565,26 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5424
5565
|
const ts = yield* service(TypeScriptApi);
|
|
5425
5566
|
const typeParser = yield* service(TypeParser);
|
|
5426
5567
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5568
|
+
function isAllowedConstructor(node) {
|
|
5569
|
+
if (node.body && node.body.statements.length === 1) {
|
|
5570
|
+
const expressionStatement = node.body.statements[0];
|
|
5571
|
+
if (ts.isExpressionStatement(expressionStatement)) {
|
|
5572
|
+
const maybeCallSuper = expressionStatement.expression;
|
|
5573
|
+
if (ts.isCallExpression(maybeCallSuper)) {
|
|
5574
|
+
if (maybeCallSuper.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
5575
|
+
const expectedNames = node.parameters.map((_) => _.name).filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5576
|
+
if (expectedNames.length === 2 && expectedNames.length === node.parameters.length) {
|
|
5577
|
+
const givenNames = maybeCallSuper.arguments.filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5578
|
+
if (givenNames.length === expectedNames.length && givenNames.every((name, index) => name === expectedNames[index])) {
|
|
5579
|
+
return true;
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
return false;
|
|
5587
|
+
}
|
|
5427
5588
|
const nodeToVisit = [];
|
|
5428
5589
|
const appendNodeToVisit = (node) => {
|
|
5429
5590
|
nodeToVisit.push(node);
|
|
@@ -5455,6 +5616,9 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5455
5616
|
const members = node.members;
|
|
5456
5617
|
for (const member of members) {
|
|
5457
5618
|
if (ts.isConstructorDeclaration(member)) {
|
|
5619
|
+
if (isAllowedConstructor(member)) {
|
|
5620
|
+
continue;
|
|
5621
|
+
}
|
|
5458
5622
|
const fixAsStaticNew = {
|
|
5459
5623
|
fixName: "overriddenSchemaConstructor_static",
|
|
5460
5624
|
description: "Rewrite using the static 'new' pattern",
|
|
@@ -5863,6 +6027,7 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
5863
6027
|
for (const nodeToCheck of nodes) {
|
|
5864
6028
|
if (!nodeToCheck) continue;
|
|
5865
6029
|
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
6030
|
+
if (!ts.isExpression(nodeToCheck)) continue;
|
|
5866
6031
|
const nodeType = typeChecker.getTypeAtLocation(nodeToCheck);
|
|
5867
6032
|
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
5868
6033
|
let typesToCheck = [constrainedType || nodeType];
|
|
@@ -6252,6 +6417,7 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
6252
6417
|
|
|
6253
6418
|
// src/diagnostics.ts
|
|
6254
6419
|
var diagnostics = [
|
|
6420
|
+
anyUnknownInErrorContext,
|
|
6255
6421
|
catchUnfailableEffect,
|
|
6256
6422
|
classSelfMismatch,
|
|
6257
6423
|
duplicatePackage,
|
|
@@ -6342,7 +6508,7 @@ function checkSourceFileWorker(tsInstance, program, sourceFile, compilerOptions,
|
|
|
6342
6508
|
})
|
|
6343
6509
|
),
|
|
6344
6510
|
getOrElse((e) => {
|
|
6345
|
-
console.error(e);
|
|
6511
|
+
console.error(e.message, "at", e.lastSpan);
|
|
6346
6512
|
return [];
|
|
6347
6513
|
}),
|
|
6348
6514
|
map3(addDiagnostic)
|