@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
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
|
}
|
|
@@ -2483,6 +2520,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2483
2520
|
const getSourceFilesDeclaringSymbolModule = (packageName) => cachedBy(
|
|
2484
2521
|
fn("TypeParser.getSourceFilesDeclaringSymbolModule")(function* (symbol3) {
|
|
2485
2522
|
const result = [];
|
|
2523
|
+
if (!symbol3) return result;
|
|
2486
2524
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
2487
2525
|
for (const sourceFile of symbol3.declarations) {
|
|
2488
2526
|
if (!ts.isSourceFile(sourceFile)) continue;
|
|
@@ -2520,6 +2558,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2520
2558
|
const getSourceFilesDeclaringSymbolExportedUnderPackageModule = (packageName, memberName) => cachedBy(
|
|
2521
2559
|
fn("TypeParser.getSourceFilesDeclaringSymbolUnderPackageExportedMember")(function* (symbol3) {
|
|
2522
2560
|
const result = [];
|
|
2561
|
+
if (!symbol3) return result;
|
|
2523
2562
|
if (!symbol3.declarations) return yield* typeParserIssue("Symbol has no declarations", void 0, void 0);
|
|
2524
2563
|
for (const declaration of symbol3.declarations) {
|
|
2525
2564
|
const sourceFile = tsUtils.getSourceFileOfNode(declaration);
|
|
@@ -2741,14 +2780,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2741
2780
|
);
|
|
2742
2781
|
const importedContextModule = cachedBy(
|
|
2743
2782
|
fn("TypeParser.importedContextModule")(function* (node) {
|
|
2783
|
+
if (!ts.isIdentifier(node)) {
|
|
2784
|
+
return yield* typeParserIssue("Node is not an identifier", void 0, node);
|
|
2785
|
+
}
|
|
2744
2786
|
const type = typeChecker.getTypeAtLocation(node);
|
|
2745
2787
|
const propertySymbol = typeChecker.getPropertyOfType(type, "Tag");
|
|
2746
2788
|
if (!propertySymbol) {
|
|
2747
2789
|
return yield* typeParserIssue("Type has no 'Tag' property", type, node);
|
|
2748
2790
|
}
|
|
2749
|
-
if (!ts.isIdentifier(node)) {
|
|
2750
|
-
return yield* typeParserIssue("Node is not an identifier", type, node);
|
|
2751
|
-
}
|
|
2752
2791
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2753
2792
|
if (!sourceFile) {
|
|
2754
2793
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -2775,14 +2814,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
2775
2814
|
);
|
|
2776
2815
|
const importedDataModule = cachedBy(
|
|
2777
2816
|
fn("TypeParser.importedDataModule")(function* (node) {
|
|
2817
|
+
if (!ts.isIdentifier(node)) {
|
|
2818
|
+
return yield* typeParserIssue("Node is not an expression", void 0, node);
|
|
2819
|
+
}
|
|
2778
2820
|
const type = typeChecker.getTypeAtLocation(node);
|
|
2779
2821
|
const propertySymbol = typeChecker.getPropertyOfType(type, "TaggedError");
|
|
2780
2822
|
if (!propertySymbol) {
|
|
2781
2823
|
return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
|
|
2782
2824
|
}
|
|
2783
|
-
if (!ts.isIdentifier(node)) {
|
|
2784
|
-
return yield* typeParserIssue("Node is not an expression", type, node);
|
|
2785
|
-
}
|
|
2786
2825
|
const sourceFile = tsUtils.getSourceFileOfNode(node);
|
|
2787
2826
|
if (!sourceFile) {
|
|
2788
2827
|
return yield* typeParserIssue("Node is not in a source file", void 0, node);
|
|
@@ -3566,6 +3605,103 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3566
3605
|
};
|
|
3567
3606
|
}
|
|
3568
3607
|
|
|
3608
|
+
// src/diagnostics/anyUnknownInErrorContext.ts
|
|
3609
|
+
var anyUnknownInErrorContext = createDiagnostic({
|
|
3610
|
+
name: "anyUnknownInErrorContext",
|
|
3611
|
+
code: 28,
|
|
3612
|
+
severity: "off",
|
|
3613
|
+
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
3614
|
+
const ts = yield* service(TypeScriptApi);
|
|
3615
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3616
|
+
const typeParser = yield* service(TypeParser);
|
|
3617
|
+
const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
|
|
3618
|
+
const matchingNodes = [];
|
|
3619
|
+
const nodeToVisit = [sourceFile];
|
|
3620
|
+
const appendNodeToVisit = (node) => {
|
|
3621
|
+
nodeToVisit.push(node);
|
|
3622
|
+
return void 0;
|
|
3623
|
+
};
|
|
3624
|
+
while (nodeToVisit.length > 0) {
|
|
3625
|
+
const node = nodeToVisit.pop();
|
|
3626
|
+
if (ts.isTypeNode(node)) continue;
|
|
3627
|
+
if (ts.isTypeAliasDeclaration(node)) continue;
|
|
3628
|
+
if (ts.isInterfaceDeclaration(node)) continue;
|
|
3629
|
+
if (ts.isAsExpression(node) && node.type && node.type.kind === ts.SyntaxKind.AnyKeyword) {
|
|
3630
|
+
continue;
|
|
3631
|
+
}
|
|
3632
|
+
if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
|
|
3633
|
+
if (node.type) {
|
|
3634
|
+
const type2 = typeChecker.getTypeAtLocation(node.type);
|
|
3635
|
+
const expectedEffect = yield* pipe(
|
|
3636
|
+
typeParser.strictEffectType(type2, node.type),
|
|
3637
|
+
orElse2(() => void_)
|
|
3638
|
+
);
|
|
3639
|
+
if (expectedEffect) continue;
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3643
|
+
if (!ts.isExpression(node)) continue;
|
|
3644
|
+
let type = typeChecker.getTypeAtLocation(node);
|
|
3645
|
+
if (ts.isCallExpression(node)) {
|
|
3646
|
+
const resolvedSignature = typeChecker.getResolvedSignature(node);
|
|
3647
|
+
if (resolvedSignature) {
|
|
3648
|
+
type = typeChecker.getReturnTypeOfSignature(resolvedSignature);
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
if (!type) continue;
|
|
3652
|
+
yield* pipe(
|
|
3653
|
+
typeParser.strictEffectType(type, node),
|
|
3654
|
+
map4((effect) => {
|
|
3655
|
+
const { E, R } = effect;
|
|
3656
|
+
const hasAnyUnknownR = isAnyOrUnknown(R);
|
|
3657
|
+
const hasAnyUnknownE = isAnyOrUnknown(E);
|
|
3658
|
+
if (hasAnyUnknownR || hasAnyUnknownE) {
|
|
3659
|
+
const channels = [];
|
|
3660
|
+
if (hasAnyUnknownR) {
|
|
3661
|
+
const typeName = R.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3662
|
+
channels.push(`${typeName} in the requirements channel`);
|
|
3663
|
+
}
|
|
3664
|
+
if (hasAnyUnknownE) {
|
|
3665
|
+
const typeName = E.flags & ts.TypeFlags.Any ? "any" : "unknown";
|
|
3666
|
+
channels.push(`${typeName} in the error channel`);
|
|
3667
|
+
}
|
|
3668
|
+
const nodeStart = ts.getTokenPosOfNode(node, sourceFile);
|
|
3669
|
+
const nodeEnd = node.end;
|
|
3670
|
+
for (let i = matchingNodes.length - 1; i >= 0; i--) {
|
|
3671
|
+
const existing = matchingNodes[i];
|
|
3672
|
+
const existingStart = ts.getTokenPosOfNode(existing.node, sourceFile);
|
|
3673
|
+
const existingEnd = existing.node.end;
|
|
3674
|
+
if (existingStart <= nodeStart && existingEnd >= nodeEnd) {
|
|
3675
|
+
matchingNodes.splice(i, 1);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
const suggestions = [`This Effect has ${channels.join(" and ")} which is not recommended.`];
|
|
3679
|
+
if (hasAnyUnknownR) {
|
|
3680
|
+
suggestions.push(`Only service identifiers should appear in the requirements channel.`);
|
|
3681
|
+
}
|
|
3682
|
+
if (hasAnyUnknownE) {
|
|
3683
|
+
suggestions.push(
|
|
3684
|
+
`Having an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example.`
|
|
3685
|
+
);
|
|
3686
|
+
}
|
|
3687
|
+
channels.push(`If you plan to later on manually cast the type, you can safely disable this diagnostic.`);
|
|
3688
|
+
const messageText = suggestions.join("\n");
|
|
3689
|
+
matchingNodes.push({ messageText, node, type });
|
|
3690
|
+
}
|
|
3691
|
+
}),
|
|
3692
|
+
ignore
|
|
3693
|
+
);
|
|
3694
|
+
}
|
|
3695
|
+
for (const { messageText, node } of matchingNodes) {
|
|
3696
|
+
report({
|
|
3697
|
+
location: node,
|
|
3698
|
+
messageText,
|
|
3699
|
+
fixes: []
|
|
3700
|
+
});
|
|
3701
|
+
}
|
|
3702
|
+
})
|
|
3703
|
+
});
|
|
3704
|
+
|
|
3569
3705
|
// src/diagnostics/catchUnfailableEffect.ts
|
|
3570
3706
|
var catchUnfailableEffect = createDiagnostic({
|
|
3571
3707
|
name: "catchUnfailableEffect",
|
|
@@ -4327,9 +4463,10 @@ var leakingRequirements = createDiagnostic({
|
|
|
4327
4463
|
(type) => {
|
|
4328
4464
|
let symbol3 = type.symbol;
|
|
4329
4465
|
if (symbol3 && symbol3.flags & ts.SymbolFlags.Alias) {
|
|
4330
|
-
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
4466
|
+
symbol3 = typeChecker.getAliasedSymbol(symbol3) || symbol3;
|
|
4331
4467
|
}
|
|
4332
|
-
|
|
4468
|
+
if (!symbol3) return false;
|
|
4469
|
+
return !(symbol3?.declarations || []).some((declaration) => {
|
|
4333
4470
|
const declarationSource = tsUtils.getSourceFileOfNode(declaration);
|
|
4334
4471
|
if (!declarationSource) return false;
|
|
4335
4472
|
return declarationSource.text.substring(declaration.pos, declaration.end).toLowerCase().indexOf(
|
|
@@ -5424,6 +5561,26 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5424
5561
|
const ts = yield* service(TypeScriptApi);
|
|
5425
5562
|
const typeParser = yield* service(TypeParser);
|
|
5426
5563
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5564
|
+
function isAllowedConstructor(node) {
|
|
5565
|
+
if (node.body && node.body.statements.length === 1) {
|
|
5566
|
+
const expressionStatement = node.body.statements[0];
|
|
5567
|
+
if (ts.isExpressionStatement(expressionStatement)) {
|
|
5568
|
+
const maybeCallSuper = expressionStatement.expression;
|
|
5569
|
+
if (ts.isCallExpression(maybeCallSuper)) {
|
|
5570
|
+
if (maybeCallSuper.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
5571
|
+
const expectedNames = node.parameters.map((_) => _.name).filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5572
|
+
if (expectedNames.length === 2 && expectedNames.length === node.parameters.length) {
|
|
5573
|
+
const givenNames = maybeCallSuper.arguments.filter(ts.isIdentifier).map((_) => ts.idText(_));
|
|
5574
|
+
if (givenNames.length === expectedNames.length && givenNames.every((name, index) => name === expectedNames[index])) {
|
|
5575
|
+
return true;
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
return false;
|
|
5583
|
+
}
|
|
5427
5584
|
const nodeToVisit = [];
|
|
5428
5585
|
const appendNodeToVisit = (node) => {
|
|
5429
5586
|
nodeToVisit.push(node);
|
|
@@ -5455,6 +5612,9 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
5455
5612
|
const members = node.members;
|
|
5456
5613
|
for (const member of members) {
|
|
5457
5614
|
if (ts.isConstructorDeclaration(member)) {
|
|
5615
|
+
if (isAllowedConstructor(member)) {
|
|
5616
|
+
continue;
|
|
5617
|
+
}
|
|
5458
5618
|
const fixAsStaticNew = {
|
|
5459
5619
|
fixName: "overriddenSchemaConstructor_static",
|
|
5460
5620
|
description: "Rewrite using the static 'new' pattern",
|
|
@@ -5863,6 +6023,7 @@ var strictBooleanExpressions = createDiagnostic({
|
|
|
5863
6023
|
for (const nodeToCheck of nodes) {
|
|
5864
6024
|
if (!nodeToCheck) continue;
|
|
5865
6025
|
if (!conditionChecks.has(nodeToCheck.parent)) continue;
|
|
6026
|
+
if (!ts.isExpression(nodeToCheck)) continue;
|
|
5866
6027
|
const nodeType = typeChecker.getTypeAtLocation(nodeToCheck);
|
|
5867
6028
|
const constrainedType = typeChecker.getBaseConstraintOfType(nodeType);
|
|
5868
6029
|
let typesToCheck = [constrainedType || nodeType];
|
|
@@ -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,
|