@effect/language-service 0.4.0 → 0.5.1

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.
Files changed (3) hide show
  1. package/index.js +102 -6
  2. package/index.js.map +1 -1
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -64,6 +64,8 @@ var dual = function(arity, body) {
64
64
  }
65
65
  };
66
66
  var identity = (a) => a;
67
+ var constant = (value) => () => value;
68
+ var constUndefined = /* @__PURE__ */ constant(void 0);
67
69
  function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) {
68
70
  switch (arguments.length) {
69
71
  case 1:
@@ -649,6 +651,7 @@ var isSome2 = isSome;
649
651
  var getOrElse = /* @__PURE__ */ dual(2, (self, onNone) => isNone2(self) ? onNone() : self.value);
650
652
  var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : self);
651
653
  var fromNullable = (nullableValue) => nullableValue == null ? none2() : some2(nullableValue);
654
+ var getOrUndefined = /* @__PURE__ */ getOrElse(constUndefined);
652
655
  var map = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : some2(f(self.value)));
653
656
  var flatMap = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : f(self.value));
654
657
  var all = (input) => {
@@ -1434,12 +1437,47 @@ var missingStarInYieldEffectGen = createDiagnostic({
1434
1437
  }
1435
1438
  });
1436
1439
 
1440
+ // src/diagnostics/unnecessaryEffectGen.ts
1441
+ var unnecessaryEffectGen = createDiagnostic({
1442
+ code: 5,
1443
+ apply: (ts, program) => (sourceFile) => {
1444
+ const typeChecker = program.getTypeChecker();
1445
+ const effectDiagnostics = [];
1446
+ const brokenGenerators = /* @__PURE__ */ new Set();
1447
+ const visit = (node) => {
1448
+ const effectGenLike = effectGen(ts, typeChecker)(node);
1449
+ if (isSome2(effectGenLike)) {
1450
+ const body = effectGenLike.value.body;
1451
+ if (body.statements.length === 1 && ts.isReturnStatement(body.statements[0]) && body.statements[0].expression && ts.isYieldExpression(body.statements[0].expression) && body.statements[0].expression.expression) {
1452
+ const nodeToCheck = body.statements[0].expression.expression;
1453
+ const type = typeChecker.getTypeAtLocation(nodeToCheck);
1454
+ const maybeEffect = effectType(ts, typeChecker)(type, nodeToCheck);
1455
+ if (isSome2(maybeEffect)) {
1456
+ brokenGenerators.add(node);
1457
+ }
1458
+ }
1459
+ }
1460
+ ts.forEachChild(node, visit);
1461
+ };
1462
+ ts.forEachChild(sourceFile, visit);
1463
+ brokenGenerators.forEach(
1464
+ (node) => effectDiagnostics.push({
1465
+ node,
1466
+ category: ts.DiagnosticCategory.Warning,
1467
+ messageText: `This Effect.gen is useless here because it only contains a single return statement.`
1468
+ })
1469
+ );
1470
+ return effectDiagnostics;
1471
+ }
1472
+ });
1473
+
1437
1474
  // src/diagnostics.ts
1438
1475
  var diagnostics = {
1439
1476
  missingEffectContext,
1440
1477
  missingEffectError,
1441
1478
  floatingEffect,
1442
- missingStarInYieldEffectGen
1479
+ missingStarInYieldEffectGen,
1480
+ unnecessaryEffectGen
1443
1481
  };
1444
1482
 
1445
1483
  // src/quickinfo.ts
@@ -1458,6 +1496,47 @@ function dedupeJsDocTags(quickInfo) {
1458
1496
  }
1459
1497
  return quickInfo;
1460
1498
  }
1499
+ function formatTypeForQuickInfo(ts, typeChecker) {
1500
+ return (channelType, channelName) => {
1501
+ const stringRepresentation = typeChecker.typeToString(
1502
+ channelType,
1503
+ void 0,
1504
+ ts.TypeFormatFlags.NoTruncation
1505
+ );
1506
+ return `type ${channelName} = ${stringRepresentation}`;
1507
+ };
1508
+ }
1509
+ function prependEffectTypeArguments(ts, program) {
1510
+ return (sourceFileName, position, quickInfo) => {
1511
+ const sourceFile = program.getSourceFile(sourceFileName);
1512
+ if (!sourceFile) return quickInfo;
1513
+ const hasTruncationHappened = ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
1514
+ if (!hasTruncationHappened) return quickInfo;
1515
+ const typeChecker = program.getTypeChecker();
1516
+ const effectTypeArgsDocumentation = pipe(
1517
+ getNodesContainingRange(ts)(sourceFile, toTextRange(position)),
1518
+ head,
1519
+ flatMap(
1520
+ (_) => effectType(ts, typeChecker)(typeChecker.getTypeAtLocation(_), _)
1521
+ ),
1522
+ map((_) => [{
1523
+ kind: "text",
1524
+ text: "```ts\n/* Effect Type Parameters */\n" + formatTypeForQuickInfo(ts, typeChecker)(_.A, "Success") + "\n" + formatTypeForQuickInfo(ts, typeChecker)(_.E, "Failure") + "\n" + formatTypeForQuickInfo(ts, typeChecker)(_.R, "Requirements") + "\n```\n"
1525
+ }]),
1526
+ getOrElse(() => [])
1527
+ );
1528
+ if (quickInfo.documentation) {
1529
+ return {
1530
+ ...quickInfo,
1531
+ documentation: effectTypeArgsDocumentation.concat(quickInfo.documentation)
1532
+ };
1533
+ }
1534
+ return {
1535
+ ...quickInfo,
1536
+ documentation: effectTypeArgsDocumentation
1537
+ };
1538
+ };
1539
+ }
1461
1540
 
1462
1541
  // src/refactors/asyncAwaitToGen.ts
1463
1542
  var asyncAwaitToGen = createRefactor({
@@ -1800,7 +1879,9 @@ var toggleTypeAnnotation = createRefactor({
1800
1879
  description: "Toggle type annotation",
1801
1880
  apply: (ts, program) => (sourceFile, textRange) => pipe(
1802
1881
  getNodesContainingRange(ts)(sourceFile, textRange),
1803
- filter(ts.isVariableDeclaration),
1882
+ filter(
1883
+ (node) => ts.isVariableDeclaration(node) || ts.isPropertyDeclaration(node)
1884
+ ),
1804
1885
  filter((node) => isNodeInRange(textRange)(node.name)),
1805
1886
  filter((node) => !!node.initializer),
1806
1887
  head,
@@ -1816,10 +1897,19 @@ var toggleTypeAnnotation = createRefactor({
1816
1897
  }
1817
1898
  const initializer = node.initializer;
1818
1899
  const initializerType = typeChecker.getTypeAtLocation(initializer);
1819
- const initializerTypeNode = typeChecker.typeToTypeNode(
1900
+ const initializerTypeNode = fromNullable(typeChecker.typeToTypeNode(
1820
1901
  initializerType,
1821
1902
  node,
1822
1903
  ts.NodeBuilderFlags.NoTruncation
1904
+ )).pipe(
1905
+ orElse(
1906
+ () => fromNullable(typeChecker.typeToTypeNode(
1907
+ initializerType,
1908
+ void 0,
1909
+ ts.NodeBuilderFlags.NoTruncation
1910
+ ))
1911
+ ),
1912
+ getOrUndefined
1823
1913
  );
1824
1914
  if (initializerTypeNode) {
1825
1915
  changeTracker.insertNodeAt(
@@ -1872,7 +1962,8 @@ var init = (modules) => {
1872
1962
  function create(info) {
1873
1963
  const languageService = info.languageService;
1874
1964
  const pluginOptions = {
1875
- diagnostics: info.config && "diagnostics" in info.config && typeof info.config.diagnostics === "boolean" ? info.config.diagnostics : true
1965
+ diagnostics: info.config && "diagnostics" in info.config && typeof info.config.diagnostics === "boolean" ? info.config.diagnostics : true,
1966
+ quickinfo: info.config && "quickinfo" in info.config && typeof info.config.quickinfo === "boolean" ? info.config.quickinfo : true
1876
1967
  };
1877
1968
  const proxy = /* @__PURE__ */ Object.create(null);
1878
1969
  for (const k of Object.keys(info.languageService)) {
@@ -2005,8 +2096,13 @@ var init = (modules) => {
2005
2096
  };
2006
2097
  proxy.getQuickInfoAtPosition = (fileName, position, ...args) => {
2007
2098
  const quickInfo = languageService.getQuickInfoAtPosition(fileName, position, ...args);
2008
- if (quickInfo) {
2009
- return dedupeJsDocTags(quickInfo);
2099
+ if (pluginOptions.quickinfo && quickInfo) {
2100
+ const dedupedTagsQuickInfo = dedupeJsDocTags(quickInfo);
2101
+ const program = languageService.getProgram();
2102
+ if (program) {
2103
+ return prependEffectTypeArguments(ts, program)(fileName, position, dedupedTagsQuickInfo);
2104
+ }
2105
+ return dedupedTagsQuickInfo;
2010
2106
  }
2011
2107
  return quickInfo;
2012
2108
  };