@effect/language-service 0.55.1 → 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.
@@ -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",
@@ -4414,8 +4552,20 @@ var missedPipeableOpportunity = createDiagnostic({
4414
4552
  while (nodeToVisit.length > 0) {
4415
4553
  const node = nodeToVisit.shift();
4416
4554
  if (ts.isCallExpression(node) && node.arguments.length === 1) {
4417
- const parentChain = callChainNodes.get(node) || [];
4418
- callChainNodes.set(node.arguments[0], parentChain.concat(node));
4555
+ const isPipeCall = yield* pipe(typeParser.pipeCall(node), orElse2(() => void_));
4556
+ if (!isPipeCall) {
4557
+ const resolvedSignature = typeChecker.getResolvedSignature(node);
4558
+ if (resolvedSignature) {
4559
+ const returnType = typeChecker.getReturnTypeOfSignature(resolvedSignature);
4560
+ if (returnType) {
4561
+ const callSignatures = typeChecker.getSignaturesOfType(returnType, ts.SignatureKind.Call);
4562
+ if (callSignatures.length === 0) {
4563
+ const parentChain = callChainNodes.get(node) || [];
4564
+ callChainNodes.set(node.arguments[0], parentChain.concat(node));
4565
+ }
4566
+ }
4567
+ }
4568
+ }
4419
4569
  } else if (callChainNodes.has(node) && ts.isExpression(node)) {
4420
4570
  const parentChain = (callChainNodes.get(node) || []).slice();
4421
4571
  const originalParentChain = parentChain.slice();
@@ -5412,6 +5562,26 @@ var overriddenSchemaConstructor = createDiagnostic({
5412
5562
  const ts = yield* service(TypeScriptApi);
5413
5563
  const typeParser = yield* service(TypeParser);
5414
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
+ }
5415
5585
  const nodeToVisit = [];
5416
5586
  const appendNodeToVisit = (node) => {
5417
5587
  nodeToVisit.push(node);
@@ -5443,6 +5613,9 @@ var overriddenSchemaConstructor = createDiagnostic({
5443
5613
  const members = node.members;
5444
5614
  for (const member of members) {
5445
5615
  if (ts.isConstructorDeclaration(member)) {
5616
+ if (isAllowedConstructor(member)) {
5617
+ continue;
5618
+ }
5446
5619
  const fixAsStaticNew = {
5447
5620
  fixName: "overriddenSchemaConstructor_static",
5448
5621
  description: "Rewrite using the static 'new' pattern",
@@ -6240,6 +6413,7 @@ var unsupportedServiceAccessors = createDiagnostic({
6240
6413
 
6241
6414
  // src/diagnostics.ts
6242
6415
  var diagnostics = [
6416
+ anyUnknownInErrorContext,
6243
6417
  catchUnfailableEffect,
6244
6418
  classSelfMismatch,
6245
6419
  duplicatePackage,
@@ -6330,7 +6504,7 @@ function checkSourceFileWorker(tsInstance, program, sourceFile, compilerOptions,
6330
6504
  })
6331
6505
  ),
6332
6506
  getOrElse((e) => {
6333
- console.error(e);
6507
+ console.error(e.message, "at", e.lastSpan);
6334
6508
  return [];
6335
6509
  }),
6336
6510
  map3(addDiagnostic)