@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.
@@ -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)