@effect/language-service 0.6.2 → 0.7.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 +83 -30
  2. package/index.js.map +1 -1
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -982,20 +982,52 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
982
982
  });
983
983
 
984
984
  // src/utils/AST.ts
985
- function getNodesContainingRange(ts) {
985
+ function collectSelfAndAncestorNodesInRange(node, textRange) {
986
+ let result = empty();
987
+ let parent = node;
988
+ while (parent) {
989
+ if (parent.end >= textRange.end) {
990
+ result = pipe(result, append(parent));
991
+ }
992
+ parent = parent.parent;
993
+ }
994
+ return result;
995
+ }
996
+ function getAncestorNodesInRange(ts) {
986
997
  return (sourceFile, textRange) => {
987
998
  const precedingToken = ts.findPrecedingToken(textRange.pos, sourceFile);
988
999
  if (!precedingToken) return empty();
989
- let result = empty();
990
- let parent = precedingToken;
991
- while (parent) {
992
- if (parent.end >= textRange.end) {
993
- result = pipe(result, append(parent));
1000
+ return collectSelfAndAncestorNodesInRange(precedingToken, textRange);
1001
+ };
1002
+ }
1003
+ function findNodeAtPosition(ts, sourceFile, position) {
1004
+ function find(node) {
1005
+ if (position >= node.getStart() && position < node.getEnd()) {
1006
+ return ts.forEachChild(node, find) || node;
1007
+ }
1008
+ return void 0;
1009
+ }
1010
+ return fromNullable(find(sourceFile));
1011
+ }
1012
+ function collectDescendantsAndAncestorsInRange(ts, sourceFile, textRange) {
1013
+ const nodeAtPosition = findNodeAtPosition(ts, sourceFile, textRange.pos);
1014
+ if (isNone2(nodeAtPosition)) return empty();
1015
+ return collectSelfAndAncestorNodesInRange(nodeAtPosition.value, textRange);
1016
+ }
1017
+ function getSingleReturnEffectFromEffectGen(ts, typeChecker, node) {
1018
+ const effectGenLike = effectGen(ts, typeChecker)(node);
1019
+ if (isSome2(effectGenLike)) {
1020
+ const body = effectGenLike.value.body;
1021
+ 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) {
1022
+ const nodeToCheck = body.statements[0].expression.expression;
1023
+ const type = typeChecker.getTypeAtLocation(nodeToCheck);
1024
+ const maybeEffect = effectType(ts, typeChecker)(type, nodeToCheck);
1025
+ if (isSome2(maybeEffect)) {
1026
+ return some2(nodeToCheck);
994
1027
  }
995
- parent = parent.parent;
996
1028
  }
997
- return result;
998
- };
1029
+ }
1030
+ return none2();
999
1031
  }
1000
1032
  function toTextRange(positionOrRange) {
1001
1033
  return typeof positionOrRange === "number" ? { end: positionOrRange, pos: positionOrRange } : positionOrRange;
@@ -1492,17 +1524,8 @@ var unnecessaryEffectGen = createDiagnostic({
1492
1524
  const effectDiagnostics = [];
1493
1525
  const brokenGenerators = /* @__PURE__ */ new Set();
1494
1526
  const visit = (node) => {
1495
- const effectGenLike = effectGen(ts, typeChecker)(node);
1496
- if (isSome2(effectGenLike)) {
1497
- const body = effectGenLike.value.body;
1498
- 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) {
1499
- const nodeToCheck = body.statements[0].expression.expression;
1500
- const type = typeChecker.getTypeAtLocation(nodeToCheck);
1501
- const maybeEffect = effectType(ts, typeChecker)(type, nodeToCheck);
1502
- if (isSome2(maybeEffect)) {
1503
- brokenGenerators.add(node);
1504
- }
1505
- }
1527
+ if (isSome2(getSingleReturnEffectFromEffectGen(ts, typeChecker, node))) {
1528
+ brokenGenerators.add(node);
1506
1529
  }
1507
1530
  ts.forEachChild(node, visit);
1508
1531
  };
@@ -1561,7 +1584,7 @@ function prependEffectTypeArguments(ts, program) {
1561
1584
  if (!hasTruncationHappened) return quickInfo;
1562
1585
  const typeChecker = program.getTypeChecker();
1563
1586
  const effectTypeArgsDocumentation = pipe(
1564
- getNodesContainingRange(ts)(sourceFile, toTextRange(position)),
1587
+ getAncestorNodesInRange(ts)(sourceFile, toTextRange(position)),
1565
1588
  head,
1566
1589
  flatMap(
1567
1590
  (_) => effectType(ts, typeChecker)(typeChecker.getTypeAtLocation(_), _)
@@ -1590,7 +1613,7 @@ var asyncAwaitToGen = createRefactor({
1590
1613
  name: "effect/asyncAwaitToGen",
1591
1614
  description: "Convert to Effect.gen",
1592
1615
  apply: (ts, program) => (sourceFile, textRange) => pipe(
1593
- getNodesContainingRange(ts)(sourceFile, textRange),
1616
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1594
1617
  filter(
1595
1618
  (node) => ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)
1596
1619
  ),
@@ -1648,7 +1671,7 @@ var asyncAwaitToGenTryPromise = createRefactor({
1648
1671
  name: "effect/asyncAwaitToGenTryPromise",
1649
1672
  description: "Convert to Effect.gen with failures",
1650
1673
  apply: (ts, program) => (sourceFile, textRange) => pipe(
1651
- getNodesContainingRange(ts)(sourceFile, textRange),
1674
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1652
1675
  filter(
1653
1676
  (node) => ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)
1654
1677
  ),
@@ -1736,7 +1759,7 @@ var effectGenToFn = createRefactor({
1736
1759
  name: "effect/effectGenToFn",
1737
1760
  description: "Convert to Effect.fn",
1738
1761
  apply: (ts, program) => (sourceFile, textRange) => pipe(
1739
- getNodesContainingRange(ts)(sourceFile, textRange),
1762
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1740
1763
  findFirst2(
1741
1764
  (node) => gen(function* () {
1742
1765
  const effectGen2 = yield* effectGen(ts, program.getTypeChecker())(node);
@@ -1809,12 +1832,12 @@ var functionToArrow = createRefactor({
1809
1832
  description: "Convert to arrow",
1810
1833
  apply: (ts) => (sourceFile, textRange) => pipe(
1811
1834
  pipe(
1812
- getNodesContainingRange(ts)(sourceFile, textRange),
1835
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1813
1836
  filter(ts.isFunctionDeclaration)
1814
1837
  ),
1815
1838
  appendAll(
1816
1839
  pipe(
1817
- getNodesContainingRange(ts)(sourceFile, textRange),
1840
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1818
1841
  filter(ts.isMethodDeclaration)
1819
1842
  )
1820
1843
  ),
@@ -1886,7 +1909,7 @@ var pipeableToDatafirst = createRefactor({
1886
1909
  name: "effect/pipeableToDatafirst",
1887
1910
  description: "Rewrite to datafirst",
1888
1911
  apply: (ts, program) => (sourceFile, textRange) => pipe(
1889
- getNodesContainingRange(ts)(sourceFile, textRange),
1912
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1890
1913
  filter(isPipeCall(ts)),
1891
1914
  filter((node) => isNodeInRange(textRange)(node.expression)),
1892
1915
  filter(
@@ -1931,12 +1954,41 @@ var pipeableToDatafirst = createRefactor({
1931
1954
  )
1932
1955
  });
1933
1956
 
1957
+ // src/refactors/removeUnnecessaryEffectGen.ts
1958
+ var removeUnnecessaryEffectGen = createRefactor({
1959
+ name: "effect/removeUnnecessaryEffectGen",
1960
+ description: "Remove unnecessary Effect.gen",
1961
+ apply: (ts, program) => (sourceFile, textRange) => {
1962
+ const typeChecker = program.getTypeChecker();
1963
+ return pipe(
1964
+ collectDescendantsAndAncestorsInRange(ts, sourceFile, textRange),
1965
+ findFirst2(
1966
+ (node) => gen(function* () {
1967
+ const returnedYieldedEffect = yield* getSingleReturnEffectFromEffectGen(
1968
+ ts,
1969
+ typeChecker,
1970
+ node
1971
+ );
1972
+ return { nodeToReplace: node, returnedYieldedEffect };
1973
+ })
1974
+ ),
1975
+ map((a) => ({
1976
+ kind: "refactor.rewrite.effect.removeUnnecessaryEffectGen",
1977
+ description: "Remove unnecessary Effect.gen",
1978
+ apply: (changeTracker) => {
1979
+ changeTracker.replaceNode(sourceFile, a.nodeToReplace, a.returnedYieldedEffect);
1980
+ }
1981
+ }))
1982
+ );
1983
+ }
1984
+ });
1985
+
1934
1986
  // src/refactors/toggleLazyConst.ts
1935
1987
  var toggleLazyConst = createRefactor({
1936
1988
  name: "effect/toggleLazyConst",
1937
1989
  description: "Toggle type annotation",
1938
1990
  apply: (ts) => (sourceFile, textRange) => pipe(
1939
- getNodesContainingRange(ts)(sourceFile, textRange),
1991
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1940
1992
  filter(ts.isVariableDeclaration),
1941
1993
  filter((node) => isNodeInRange(textRange)(node.name)),
1942
1994
  filter(
@@ -1975,7 +2027,7 @@ var toggleReturnTypeAnnotation = createRefactor({
1975
2027
  return gen(function* () {
1976
2028
  const typeChecker = program.getTypeChecker();
1977
2029
  const node = yield* pipe(
1978
- getNodesContainingRange(ts)(sourceFile, textRange),
2030
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
1979
2031
  filter(
1980
2032
  (node2) => ts.isFunctionDeclaration(node2) || ts.isFunctionExpression(node2) || ts.isArrowFunction(node2) || ts.isMethodDeclaration(node2)
1981
2033
  ),
@@ -2012,7 +2064,7 @@ var toggleTypeAnnotation = createRefactor({
2012
2064
  name: "effect/toggleTypeAnnotation",
2013
2065
  description: "Toggle type annotation",
2014
2066
  apply: (ts, program) => (sourceFile, textRange) => pipe(
2015
- getNodesContainingRange(ts)(sourceFile, textRange),
2067
+ getAncestorNodesInRange(ts)(sourceFile, textRange),
2016
2068
  filter(
2017
2069
  (node) => ts.isVariableDeclaration(node) || ts.isPropertyDeclaration(node)
2018
2070
  ),
@@ -2084,6 +2136,7 @@ var refactors = {
2084
2136
  asyncAwaitToGenTryPromise,
2085
2137
  functionToArrow,
2086
2138
  pipeableToDatafirst,
2139
+ removeUnnecessaryEffectGen,
2087
2140
  toggleLazyConst,
2088
2141
  toggleReturnTypeAnnotation,
2089
2142
  toggleTypeAnnotation,