@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.55.2",
3
+ "version": "0.55.3",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "bin": {
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
- return unsafeRun(nano);
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
  }
@@ -3566,6 +3603,103 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3566
3603
  };
3567
3604
  }
3568
3605
 
3606
+ // src/diagnostics/anyUnknownInErrorContext.ts
3607
+ var anyUnknownInErrorContext = createDiagnostic({
3608
+ name: "anyUnknownInErrorContext",
3609
+ code: 28,
3610
+ severity: "off",
3611
+ apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
3612
+ const ts = yield* service(TypeScriptApi);
3613
+ const typeChecker = yield* service(TypeCheckerApi);
3614
+ const typeParser = yield* service(TypeParser);
3615
+ const isAnyOrUnknown = (type) => (type.flags & ts.TypeFlags.Any) > 0 || (type.flags & ts.TypeFlags.Unknown) > 0;
3616
+ const matchingNodes = [];
3617
+ const nodeToVisit = [sourceFile];
3618
+ const appendNodeToVisit = (node) => {
3619
+ nodeToVisit.push(node);
3620
+ return void 0;
3621
+ };
3622
+ while (nodeToVisit.length > 0) {
3623
+ const node = nodeToVisit.pop();
3624
+ if (ts.isTypeNode(node)) continue;
3625
+ if (ts.isTypeAliasDeclaration(node)) continue;
3626
+ if (ts.isInterfaceDeclaration(node)) continue;
3627
+ if (ts.isAsExpression(node) && node.type && node.type.kind === ts.SyntaxKind.AnyKeyword) {
3628
+ continue;
3629
+ }
3630
+ if (ts.isParameter(node) || ts.isPropertyDeclaration(node) || ts.isVariableDeclaration(node)) {
3631
+ if (node.type) {
3632
+ const type2 = typeChecker.getTypeAtLocation(node.type);
3633
+ const expectedEffect = yield* pipe(
3634
+ typeParser.strictEffectType(type2, node.type),
3635
+ orElse2(() => void_)
3636
+ );
3637
+ if (expectedEffect) continue;
3638
+ }
3639
+ }
3640
+ ts.forEachChild(node, appendNodeToVisit);
3641
+ if (!ts.isExpression(node)) continue;
3642
+ let type = typeChecker.getTypeAtLocation(node);
3643
+ if (ts.isCallExpression(node)) {
3644
+ const resolvedSignature = typeChecker.getResolvedSignature(node);
3645
+ if (resolvedSignature) {
3646
+ type = typeChecker.getReturnTypeOfSignature(resolvedSignature);
3647
+ }
3648
+ }
3649
+ if (!type) continue;
3650
+ yield* pipe(
3651
+ typeParser.strictEffectType(type, node),
3652
+ map4((effect) => {
3653
+ const { E, R } = effect;
3654
+ const hasAnyUnknownR = isAnyOrUnknown(R);
3655
+ const hasAnyUnknownE = isAnyOrUnknown(E);
3656
+ if (hasAnyUnknownR || hasAnyUnknownE) {
3657
+ const channels = [];
3658
+ if (hasAnyUnknownR) {
3659
+ const typeName = R.flags & ts.TypeFlags.Any ? "any" : "unknown";
3660
+ channels.push(`${typeName} in the requirements channel`);
3661
+ }
3662
+ if (hasAnyUnknownE) {
3663
+ const typeName = E.flags & ts.TypeFlags.Any ? "any" : "unknown";
3664
+ channels.push(`${typeName} in the error channel`);
3665
+ }
3666
+ const nodeStart = ts.getTokenPosOfNode(node, sourceFile);
3667
+ const nodeEnd = node.end;
3668
+ for (let i = matchingNodes.length - 1; i >= 0; i--) {
3669
+ const existing = matchingNodes[i];
3670
+ const existingStart = ts.getTokenPosOfNode(existing.node, sourceFile);
3671
+ const existingEnd = existing.node.end;
3672
+ if (existingStart <= nodeStart && existingEnd >= nodeEnd) {
3673
+ matchingNodes.splice(i, 1);
3674
+ }
3675
+ }
3676
+ const suggestions = [`This Effect has ${channels.join(" and ")} which is not recommended.`];
3677
+ if (hasAnyUnknownR) {
3678
+ suggestions.push(`Only service identifiers should appear in the requirements channel.`);
3679
+ }
3680
+ if (hasAnyUnknownE) {
3681
+ suggestions.push(
3682
+ `Having an unknown or any error type is not useful. Consider instead using specific error types baked by Data.TaggedError for example.`
3683
+ );
3684
+ }
3685
+ channels.push(`If you plan to later on manually cast the type, you can safely disable this diagnostic.`);
3686
+ const messageText = suggestions.join("\n");
3687
+ matchingNodes.push({ messageText, node, type });
3688
+ }
3689
+ }),
3690
+ ignore
3691
+ );
3692
+ }
3693
+ for (const { messageText, node } of matchingNodes) {
3694
+ report({
3695
+ location: node,
3696
+ messageText,
3697
+ fixes: []
3698
+ });
3699
+ }
3700
+ })
3701
+ });
3702
+
3569
3703
  // src/diagnostics/catchUnfailableEffect.ts
3570
3704
  var catchUnfailableEffect = createDiagnostic({
3571
3705
  name: "catchUnfailableEffect",
@@ -5424,6 +5558,26 @@ var overriddenSchemaConstructor = createDiagnostic({
5424
5558
  const ts = yield* service(TypeScriptApi);
5425
5559
  const typeParser = yield* service(TypeParser);
5426
5560
  const typeChecker = yield* service(TypeCheckerApi);
5561
+ function isAllowedConstructor(node) {
5562
+ if (node.body && node.body.statements.length === 1) {
5563
+ const expressionStatement = node.body.statements[0];
5564
+ if (ts.isExpressionStatement(expressionStatement)) {
5565
+ const maybeCallSuper = expressionStatement.expression;
5566
+ if (ts.isCallExpression(maybeCallSuper)) {
5567
+ if (maybeCallSuper.expression.kind === ts.SyntaxKind.SuperKeyword) {
5568
+ const expectedNames = node.parameters.map((_) => _.name).filter(ts.isIdentifier).map((_) => ts.idText(_));
5569
+ if (expectedNames.length === 2 && expectedNames.length === node.parameters.length) {
5570
+ const givenNames = maybeCallSuper.arguments.filter(ts.isIdentifier).map((_) => ts.idText(_));
5571
+ if (givenNames.length === expectedNames.length && givenNames.every((name, index) => name === expectedNames[index])) {
5572
+ return true;
5573
+ }
5574
+ }
5575
+ }
5576
+ }
5577
+ }
5578
+ }
5579
+ return false;
5580
+ }
5427
5581
  const nodeToVisit = [];
5428
5582
  const appendNodeToVisit = (node) => {
5429
5583
  nodeToVisit.push(node);
@@ -5455,6 +5609,9 @@ var overriddenSchemaConstructor = createDiagnostic({
5455
5609
  const members = node.members;
5456
5610
  for (const member of members) {
5457
5611
  if (ts.isConstructorDeclaration(member)) {
5612
+ if (isAllowedConstructor(member)) {
5613
+ continue;
5614
+ }
5458
5615
  const fixAsStaticNew = {
5459
5616
  fixName: "overriddenSchemaConstructor_static",
5460
5617
  description: "Rewrite using the static 'new' pattern",
@@ -6252,6 +6409,7 @@ var unsupportedServiceAccessors = createDiagnostic({
6252
6409
 
6253
6410
  // src/diagnostics.ts
6254
6411
  var diagnostics = [
6412
+ anyUnknownInErrorContext,
6255
6413
  catchUnfailableEffect,
6256
6414
  classSelfMismatch,
6257
6415
  duplicatePackage,