@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.
@@ -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
- return !(symbol3.declarations || []).some((declaration) => {
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)