@effect/language-service 0.22.1 → 0.22.2

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 (4) hide show
  1. package/README.md +1 -0
  2. package/index.js +1093 -1058
  3. package/index.js.map +1 -1
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -729,6 +729,7 @@ var getOrElse = /* @__PURE__ */ dual(2, (self, onLeft) => isLeft2(self) ? onLeft
729
729
 
730
730
  // node_modules/.pnpm/effect@3.16.5/node_modules/effect/dist/esm/Order.js
731
731
  var make2 = (compare) => (self, that) => self === that ? 0 : compare(self, that);
732
+ var string2 = /* @__PURE__ */ make2((self, that) => self < that ? -1 : 1);
732
733
 
733
734
  // node_modules/.pnpm/effect@3.16.5/node_modules/effect/dist/esm/Option.js
734
735
  var none2 = () => none;
@@ -1732,139 +1733,364 @@ var effectDataClasses = createCompletion({
1732
1733
  })
1733
1734
  });
1734
1735
 
1735
- // src/completions/effectSchemaSelfInClasses.ts
1736
- var effectSchemaSelfInClasses = createCompletion({
1737
- name: "effectSchemaSelfInClasses",
1738
- apply: fn("effectSchemaSelfInClasses")(function* (sourceFile, position) {
1739
- const ts = yield* service(TypeScriptApi);
1740
- const maybeInfos = yield* option(
1741
- parseDataForExtendsClassCompletion(sourceFile, position)
1742
- );
1743
- if (isNone2(maybeInfos)) return [];
1744
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
1745
- const effectSchemaName = yield* option(
1746
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
1747
- sourceFile,
1748
- "effect",
1749
- "Schema"
1750
- )
1751
- );
1752
- const schemaIdentifier = match(effectSchemaName, {
1753
- onNone: () => "Schema",
1754
- onSome: (_) => _.text
1755
- });
1756
- if (schemaIdentifier !== accessedObject.text) return [];
1757
- const name = className.text;
1758
- return [{
1759
- name: `Class<${name}>`,
1760
- kind: ts.ScriptElementKind.constElement,
1761
- insertText: `${schemaIdentifier}.Class<${name}>("${name}")({${"${0}"}}){}`,
1762
- replacementSpan,
1763
- isSnippet: true
1764
- }, {
1765
- name: `TaggedError<${name}>`,
1766
- kind: ts.ScriptElementKind.constElement,
1767
- insertText: `${schemaIdentifier}.TaggedError<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1768
- replacementSpan,
1769
- isSnippet: true
1770
- }, {
1771
- name: `TaggedClass<${name}>`,
1772
- kind: ts.ScriptElementKind.constElement,
1773
- insertText: `${schemaIdentifier}.TaggedClass<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1774
- replacementSpan,
1775
- isSnippet: true
1776
- }, {
1777
- name: `TaggedRequest<${name}>`,
1778
- kind: ts.ScriptElementKind.constElement,
1779
- insertText: `${schemaIdentifier}.TaggedRequest<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1780
- replacementSpan,
1781
- isSnippet: true
1782
- }];
1783
- })
1784
- });
1736
+ // src/diagnostics/duplicatePackage.ts
1737
+ var checkedPackagesCache = /* @__PURE__ */ new Map();
1738
+ var programResolvedCacheSize = /* @__PURE__ */ new Map();
1739
+ var duplicatePackage = createDiagnostic({
1740
+ name: "duplicatePackage",
1741
+ code: 6,
1742
+ severity: "warning",
1743
+ apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
1744
+ const program = yield* service(TypeScriptProgram);
1745
+ const options = yield* service(LanguageServicePluginOptions);
1746
+ if (sourceFile.statements.length < 1) return;
1747
+ let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
1748
+ const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
1749
+ const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
1750
+ if (newResolvedModuleSize !== oldResolvedSize) {
1751
+ const seenPackages = /* @__PURE__ */ new Set();
1752
+ resolvedPackages = {};
1753
+ program.getSourceFiles().map((_) => {
1754
+ const packageInfo = parsePackageContentNameAndVersionFromScope(_);
1755
+ if (!packageInfo) return;
1756
+ const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
1757
+ if (seenPackages.has(packageNameAndVersion)) return;
1758
+ seenPackages.add(packageNameAndVersion);
1759
+ if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
1760
+ if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
1761
+ resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
1762
+ resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
1763
+ });
1764
+ checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
1765
+ programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
1766
+ }
1767
+ for (const packageName of Object.keys(resolvedPackages)) {
1768
+ if (Object.keys(resolvedPackages[packageName]).length > 1) {
1769
+ const versions = Object.keys(resolvedPackages[packageName]);
1770
+ report({
1771
+ node: sourceFile.statements[0],
1772
+ messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
1773
+ Cleanup your dependencies and your package lockfile to avoid multiple instances of this package and reload the project.
1774
+ If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
1785
1775
 
1786
- // src/completions/effectSelfInClasses.ts
1787
- var effectSelfInClasses = createCompletion({
1788
- name: "effectSelfInClasses",
1789
- apply: fn("effectSelfInClasses")(function* (sourceFile, position) {
1790
- const ts = yield* service(TypeScriptApi);
1791
- const maybeInfos = yield* option(
1792
- parseDataForExtendsClassCompletion(sourceFile, position)
1793
- );
1794
- if (isNone2(maybeInfos)) return [];
1795
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
1796
- const effectName = yield* option(
1797
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
1798
- sourceFile,
1799
- "effect",
1800
- "Effect"
1801
- )
1802
- );
1803
- const effectIdentifier = match(effectName, {
1804
- onNone: () => "Effect",
1805
- onSome: (_) => _.text
1806
- });
1807
- if (effectIdentifier !== accessedObject.text) return [];
1808
- const name = className.text;
1809
- return [{
1810
- name: `Service<${name}>`,
1811
- kind: ts.ScriptElementKind.constElement,
1812
- insertText: `${effectIdentifier}.Service<${name}>()("${name}", {${"${0}"}}){}`,
1813
- replacementSpan,
1814
- isSnippet: true
1815
- }];
1776
+ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
1777
+ fixes: []
1778
+ });
1779
+ }
1780
+ }
1816
1781
  })
1817
1782
  });
1818
1783
 
1819
- // src/core/TypeParser.ts
1820
- var TypeParser = Tag("@effect/language-service/TypeParser");
1821
- var TypeParserIssue = class _TypeParserIssue {
1822
- _tag = "@effect/language-service/TypeParserIssue";
1823
- static issue = fail(new _TypeParserIssue());
1824
- };
1825
- function make4(ts, typeChecker) {
1826
- function typeParserIssue(_message, _type, _node) {
1827
- return TypeParserIssue.issue;
1828
- }
1829
- function covariantTypeArgument(type) {
1830
- const signatures = type.getCallSignatures();
1831
- if (signatures.length !== 1) {
1832
- return typeParserIssue("Covariant type has no call signature", type);
1784
+ // src/core/TypeCheckerApi.ts
1785
+ var TypeCheckerApi = Tag("TypeChecker");
1786
+ var TypeCheckerApiCache = Tag("TypeCheckerApiCache");
1787
+ function makeTypeCheckerApiCache() {
1788
+ return {
1789
+ expectedAndRealType: /* @__PURE__ */ new WeakMap()
1790
+ };
1791
+ }
1792
+ var deterministicTypeOrder = gen(function* () {
1793
+ const typeChecker = yield* service(TypeCheckerApi);
1794
+ return make2((a, b) => {
1795
+ const aName = typeChecker.typeToString(a);
1796
+ const bName = typeChecker.typeToString(b);
1797
+ if (aName < bName) return -1;
1798
+ if (aName > bName) return 1;
1799
+ return 0;
1800
+ });
1801
+ });
1802
+ var getMissingTypeEntriesInTargetType = fn(
1803
+ "TypeCheckerApi.getMissingTypeEntriesInTargetType"
1804
+ )(
1805
+ function* (realType, expectedType) {
1806
+ if (realType === expectedType) return [];
1807
+ const typeChecker = yield* service(TypeCheckerApi);
1808
+ const result = [];
1809
+ let toTest = [realType];
1810
+ while (toTest.length > 0) {
1811
+ const type = toTest.pop();
1812
+ if (!type) return result;
1813
+ if (type.isUnion()) {
1814
+ toTest = toTest.concat(type.types);
1815
+ } else {
1816
+ const assignable = typeChecker.isTypeAssignableTo(type, expectedType);
1817
+ if (!assignable) {
1818
+ result.push(type);
1819
+ }
1820
+ }
1833
1821
  }
1834
- return succeed(signatures[0].getReturnType());
1822
+ return result;
1835
1823
  }
1836
- function contravariantTypeArgument(type) {
1837
- const signatures = type.getCallSignatures();
1838
- if (signatures.length !== 1) {
1839
- return typeParserIssue("Contravariant type has no call signature", type);
1824
+ );
1825
+ var CannotFindAncestorConvertibleDeclarationError = class {
1826
+ constructor(node) {
1827
+ this.node = node;
1828
+ }
1829
+ _tag = "@effect/language-service/CannotFindAncestorConvertibleDeclarationError";
1830
+ };
1831
+ var getAncestorConvertibleDeclaration = fn(
1832
+ "TypeCheckerApi.getAncestorConvertibleDeclaration"
1833
+ )(function* (node) {
1834
+ const ts = yield* service(TypeScriptApi);
1835
+ let current = node;
1836
+ while (current) {
1837
+ if (ts.isFunctionDeclaration(current) || ts.isFunctionExpression(current) || ts.isArrowFunction(current) || ts.isMethodDeclaration(current)) {
1838
+ return current;
1840
1839
  }
1841
- return succeed(signatures[0].getTypeParameterAtPosition(0));
1840
+ current = current.parent;
1842
1841
  }
1843
- function invariantTypeArgument(type) {
1844
- const signatures = type.getCallSignatures();
1845
- if (signatures.length !== 1) {
1846
- return typeParserIssue("Invariant type has no call signature", type);
1842
+ return yield* fail(new CannotFindAncestorConvertibleDeclarationError(node));
1843
+ });
1844
+ var CannotInferReturnTypeFromEmptyBody = class {
1845
+ constructor(declaration) {
1846
+ this.declaration = declaration;
1847
+ }
1848
+ _tag = "@effect/language-service/CannotInferReturnTypeFromEmptyBody";
1849
+ };
1850
+ var CannotInferReturnType = class {
1851
+ constructor(declaration) {
1852
+ this.declaration = declaration;
1853
+ }
1854
+ _tag = "@effect/language-service/CannotInferReturnType";
1855
+ };
1856
+ var getInferredReturnType = fn("TypeCheckerApi.getInferredReturnType")(function* (declaration) {
1857
+ const typeChecker = yield* service(TypeCheckerApi);
1858
+ if (!declaration.body) {
1859
+ return yield* fail(
1860
+ new CannotInferReturnTypeFromEmptyBody(declaration)
1861
+ );
1862
+ }
1863
+ let returnType;
1864
+ if (typeChecker.isImplementationOfOverload(declaration)) {
1865
+ const signatures = typeChecker.getTypeAtLocation(declaration).getCallSignatures();
1866
+ if (signatures.length > 1) {
1867
+ returnType = typeChecker.getUnionType(
1868
+ signatures.map((s) => s.getReturnType()).filter((_) => !!_)
1869
+ );
1847
1870
  }
1848
- return succeed(signatures[0].getReturnType());
1849
1871
  }
1850
- const pipeableType = cachedBy(
1851
- function(type, atLocation) {
1852
- const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
1853
- if (!pipeSymbol) {
1854
- return typeParserIssue("Type has no 'pipe' property", type, atLocation);
1855
- }
1856
- const pipeType = typeChecker.getTypeOfSymbolAtLocation(pipeSymbol, atLocation);
1857
- const signatures = pipeType.getCallSignatures();
1858
- if (signatures.length === 0) {
1859
- return typeParserIssue("'pipe' property is not callable", type, atLocation);
1872
+ if (!returnType) {
1873
+ const signature = typeChecker.getSignatureFromDeclaration(declaration);
1874
+ if (signature) {
1875
+ const typePredicate = typeChecker.getTypePredicateOfSignature(signature);
1876
+ if (typePredicate && typePredicate.type) {
1877
+ return typePredicate.type;
1878
+ } else {
1879
+ returnType = typeChecker.getReturnTypeOfSignature(signature);
1860
1880
  }
1861
- return succeed(type);
1862
- },
1863
- "TypeParser.pipeableType",
1864
- (type) => type
1865
- );
1866
- const varianceStructCovariantType = (type, atLocation, propertyName) => {
1867
- const propertySymbol = typeChecker.getPropertyOfType(type, propertyName);
1881
+ }
1882
+ }
1883
+ if (!returnType) {
1884
+ return yield* fail(
1885
+ new CannotInferReturnType(declaration)
1886
+ );
1887
+ }
1888
+ return returnType;
1889
+ });
1890
+ var expectedAndRealType = fn("TypeCheckerApi.expectedAndRealType")(function* (sourceFile) {
1891
+ const cache = yield* service(TypeCheckerApiCache);
1892
+ const resultCached = cache.expectedAndRealType.get(sourceFile);
1893
+ if (resultCached) return resultCached;
1894
+ const typeChecker = yield* service(TypeCheckerApi);
1895
+ const ts = yield* service(TypeScriptApi);
1896
+ const result = [];
1897
+ const nodeToVisit = [sourceFile];
1898
+ const appendNodeToVisit = (node) => {
1899
+ nodeToVisit.push(node);
1900
+ return void 0;
1901
+ };
1902
+ while (nodeToVisit.length > 0) {
1903
+ const node = nodeToVisit.shift();
1904
+ if (ts.isVariableDeclaration(node) && node.initializer) {
1905
+ const expectedType = typeChecker.getTypeAtLocation(node.name);
1906
+ const realType = typeChecker.getTypeAtLocation(node.initializer);
1907
+ result.push([node.name, expectedType, node.initializer, realType]);
1908
+ appendNodeToVisit(node.initializer);
1909
+ continue;
1910
+ } else if (ts.isCallExpression(node)) {
1911
+ const resolvedSignature = typeChecker.getResolvedSignature(node);
1912
+ if (resolvedSignature) {
1913
+ resolvedSignature.getParameters().map((parameter, index) => {
1914
+ const expectedType = typeChecker.getTypeOfSymbolAtLocation(parameter, node);
1915
+ const realType = typeChecker.getTypeAtLocation(node.arguments[index]);
1916
+ result.push([
1917
+ node.arguments[index],
1918
+ expectedType,
1919
+ node.arguments[index],
1920
+ realType
1921
+ ]);
1922
+ });
1923
+ }
1924
+ ts.forEachChild(node, appendNodeToVisit);
1925
+ continue;
1926
+ } else if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
1927
+ const parent = node.parent;
1928
+ if (ts.isObjectLiteralElement(parent)) {
1929
+ if (ts.isObjectLiteralExpression(parent.parent) && parent.name === node) {
1930
+ const type = typeChecker.getContextualType(parent.parent);
1931
+ if (type) {
1932
+ const symbol3 = typeChecker.getPropertyOfType(type, node.text);
1933
+ if (symbol3) {
1934
+ const expectedType = typeChecker.getTypeOfSymbolAtLocation(symbol3, node);
1935
+ const realType = typeChecker.getTypeAtLocation(node);
1936
+ result.push([node, expectedType, node, realType]);
1937
+ }
1938
+ }
1939
+ }
1940
+ }
1941
+ ts.forEachChild(node, appendNodeToVisit);
1942
+ continue;
1943
+ } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
1944
+ const expectedType = typeChecker.getTypeAtLocation(node.left);
1945
+ const realType = typeChecker.getTypeAtLocation(node.right);
1946
+ result.push([node.left, expectedType, node.right, realType]);
1947
+ appendNodeToVisit(node.right);
1948
+ continue;
1949
+ } else if (ts.isReturnStatement(node) && node.expression) {
1950
+ const parentDeclaration = yield* option(getAncestorConvertibleDeclaration(node));
1951
+ if (isSome2(parentDeclaration)) {
1952
+ const expectedType = yield* option(getInferredReturnType(parentDeclaration.value));
1953
+ const realType = typeChecker.getTypeAtLocation(node.expression);
1954
+ if (isSome2(expectedType)) {
1955
+ result.push([node, expectedType.value, node, realType]);
1956
+ }
1957
+ }
1958
+ ts.forEachChild(node, appendNodeToVisit);
1959
+ continue;
1960
+ } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length === 0 && ts.isExpression(node.body)) {
1961
+ const body = node.body;
1962
+ const expectedType = typeChecker.getContextualType(body);
1963
+ const realType = typeChecker.getTypeAtLocation(body);
1964
+ if (expectedType) {
1965
+ result.push([body, expectedType, body, realType]);
1966
+ }
1967
+ ts.forEachChild(body, appendNodeToVisit);
1968
+ continue;
1969
+ } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length > 0 && ts.isExpression(node.body)) {
1970
+ const body = node.body;
1971
+ const expectedType = yield* option(getInferredReturnType(node));
1972
+ const realType = typeChecker.getTypeAtLocation(body);
1973
+ if (isSome2(expectedType)) {
1974
+ result.push([body, expectedType.value, body, realType]);
1975
+ }
1976
+ ts.forEachChild(body, appendNodeToVisit);
1977
+ continue;
1978
+ } else if (ts.isSatisfiesExpression(node)) {
1979
+ const expectedType = typeChecker.getTypeAtLocation(node.type);
1980
+ const realType = typeChecker.getTypeAtLocation(node.expression);
1981
+ result.push([node.expression, expectedType, node.expression, realType]);
1982
+ appendNodeToVisit(node.expression);
1983
+ continue;
1984
+ }
1985
+ ts.forEachChild(node, appendNodeToVisit);
1986
+ }
1987
+ cache.expectedAndRealType.set(sourceFile, result);
1988
+ return result;
1989
+ });
1990
+ var appendToUniqueTypesMap = fn(
1991
+ "TypeCheckerApi.appendToUniqueTypesMap"
1992
+ )(
1993
+ function* (memory, initialType, excludeNever) {
1994
+ const ts = yield* service(TypeScriptApi);
1995
+ const typeChecker = yield* service(TypeCheckerApi);
1996
+ const newIndexes = /* @__PURE__ */ new Set();
1997
+ const knownIndexes = /* @__PURE__ */ new Set();
1998
+ let toTest = [initialType];
1999
+ while (toTest.length > 0) {
2000
+ const type = toTest.pop();
2001
+ if (!type) break;
2002
+ if (excludeNever && type.flags & ts.TypeFlags.Never) {
2003
+ continue;
2004
+ }
2005
+ if (type.isUnion()) {
2006
+ toTest = toTest.concat(type.types);
2007
+ } else {
2008
+ const foundMatch = [];
2009
+ for (const [typeId, knownType] of memory.entries()) {
2010
+ const areSame = typeChecker.isTypeAssignableTo(knownType, type) && typeChecker.isTypeAssignableTo(type, knownType);
2011
+ if (areSame) {
2012
+ foundMatch.push(typeId);
2013
+ break;
2014
+ }
2015
+ }
2016
+ if (foundMatch.length === 0) {
2017
+ const newId = "t" + (memory.size + 1);
2018
+ memory.set(newId, type);
2019
+ newIndexes.add(newId);
2020
+ } else {
2021
+ knownIndexes.add(foundMatch[0]);
2022
+ }
2023
+ }
2024
+ }
2025
+ return {
2026
+ newIndexes,
2027
+ knownIndexes,
2028
+ allIndexes: pipe(
2029
+ fromIterable(newIndexes),
2030
+ appendAll(fromIterable(knownIndexes))
2031
+ )
2032
+ };
2033
+ }
2034
+ );
2035
+ function makeResolveExternalModuleName(typeChecker) {
2036
+ if (!(hasProperty(typeChecker, "resolveExternalModuleName") && isFunction(typeChecker.resolveExternalModuleName))) {
2037
+ return;
2038
+ }
2039
+ const _internal = typeChecker.resolveExternalModuleName;
2040
+ return (moduleSpecifier) => {
2041
+ return _internal(moduleSpecifier);
2042
+ };
2043
+ }
2044
+
2045
+ // src/core/TypeParser.ts
2046
+ var TypeParser = Tag("@effect/language-service/TypeParser");
2047
+ var TypeParserIssue = class _TypeParserIssue {
2048
+ _tag = "@effect/language-service/TypeParserIssue";
2049
+ static issue = fail(new _TypeParserIssue());
2050
+ };
2051
+ function make4(ts, typeChecker) {
2052
+ function typeParserIssue(_message, _type, _node) {
2053
+ return TypeParserIssue.issue;
2054
+ }
2055
+ function covariantTypeArgument(type) {
2056
+ const signatures = type.getCallSignatures();
2057
+ if (signatures.length !== 1) {
2058
+ return typeParserIssue("Covariant type has no call signature", type);
2059
+ }
2060
+ return succeed(signatures[0].getReturnType());
2061
+ }
2062
+ function contravariantTypeArgument(type) {
2063
+ const signatures = type.getCallSignatures();
2064
+ if (signatures.length !== 1) {
2065
+ return typeParserIssue("Contravariant type has no call signature", type);
2066
+ }
2067
+ return succeed(signatures[0].getTypeParameterAtPosition(0));
2068
+ }
2069
+ function invariantTypeArgument(type) {
2070
+ const signatures = type.getCallSignatures();
2071
+ if (signatures.length !== 1) {
2072
+ return typeParserIssue("Invariant type has no call signature", type);
2073
+ }
2074
+ return succeed(signatures[0].getReturnType());
2075
+ }
2076
+ const pipeableType = cachedBy(
2077
+ function(type, atLocation) {
2078
+ const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
2079
+ if (!pipeSymbol) {
2080
+ return typeParserIssue("Type has no 'pipe' property", type, atLocation);
2081
+ }
2082
+ const pipeType = typeChecker.getTypeOfSymbolAtLocation(pipeSymbol, atLocation);
2083
+ const signatures = pipeType.getCallSignatures();
2084
+ if (signatures.length === 0) {
2085
+ return typeParserIssue("'pipe' property is not callable", type, atLocation);
2086
+ }
2087
+ return succeed(type);
2088
+ },
2089
+ "TypeParser.pipeableType",
2090
+ (type) => type
2091
+ );
2092
+ const varianceStructCovariantType = (type, atLocation, propertyName) => {
2093
+ const propertySymbol = typeChecker.getPropertyOfType(type, propertyName);
1868
2094
  if (!propertySymbol) {
1869
2095
  return typeParserIssue(`Type has no '${propertyName}' property`, type, atLocation);
1870
2096
  }
@@ -2301,641 +2527,14 @@ function make4(ts, typeChecker) {
2301
2527
  };
2302
2528
  }
2303
2529
 
2304
- // src/completions/fnFunctionStar.ts
2305
- var fnFunctionStar = createCompletion({
2306
- name: "fnFunctionStar",
2307
- apply: fn("fnFunctionStar")(function* (sourceFile, position) {
2530
+ // src/diagnostics/floatingEffect.ts
2531
+ var floatingEffect = createDiagnostic({
2532
+ name: "floatingEffect",
2533
+ code: 3,
2534
+ severity: "error",
2535
+ apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
2308
2536
  const ts = yield* service(TypeScriptApi);
2309
- const typeParser = yield* service(TypeParser);
2310
- const maybeInfos = yield* option(
2311
- parseAccessedExpressionForCompletion(sourceFile, position)
2312
- );
2313
- if (isNone2(maybeInfos)) return [];
2314
- const { accessedObject } = maybeInfos.value;
2315
- const isEffectModule = yield* option(typeParser.importedEffectModule(accessedObject));
2316
- if (isNone2(isEffectModule)) return [];
2317
- const span = ts.createTextSpan(
2318
- accessedObject.end + 1,
2319
- Math.max(0, position - accessedObject.end - 1)
2320
- );
2321
- const maybeFnName = pipe(
2322
- yield* getAncestorNodesInRange(sourceFile, toTextRange(accessedObject.pos)),
2323
- filter(ts.isVariableDeclaration),
2324
- map3((_) => _.name && ts.isIdentifier(_.name) ? _.name.text : ""),
2325
- filter((_) => _.length > 0),
2326
- head,
2327
- map2((name) => [
2328
- {
2329
- name: `fn("${name}")`,
2330
- kind: ts.ScriptElementKind.constElement,
2331
- insertText: `fn("${name}")(function*(${"${1}"}){${"${0}"}})`,
2332
- replacementSpan: span,
2333
- isSnippet: true
2334
- }
2335
- ]),
2336
- getOrElse2(() => [])
2337
- );
2338
- return maybeFnName.concat([{
2339
- name: `fn(function*(){})`,
2340
- kind: ts.ScriptElementKind.constElement,
2341
- insertText: `fn(function*(${"${1}"}){${"${0}"}})`,
2342
- replacementSpan: span,
2343
- isSnippet: true
2344
- }, {
2345
- name: `fnUntraced(function*(){})`,
2346
- kind: ts.ScriptElementKind.constElement,
2347
- insertText: `fnUntraced(function*(${"${1}"}){${"${0}"}})`,
2348
- replacementSpan: span,
2349
- isSnippet: true
2350
- }]);
2351
- })
2352
- });
2353
-
2354
- // src/core/TypeCheckerApi.ts
2355
- var TypeCheckerApi = Tag("TypeChecker");
2356
- var TypeCheckerApiCache = Tag("TypeCheckerApiCache");
2357
- function makeTypeCheckerApiCache() {
2358
- return {
2359
- expectedAndRealType: /* @__PURE__ */ new WeakMap()
2360
- };
2361
- }
2362
- var deterministicTypeOrder = gen(function* () {
2363
- const typeChecker = yield* service(TypeCheckerApi);
2364
- return make2((a, b) => {
2365
- const aName = typeChecker.typeToString(a);
2366
- const bName = typeChecker.typeToString(b);
2367
- if (aName < bName) return -1;
2368
- if (aName > bName) return 1;
2369
- return 0;
2370
- });
2371
- });
2372
- var getMissingTypeEntriesInTargetType = fn(
2373
- "TypeCheckerApi.getMissingTypeEntriesInTargetType"
2374
- )(
2375
- function* (realType, expectedType) {
2376
- if (realType === expectedType) return [];
2377
- const typeChecker = yield* service(TypeCheckerApi);
2378
- const result = [];
2379
- let toTest = [realType];
2380
- while (toTest.length > 0) {
2381
- const type = toTest.pop();
2382
- if (!type) return result;
2383
- if (type.isUnion()) {
2384
- toTest = toTest.concat(type.types);
2385
- } else {
2386
- const assignable = typeChecker.isTypeAssignableTo(type, expectedType);
2387
- if (!assignable) {
2388
- result.push(type);
2389
- }
2390
- }
2391
- }
2392
- return result;
2393
- }
2394
- );
2395
- var CannotFindAncestorConvertibleDeclarationError = class {
2396
- constructor(node) {
2397
- this.node = node;
2398
- }
2399
- _tag = "@effect/language-service/CannotFindAncestorConvertibleDeclarationError";
2400
- };
2401
- var getAncestorConvertibleDeclaration = fn(
2402
- "TypeCheckerApi.getAncestorConvertibleDeclaration"
2403
- )(function* (node) {
2404
- const ts = yield* service(TypeScriptApi);
2405
- let current = node;
2406
- while (current) {
2407
- if (ts.isFunctionDeclaration(current) || ts.isFunctionExpression(current) || ts.isArrowFunction(current) || ts.isMethodDeclaration(current)) {
2408
- return current;
2409
- }
2410
- current = current.parent;
2411
- }
2412
- return yield* fail(new CannotFindAncestorConvertibleDeclarationError(node));
2413
- });
2414
- var CannotInferReturnTypeFromEmptyBody = class {
2415
- constructor(declaration) {
2416
- this.declaration = declaration;
2417
- }
2418
- _tag = "@effect/language-service/CannotInferReturnTypeFromEmptyBody";
2419
- };
2420
- var CannotInferReturnType = class {
2421
- constructor(declaration) {
2422
- this.declaration = declaration;
2423
- }
2424
- _tag = "@effect/language-service/CannotInferReturnType";
2425
- };
2426
- var getInferredReturnType = fn("TypeCheckerApi.getInferredReturnType")(function* (declaration) {
2427
- const typeChecker = yield* service(TypeCheckerApi);
2428
- if (!declaration.body) {
2429
- return yield* fail(
2430
- new CannotInferReturnTypeFromEmptyBody(declaration)
2431
- );
2432
- }
2433
- let returnType;
2434
- if (typeChecker.isImplementationOfOverload(declaration)) {
2435
- const signatures = typeChecker.getTypeAtLocation(declaration).getCallSignatures();
2436
- if (signatures.length > 1) {
2437
- returnType = typeChecker.getUnionType(
2438
- signatures.map((s) => s.getReturnType()).filter((_) => !!_)
2439
- );
2440
- }
2441
- }
2442
- if (!returnType) {
2443
- const signature = typeChecker.getSignatureFromDeclaration(declaration);
2444
- if (signature) {
2445
- const typePredicate = typeChecker.getTypePredicateOfSignature(signature);
2446
- if (typePredicate && typePredicate.type) {
2447
- return typePredicate.type;
2448
- } else {
2449
- returnType = typeChecker.getReturnTypeOfSignature(signature);
2450
- }
2451
- }
2452
- }
2453
- if (!returnType) {
2454
- return yield* fail(
2455
- new CannotInferReturnType(declaration)
2456
- );
2457
- }
2458
- return returnType;
2459
- });
2460
- var expectedAndRealType = fn("TypeCheckerApi.expectedAndRealType")(function* (sourceFile) {
2461
- const cache = yield* service(TypeCheckerApiCache);
2462
- const resultCached = cache.expectedAndRealType.get(sourceFile);
2463
- if (resultCached) return resultCached;
2464
- const typeChecker = yield* service(TypeCheckerApi);
2465
- const ts = yield* service(TypeScriptApi);
2466
- const result = [];
2467
- const nodeToVisit = [sourceFile];
2468
- const appendNodeToVisit = (node) => {
2469
- nodeToVisit.push(node);
2470
- return void 0;
2471
- };
2472
- while (nodeToVisit.length > 0) {
2473
- const node = nodeToVisit.shift();
2474
- if (ts.isVariableDeclaration(node) && node.initializer) {
2475
- const expectedType = typeChecker.getTypeAtLocation(node.name);
2476
- const realType = typeChecker.getTypeAtLocation(node.initializer);
2477
- result.push([node.name, expectedType, node.initializer, realType]);
2478
- appendNodeToVisit(node.initializer);
2479
- continue;
2480
- } else if (ts.isCallExpression(node)) {
2481
- const resolvedSignature = typeChecker.getResolvedSignature(node);
2482
- if (resolvedSignature) {
2483
- resolvedSignature.getParameters().map((parameter, index) => {
2484
- const expectedType = typeChecker.getTypeOfSymbolAtLocation(parameter, node);
2485
- const realType = typeChecker.getTypeAtLocation(node.arguments[index]);
2486
- result.push([
2487
- node.arguments[index],
2488
- expectedType,
2489
- node.arguments[index],
2490
- realType
2491
- ]);
2492
- });
2493
- }
2494
- ts.forEachChild(node, appendNodeToVisit);
2495
- continue;
2496
- } else if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
2497
- const parent = node.parent;
2498
- if (ts.isObjectLiteralElement(parent)) {
2499
- if (ts.isObjectLiteralExpression(parent.parent) && parent.name === node) {
2500
- const type = typeChecker.getContextualType(parent.parent);
2501
- if (type) {
2502
- const symbol3 = typeChecker.getPropertyOfType(type, node.text);
2503
- if (symbol3) {
2504
- const expectedType = typeChecker.getTypeOfSymbolAtLocation(symbol3, node);
2505
- const realType = typeChecker.getTypeAtLocation(node);
2506
- result.push([node, expectedType, node, realType]);
2507
- }
2508
- }
2509
- }
2510
- }
2511
- ts.forEachChild(node, appendNodeToVisit);
2512
- continue;
2513
- } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
2514
- const expectedType = typeChecker.getTypeAtLocation(node.left);
2515
- const realType = typeChecker.getTypeAtLocation(node.right);
2516
- result.push([node.left, expectedType, node.right, realType]);
2517
- appendNodeToVisit(node.right);
2518
- continue;
2519
- } else if (ts.isReturnStatement(node) && node.expression) {
2520
- const parentDeclaration = yield* option(getAncestorConvertibleDeclaration(node));
2521
- if (isSome2(parentDeclaration)) {
2522
- const expectedType = yield* option(getInferredReturnType(parentDeclaration.value));
2523
- const realType = typeChecker.getTypeAtLocation(node.expression);
2524
- if (isSome2(expectedType)) {
2525
- result.push([node, expectedType.value, node, realType]);
2526
- }
2527
- }
2528
- ts.forEachChild(node, appendNodeToVisit);
2529
- continue;
2530
- } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length === 0 && ts.isExpression(node.body)) {
2531
- const body = node.body;
2532
- const expectedType = typeChecker.getContextualType(body);
2533
- const realType = typeChecker.getTypeAtLocation(body);
2534
- if (expectedType) {
2535
- result.push([body, expectedType, body, realType]);
2536
- }
2537
- ts.forEachChild(body, appendNodeToVisit);
2538
- continue;
2539
- } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length > 0 && ts.isExpression(node.body)) {
2540
- const body = node.body;
2541
- const expectedType = yield* option(getInferredReturnType(node));
2542
- const realType = typeChecker.getTypeAtLocation(body);
2543
- if (isSome2(expectedType)) {
2544
- result.push([body, expectedType.value, body, realType]);
2545
- }
2546
- ts.forEachChild(body, appendNodeToVisit);
2547
- continue;
2548
- } else if (ts.isSatisfiesExpression(node)) {
2549
- const expectedType = typeChecker.getTypeAtLocation(node.type);
2550
- const realType = typeChecker.getTypeAtLocation(node.expression);
2551
- result.push([node.expression, expectedType, node.expression, realType]);
2552
- appendNodeToVisit(node.expression);
2553
- continue;
2554
- }
2555
- ts.forEachChild(node, appendNodeToVisit);
2556
- }
2557
- cache.expectedAndRealType.set(sourceFile, result);
2558
- return result;
2559
- });
2560
- var appendToUniqueTypesMap = fn(
2561
- "TypeCheckerApi.appendToUniqueTypesMap"
2562
- )(
2563
- function* (memory, initialType, excludeNever) {
2564
- const ts = yield* service(TypeScriptApi);
2565
- const typeChecker = yield* service(TypeCheckerApi);
2566
- const newIndexes = /* @__PURE__ */ new Set();
2567
- const knownIndexes = /* @__PURE__ */ new Set();
2568
- let toTest = [initialType];
2569
- while (toTest.length > 0) {
2570
- const type = toTest.pop();
2571
- if (!type) break;
2572
- if (excludeNever && type.flags & ts.TypeFlags.Never) {
2573
- continue;
2574
- }
2575
- if (type.isUnion()) {
2576
- toTest = toTest.concat(type.types);
2577
- } else {
2578
- const foundMatch = [];
2579
- for (const [typeId, knownType] of memory.entries()) {
2580
- const areSame = typeChecker.isTypeAssignableTo(knownType, type) && typeChecker.isTypeAssignableTo(type, knownType);
2581
- if (areSame) {
2582
- foundMatch.push(typeId);
2583
- break;
2584
- }
2585
- }
2586
- if (foundMatch.length === 0) {
2587
- const newId = "t" + (memory.size + 1);
2588
- memory.set(newId, type);
2589
- newIndexes.add(newId);
2590
- } else {
2591
- knownIndexes.add(foundMatch[0]);
2592
- }
2593
- }
2594
- }
2595
- return {
2596
- newIndexes,
2597
- knownIndexes,
2598
- allIndexes: pipe(
2599
- fromIterable(newIndexes),
2600
- appendAll(fromIterable(knownIndexes))
2601
- )
2602
- };
2603
- }
2604
- );
2605
- function makeResolveExternalModuleName(typeChecker) {
2606
- if (!(hasProperty(typeChecker, "resolveExternalModuleName") && isFunction(typeChecker.resolveExternalModuleName))) {
2607
- return;
2608
- }
2609
- const _internal = typeChecker.resolveExternalModuleName;
2610
- return (moduleSpecifier) => {
2611
- return _internal(moduleSpecifier);
2612
- };
2613
- }
2614
-
2615
- // src/completions/genFunctionStar.ts
2616
- var genFunctionStar = createCompletion({
2617
- name: "genFunctionStar",
2618
- apply: fn("genFunctionStar")(function* (sourceFile, position) {
2619
- const ts = yield* service(TypeScriptApi);
2620
- const typeChecker = yield* service(TypeCheckerApi);
2621
- const maybeInfos = yield* option(
2622
- parseAccessedExpressionForCompletion(sourceFile, position)
2623
- );
2624
- if (isNone2(maybeInfos)) return [];
2625
- const { accessedObject } = maybeInfos.value;
2626
- const type = typeChecker.getTypeAtLocation(accessedObject);
2627
- const genMemberSymbol = type.getProperty("gen");
2628
- if (!genMemberSymbol) return [];
2629
- const genType = typeChecker.getTypeOfSymbolAtLocation(genMemberSymbol, accessedObject);
2630
- if (genType.getCallSignatures().length === 0) return [];
2631
- const span = ts.createTextSpan(
2632
- accessedObject.end + 1,
2633
- Math.max(0, position - accessedObject.end - 1)
2634
- );
2635
- return [{
2636
- name: `gen(function*(){})`,
2637
- kind: ts.ScriptElementKind.constElement,
2638
- insertText: `gen(function*(){${"${0}"}})`,
2639
- replacementSpan: span,
2640
- isSnippet: true
2641
- }];
2642
- })
2643
- });
2644
-
2645
- // src/completions/rpcMakeClasses.ts
2646
- var rpcMakeClasses = createCompletion({
2647
- name: "rpcMakeClasses",
2648
- apply: fn("rpcMakeClasses")(function* (sourceFile, position) {
2649
- const ts = yield* service(TypeScriptApi);
2650
- const maybeInfos = yield* option(
2651
- parseDataForExtendsClassCompletion(sourceFile, position)
2652
- );
2653
- if (isNone2(maybeInfos)) return [];
2654
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
2655
- const rpcName = yield* option(
2656
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
2657
- sourceFile,
2658
- "@effect/rpc",
2659
- "Rpc"
2660
- )
2661
- );
2662
- const rpcIdentifier = match(rpcName, {
2663
- onNone: () => "Rpc",
2664
- onSome: (_) => _.text
2665
- });
2666
- if (rpcIdentifier !== accessedObject.text) return [];
2667
- const name = className.text;
2668
- return [{
2669
- name: `make("${name}")`,
2670
- kind: ts.ScriptElementKind.constElement,
2671
- insertText: `${rpcIdentifier}.make("${name}", {${"${0}"}}) {}`,
2672
- replacementSpan,
2673
- isSnippet: true
2674
- }];
2675
- })
2676
- });
2677
-
2678
- // src/completions.ts
2679
- var completions = [
2680
- effectSchemaSelfInClasses,
2681
- effectSelfInClasses,
2682
- contextSelfInClasses,
2683
- rpcMakeClasses,
2684
- genFunctionStar,
2685
- fnFunctionStar,
2686
- effectDataClasses
2687
- ];
2688
-
2689
- // src/completions/middlewareNamespaceImports.ts
2690
- var importablePackagesMetadataCache = /* @__PURE__ */ new Map();
2691
- var makeImportablePackagesMetadata = fn("makeImportablePackagesMetadata")(function* (sourceFile) {
2692
- const ts = yield* service(TypeScriptApi);
2693
- const program = yield* service(TypeScriptProgram);
2694
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2695
- const host = program;
2696
- const namespaceByFileName = /* @__PURE__ */ new Map();
2697
- const excludedByFileName = /* @__PURE__ */ new Map();
2698
- const unbarreledModulePathByFileName = /* @__PURE__ */ new Map();
2699
- for (const packageName of languageServicePluginOptions.namespaceImportPackages) {
2700
- const barrelModule = ts.resolveModuleName(packageName, sourceFile.fileName, program.getCompilerOptions(), host);
2701
- if (barrelModule.resolvedModule) {
2702
- const barrelPath = barrelModule.resolvedModule.resolvedFileName;
2703
- const barrelSource = program.getSourceFile(barrelPath) || ts.createSourceFile(barrelPath, host.readFile(barrelPath) || "", sourceFile.languageVersion, true);
2704
- if (barrelSource) {
2705
- for (const statement of barrelSource.statements) {
2706
- if (ts.isExportDeclaration(statement)) {
2707
- const exportClause = statement.exportClause;
2708
- const moduleSpecifier = statement.moduleSpecifier;
2709
- if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
2710
- const unbarreledModulePathResolved = ts.resolveModuleName(
2711
- moduleSpecifier.text,
2712
- barrelSource.fileName,
2713
- program.getCompilerOptions(),
2714
- host
2715
- );
2716
- if (unbarreledModulePathResolved.resolvedModule) {
2717
- const unbarreledModulePath = unbarreledModulePathResolved.resolvedModule.resolvedFileName;
2718
- if (exportClause && ts.isNamespaceExport(exportClause) && ts.isIdentifier(exportClause.name)) {
2719
- namespaceByFileName.set(unbarreledModulePath, exportClause.name.text);
2720
- const existingUnbarreledModulePath = unbarreledModulePathByFileName.get(barrelSource.fileName) || [];
2721
- existingUnbarreledModulePath.push([exportClause.name.text, unbarreledModulePath]);
2722
- unbarreledModulePathByFileName.set(barrelSource.fileName, existingUnbarreledModulePath);
2723
- }
2724
- if (exportClause && ts.isNamedExports(exportClause)) {
2725
- for (const element of exportClause.elements) {
2726
- if (!ts.isIdentifier(element.name)) continue;
2727
- const methodName = element.name.text;
2728
- const excludedMethods = excludedByFileName.get(methodName) || [];
2729
- excludedMethods.push(unbarreledModulePath);
2730
- excludedByFileName.set(methodName, excludedMethods);
2731
- }
2732
- }
2733
- }
2734
- }
2735
- }
2736
- }
2737
- }
2738
- }
2739
- }
2740
- return {
2741
- getImportNamespaceByFileName: (fileName) => namespaceByFileName.get(fileName),
2742
- isExcludedFromNamespaceImport: (fileName, exportName) => (excludedByFileName.get(exportName) || []).includes(fileName),
2743
- getUnbarreledModulePath: (fileName, exportName) => unbarreledModulePathByFileName.get(fileName)?.find(([name]) => name === exportName)?.[1]
2744
- };
2745
- });
2746
- var appendEffectCompletionEntryData = fn("collectNamespaceImports")(
2747
- function* (sourceFile, applicableCompletions) {
2748
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2749
- if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletions;
2750
- const packagesMetadata = importablePackagesMetadataCache.get(sourceFile.fileName) || (yield* makeImportablePackagesMetadata(sourceFile));
2751
- importablePackagesMetadataCache.set(sourceFile.fileName, packagesMetadata);
2752
- if (applicableCompletions) {
2753
- return {
2754
- ...applicableCompletions,
2755
- entries: applicableCompletions.entries.map((entry) => {
2756
- if (entry.data && entry.data.fileName && !entry.insertText && !entry.filterText && entry.data.exportName && entry.data.moduleSpecifier) {
2757
- const isExcluded = packagesMetadata.isExcludedFromNamespaceImport(
2758
- entry.data.fileName,
2759
- entry.data.exportName
2760
- );
2761
- if (isExcluded) return entry;
2762
- const unbarreledModulePath = packagesMetadata.getUnbarreledModulePath(
2763
- entry.data.fileName,
2764
- entry.data.exportName
2765
- );
2766
- const namespaceName = packagesMetadata.getImportNamespaceByFileName(
2767
- unbarreledModulePath || entry.data.fileName
2768
- );
2769
- if (namespaceName) {
2770
- return {
2771
- ...entry,
2772
- // insertText: unbarreledModulePath ? namespaceName : namespaceName + "." + entry.name,
2773
- // filterText: entry.name,
2774
- data: {
2775
- ...entry.data,
2776
- effectNamespaceName: namespaceName,
2777
- effectUnbarreledModulePath: unbarreledModulePath || "",
2778
- effectReplaceSpan: entry.replacementSpan || applicableCompletions.optionalReplacementSpan
2779
- }
2780
- };
2781
- }
2782
- }
2783
- return entry;
2784
- })
2785
- };
2786
- }
2787
- return applicableCompletions;
2788
- }
2789
- );
2790
- var postprocessCompletionEntryDetails = fn("postprocessCompletionEntryDetails")(
2791
- function* (sourceFile, data, applicableCompletionEntryDetails, formatOptions, preferences, languageServiceHost) {
2792
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2793
- if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletionEntryDetails;
2794
- const ts = yield* service(TypeScriptApi);
2795
- const program = yield* service(TypeScriptProgram);
2796
- const getModuleSpecifier = makeGetModuleSpecifier(ts);
2797
- if (!getModuleSpecifier) return applicableCompletionEntryDetails;
2798
- if (!applicableCompletionEntryDetails) return applicableCompletionEntryDetails;
2799
- if (!data) return applicableCompletionEntryDetails;
2800
- if (!("effectNamespaceName" in data && "effectUnbarreledModulePath" in data && "effectReplaceSpan" in data)) {
2801
- return applicableCompletionEntryDetails;
2802
- }
2803
- const effectReplaceSpan = data.effectReplaceSpan;
2804
- const codeActions = applicableCompletionEntryDetails.codeActions;
2805
- if (codeActions && codeActions.length === 1) {
2806
- const action = codeActions[0];
2807
- if (action.changes.length === 1) {
2808
- const fileTextChanges = action.changes[0];
2809
- if (fileTextChanges.fileName === sourceFile.fileName && fileTextChanges.textChanges.length === 1) {
2810
- const change = fileTextChanges.textChanges[0];
2811
- let hasImportActions = false;
2812
- if (change.newText.trim().toLowerCase().startsWith("import") && change.newText.indexOf(data.exportName) > -1) {
2813
- hasImportActions = true;
2814
- }
2815
- if (!hasImportActions && change.newText.indexOf(data.exportName) > -1) {
2816
- const ancestorNodes = yield* getAncestorNodesInRange(sourceFile, {
2817
- pos: change.span.start,
2818
- end: change.span.start
2819
- });
2820
- const importNodes = ancestorNodes.filter((node) => ts.isImportDeclaration(node));
2821
- hasImportActions = importNodes.length > 0;
2822
- }
2823
- if (!hasImportActions) return applicableCompletionEntryDetails;
2824
- const formatContext = ts.formatting.getFormatContext(
2825
- formatOptions || {},
2826
- languageServiceHost
2827
- );
2828
- const changes = ts.textChanges.ChangeTracker.with(
2829
- {
2830
- formatContext,
2831
- host: languageServiceHost,
2832
- preferences: preferences || {}
2833
- },
2834
- (changeTracker) => {
2835
- const isBarrelRedirect = String(data.effectUnbarreledModulePath).length > 0;
2836
- const moduleSpecifier = isBarrelRedirect ? getModuleSpecifier(
2837
- program.getCompilerOptions(),
2838
- sourceFile,
2839
- sourceFile.fileName,
2840
- String(data.effectUnbarreledModulePath),
2841
- program
2842
- ) : String(data.moduleSpecifier);
2843
- ts.insertImports(
2844
- changeTracker,
2845
- sourceFile,
2846
- ts.factory.createImportDeclaration(
2847
- void 0,
2848
- ts.factory.createImportClause(
2849
- false,
2850
- void 0,
2851
- ts.factory.createNamespaceImport(ts.factory.createIdentifier(String(data.effectNamespaceName)))
2852
- ),
2853
- ts.factory.createStringLiteral(moduleSpecifier)
2854
- ),
2855
- true,
2856
- preferences || {}
2857
- );
2858
- if (!isBarrelRedirect) {
2859
- changeTracker.insertText(
2860
- sourceFile,
2861
- effectReplaceSpan.start,
2862
- String(data.effectNamespaceName) + "."
2863
- );
2864
- }
2865
- }
2866
- );
2867
- return {
2868
- ...applicableCompletionEntryDetails,
2869
- codeActions: [
2870
- {
2871
- description: "Import * as " + data.effectNamespaceName + " from " + data.effectUnbarreledModulePath,
2872
- changes
2873
- }
2874
- ]
2875
- };
2876
- }
2877
- }
2878
- }
2879
- return applicableCompletionEntryDetails;
2880
- }
2881
- );
2882
-
2883
- // src/diagnostics/duplicatePackage.ts
2884
- var checkedPackagesCache = /* @__PURE__ */ new Map();
2885
- var programResolvedCacheSize = /* @__PURE__ */ new Map();
2886
- var duplicatePackage = createDiagnostic({
2887
- name: "duplicatePackage",
2888
- code: 6,
2889
- severity: "warning",
2890
- apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
2891
- const program = yield* service(TypeScriptProgram);
2892
- const options = yield* service(LanguageServicePluginOptions);
2893
- if (sourceFile.statements.length < 1) return;
2894
- let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
2895
- const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
2896
- const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
2897
- if (newResolvedModuleSize !== oldResolvedSize) {
2898
- const seenPackages = /* @__PURE__ */ new Set();
2899
- resolvedPackages = {};
2900
- program.getSourceFiles().map((_) => {
2901
- const packageInfo = parsePackageContentNameAndVersionFromScope(_);
2902
- if (!packageInfo) return;
2903
- const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
2904
- if (seenPackages.has(packageNameAndVersion)) return;
2905
- seenPackages.add(packageNameAndVersion);
2906
- if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
2907
- if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
2908
- resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
2909
- resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
2910
- });
2911
- checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
2912
- programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
2913
- }
2914
- for (const packageName of Object.keys(resolvedPackages)) {
2915
- if (Object.keys(resolvedPackages[packageName]).length > 1) {
2916
- const versions = Object.keys(resolvedPackages[packageName]);
2917
- report({
2918
- node: sourceFile.statements[0],
2919
- messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
2920
- Cleanup your dependencies and your package lockfile to avoid multiple instances of this package and reload the project.
2921
- If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
2922
-
2923
- ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
2924
- fixes: []
2925
- });
2926
- }
2927
- }
2928
- })
2929
- });
2930
-
2931
- // src/diagnostics/floatingEffect.ts
2932
- var floatingEffect = createDiagnostic({
2933
- name: "floatingEffect",
2934
- code: 3,
2935
- severity: "error",
2936
- apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
2937
- const ts = yield* service(TypeScriptApi);
2938
- const typeChecker = yield* service(TypeCheckerApi);
2537
+ const typeChecker = yield* service(TypeCheckerApi);
2939
2538
  const typeParser = yield* service(TypeParser);
2940
2539
  function isFloatingExpression(node) {
2941
2540
  if (!ts.isExpressionStatement(node)) return false;
@@ -3295,38 +2894,285 @@ var missingEffectError = createDiagnostic({
3295
2894
  apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
3296
2895
  const typeChecker = yield* service(TypeCheckerApi);
3297
2896
  const typeParser = yield* service(TypeParser);
3298
- const typeOrder = yield* deterministicTypeOrder;
3299
- const checkForMissingErrorTypes = (node, expectedType, valueNode, realType) => pipe(
3300
- all(
3301
- typeParser.effectType(expectedType, node),
3302
- typeParser.effectType(realType, valueNode)
3303
- ),
3304
- flatMap2(
3305
- ([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
3306
- realEffect.E,
3307
- expectedEffect.E
3308
- )
3309
- )
3310
- );
3311
- const sortTypes = sort(typeOrder);
3312
- const entries = yield* expectedAndRealType(sourceFile);
3313
- for (const [node, expectedType, valueNode, realType] of entries) {
3314
- if (expectedType !== realType) {
2897
+ const typeOrder = yield* deterministicTypeOrder;
2898
+ const checkForMissingErrorTypes = (node, expectedType, valueNode, realType) => pipe(
2899
+ all(
2900
+ typeParser.effectType(expectedType, node),
2901
+ typeParser.effectType(realType, valueNode)
2902
+ ),
2903
+ flatMap2(
2904
+ ([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
2905
+ realEffect.E,
2906
+ expectedEffect.E
2907
+ )
2908
+ )
2909
+ );
2910
+ const sortTypes = sort(typeOrder);
2911
+ const entries = yield* expectedAndRealType(sourceFile);
2912
+ for (const [node, expectedType, valueNode, realType] of entries) {
2913
+ if (expectedType !== realType) {
2914
+ yield* pipe(
2915
+ checkForMissingErrorTypes(
2916
+ node,
2917
+ expectedType,
2918
+ valueNode,
2919
+ realType
2920
+ ),
2921
+ map4(
2922
+ (missingTypes) => missingTypes.length > 0 ? report(
2923
+ {
2924
+ node,
2925
+ messageText: `Missing '${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect errors.`,
2926
+ fixes: []
2927
+ }
2928
+ ) : void 0
2929
+ ),
2930
+ ignore
2931
+ );
2932
+ }
2933
+ }
2934
+ })
2935
+ });
2936
+
2937
+ // src/diagnostics/missingReturnYieldStar.ts
2938
+ var missingReturnYieldStar = createDiagnostic({
2939
+ name: "missingReturnYieldStar",
2940
+ code: 7,
2941
+ severity: "error",
2942
+ apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
2943
+ const ts = yield* service(TypeScriptApi);
2944
+ const typeChecker = yield* service(TypeCheckerApi);
2945
+ const typeParser = yield* service(TypeParser);
2946
+ const nodeToVisit = [];
2947
+ const appendNodeToVisit = (node) => {
2948
+ nodeToVisit.push(node);
2949
+ return void 0;
2950
+ };
2951
+ ts.forEachChild(sourceFile, appendNodeToVisit);
2952
+ while (nodeToVisit.length > 0) {
2953
+ const node = nodeToVisit.shift();
2954
+ ts.forEachChild(node, appendNodeToVisit);
2955
+ if (ts.isYieldExpression(node) && node.expression && node.asteriskToken) {
2956
+ const type = typeChecker.getTypeAtLocation(node.expression);
2957
+ const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
2958
+ if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
2959
+ const generatorFunctionOrReturnStatement = ts.findAncestor(
2960
+ node,
2961
+ (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_)
2962
+ );
2963
+ if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement)) {
2964
+ if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
2965
+ const effectGenNode = generatorFunctionOrReturnStatement.parent;
2966
+ const effectGenLike = yield* pipe(
2967
+ typeParser.effectGen(effectGenNode),
2968
+ orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
2969
+ orElse2(() => typeParser.effectFnGen(effectGenNode)),
2970
+ option
2971
+ );
2972
+ if (isSome2(effectGenLike)) {
2973
+ const fix = node.expression ? [{
2974
+ fixName: "missingReturnYieldStar_fix",
2975
+ description: "Add return statement",
2976
+ apply: gen(function* () {
2977
+ const changeTracker = yield* service(ChangeTracker);
2978
+ changeTracker.replaceNode(
2979
+ sourceFile,
2980
+ node,
2981
+ ts.factory.createReturnStatement(
2982
+ node
2983
+ )
2984
+ );
2985
+ })
2986
+ }] : [];
2987
+ report({
2988
+ node,
2989
+ messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
2990
+ fixes: fix
2991
+ });
2992
+ }
2993
+ }
2994
+ }
2995
+ }
2996
+ }
2997
+ }
2998
+ })
2999
+ });
3000
+
3001
+ // src/diagnostics/missingStarInYieldEffectGen.ts
3002
+ var missingStarInYieldEffectGen = createDiagnostic({
3003
+ name: "missingStarInYieldEffectGen",
3004
+ code: 4,
3005
+ severity: "error",
3006
+ apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
3007
+ const ts = yield* service(TypeScriptApi);
3008
+ const typeParser = yield* service(TypeParser);
3009
+ const brokenGenerators = /* @__PURE__ */ new Set();
3010
+ const brokenYields = /* @__PURE__ */ new Set();
3011
+ const nodeToVisit = [];
3012
+ const appendNodeToVisit = (node) => {
3013
+ nodeToVisit.push(node);
3014
+ return void 0;
3015
+ };
3016
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3017
+ while (nodeToVisit.length > 0) {
3018
+ const node = nodeToVisit.shift();
3019
+ ts.forEachChild(node, appendNodeToVisit);
3020
+ if (ts.isYieldExpression(node) && node.expression && node.asteriskToken === void 0) {
3021
+ const functionStarNode = ts.findAncestor(
3022
+ node,
3023
+ (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_)
3024
+ );
3025
+ if (functionStarNode && functionStarNode.parent) {
3026
+ const effectGenNode = functionStarNode.parent;
3027
+ yield* pipe(
3028
+ typeParser.effectGen(effectGenNode),
3029
+ orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3030
+ orElse2(() => typeParser.effectFnGen(effectGenNode)),
3031
+ map4(({ functionStar }) => {
3032
+ if (functionStar) {
3033
+ brokenGenerators.add(functionStar);
3034
+ }
3035
+ brokenYields.add(node);
3036
+ }),
3037
+ ignore
3038
+ );
3039
+ }
3040
+ }
3041
+ }
3042
+ brokenGenerators.forEach(
3043
+ (node) => report({
3044
+ node,
3045
+ messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
3046
+ fixes: []
3047
+ })
3048
+ );
3049
+ brokenYields.forEach((node) => {
3050
+ const fix = node.expression ? [{
3051
+ fixName: "missingStarInYieldEffectGen_fix",
3052
+ description: "Replace yield with yield*",
3053
+ apply: gen(function* () {
3054
+ const changeTracker = yield* service(ChangeTracker);
3055
+ changeTracker.replaceNode(
3056
+ sourceFile,
3057
+ node,
3058
+ ts.factory.createYieldExpression(
3059
+ ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3060
+ node.expression
3061
+ )
3062
+ );
3063
+ })
3064
+ }] : [];
3065
+ report({
3066
+ node,
3067
+ messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
3068
+ fixes: fix
3069
+ });
3070
+ });
3071
+ })
3072
+ });
3073
+
3074
+ // src/diagnostics/returnEffectInGen.ts
3075
+ var returnEffectInGen = createDiagnostic({
3076
+ name: "returnEffectInGen",
3077
+ code: 11,
3078
+ severity: "suggestion",
3079
+ apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
3080
+ const ts = yield* service(TypeScriptApi);
3081
+ const typeChecker = yield* service(TypeCheckerApi);
3082
+ const typeParser = yield* service(TypeParser);
3083
+ const nodeToVisit = [];
3084
+ const appendNodeToVisit = (node) => {
3085
+ nodeToVisit.push(node);
3086
+ return void 0;
3087
+ };
3088
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3089
+ while (nodeToVisit.length > 0) {
3090
+ const node = nodeToVisit.shift();
3091
+ ts.forEachChild(node, appendNodeToVisit);
3092
+ if (ts.isReturnStatement(node) && node.expression) {
3093
+ if (ts.isYieldExpression(node.expression)) continue;
3094
+ const generatorOrRegularFunction = ts.findAncestor(
3095
+ node,
3096
+ (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
3097
+ );
3098
+ if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
3099
+ const type = typeChecker.getTypeAtLocation(node.expression);
3100
+ const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
3101
+ if (isSome2(maybeEffect)) {
3102
+ if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
3103
+ const effectGenNode = generatorOrRegularFunction.parent;
3104
+ yield* pipe(
3105
+ typeParser.effectGen(effectGenNode),
3106
+ orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3107
+ orElse2(() => typeParser.effectFnGen(effectGenNode)),
3108
+ map4(() => {
3109
+ const fix = node.expression ? [{
3110
+ fixName: "returnEffectInGen_fix",
3111
+ description: "Add yield* statement",
3112
+ apply: gen(function* () {
3113
+ const changeTracker = yield* service(ChangeTracker);
3114
+ changeTracker.replaceNode(
3115
+ sourceFile,
3116
+ node.expression,
3117
+ ts.factory.createYieldExpression(
3118
+ ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3119
+ node.expression
3120
+ )
3121
+ );
3122
+ })
3123
+ }] : [];
3124
+ report({
3125
+ node,
3126
+ messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>.
3127
+ Maybe you wanted to return yield* instead?
3128
+ Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect, if so you can safely disable this diagnostic for this line through quickfixes.`,
3129
+ fixes: fix
3130
+ });
3131
+ }),
3132
+ ignore
3133
+ );
3134
+ }
3135
+ }
3136
+ }
3137
+ }
3138
+ })
3139
+ });
3140
+
3141
+ // src/diagnostics/unnecessaryEffectGen.ts
3142
+ var unnecessaryEffectGen = createDiagnostic({
3143
+ name: "unnecessaryEffectGen",
3144
+ code: 5,
3145
+ severity: "suggestion",
3146
+ apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
3147
+ const ts = yield* service(TypeScriptApi);
3148
+ const typeParser = yield* service(TypeParser);
3149
+ const nodeToVisit = [];
3150
+ const appendNodeToVisit = (node) => {
3151
+ nodeToVisit.push(node);
3152
+ return void 0;
3153
+ };
3154
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3155
+ while (nodeToVisit.length > 0) {
3156
+ const node = nodeToVisit.shift();
3157
+ ts.forEachChild(node, appendNodeToVisit);
3158
+ if (ts.isCallExpression(node)) {
3315
3159
  yield* pipe(
3316
- checkForMissingErrorTypes(
3317
- node,
3318
- expectedType,
3319
- valueNode,
3320
- realType
3321
- ),
3160
+ typeParser.unnecessaryEffectGen(node),
3322
3161
  map4(
3323
- (missingTypes) => missingTypes.length > 0 ? report(
3324
- {
3325
- node,
3326
- messageText: `Missing '${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect errors.`,
3327
- fixes: []
3328
- }
3329
- ) : void 0
3162
+ ({ replacementNode }) => report({
3163
+ node,
3164
+ messageText: `This Effect.gen contains a single return statement.`,
3165
+ fixes: [{
3166
+ fixName: "unnecessaryEffectGen_fix",
3167
+ description: "Remove the Effect.gen, and keep the body",
3168
+ apply: gen(function* () {
3169
+ const textChanges = yield* service(
3170
+ ChangeTracker
3171
+ );
3172
+ textChanges.replaceNode(sourceFile, node, yield* replacementNode);
3173
+ })
3174
+ }]
3175
+ })
3330
3176
  ),
3331
3177
  ignore
3332
3178
  );
@@ -3335,14 +3181,13 @@ var missingEffectError = createDiagnostic({
3335
3181
  })
3336
3182
  });
3337
3183
 
3338
- // src/diagnostics/missingReturnYieldStar.ts
3339
- var missingReturnYieldStar = createDiagnostic({
3340
- name: "missingReturnYieldStar",
3341
- code: 7,
3342
- severity: "error",
3343
- apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
3184
+ // src/diagnostics/unnecessaryPipe.ts
3185
+ var unnecessaryPipe = createDiagnostic({
3186
+ name: "unnecessaryPipe",
3187
+ code: 9,
3188
+ severity: "suggestion",
3189
+ apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
3344
3190
  const ts = yield* service(TypeScriptApi);
3345
- const typeChecker = yield* service(TypeCheckerApi);
3346
3191
  const typeParser = yield* service(TypeParser);
3347
3192
  const nodeToVisit = [];
3348
3193
  const appendNodeToVisit = (node) => {
@@ -3353,295 +3198,485 @@ var missingReturnYieldStar = createDiagnostic({
3353
3198
  while (nodeToVisit.length > 0) {
3354
3199
  const node = nodeToVisit.shift();
3355
3200
  ts.forEachChild(node, appendNodeToVisit);
3356
- if (ts.isYieldExpression(node) && node.expression && node.asteriskToken) {
3357
- const type = typeChecker.getTypeAtLocation(node.expression);
3358
- const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
3359
- if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
3360
- const generatorFunctionOrReturnStatement = ts.findAncestor(
3361
- node,
3362
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_)
3363
- );
3364
- if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement)) {
3365
- if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
3366
- const effectGenNode = generatorFunctionOrReturnStatement.parent;
3367
- const effectGenLike = yield* pipe(
3368
- typeParser.effectGen(effectGenNode),
3369
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3370
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3371
- option
3372
- );
3373
- if (isSome2(effectGenLike)) {
3374
- const fix = node.expression ? [{
3375
- fixName: "missingReturnYieldStar_fix",
3376
- description: "Add return statement",
3201
+ if (ts.isCallExpression(node)) {
3202
+ yield* pipe(
3203
+ typeParser.pipeCall(node),
3204
+ map4(({ args, subject }) => {
3205
+ if (args.length === 0) {
3206
+ report({
3207
+ node,
3208
+ messageText: `This pipe call contains no arguments.`,
3209
+ fixes: [{
3210
+ fixName: "unnecessaryPipe_fix",
3211
+ description: "Remove the pipe call",
3377
3212
  apply: gen(function* () {
3378
- const changeTracker = yield* service(ChangeTracker);
3379
- changeTracker.replaceNode(
3380
- sourceFile,
3381
- node,
3382
- ts.factory.createReturnStatement(
3383
- node
3384
- )
3213
+ const textChanges = yield* service(
3214
+ ChangeTracker
3385
3215
  );
3216
+ textChanges.replaceNode(sourceFile, node, subject);
3386
3217
  })
3387
- }] : [];
3388
- report({
3389
- node,
3390
- messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
3391
- fixes: fix
3392
- });
3393
- }
3218
+ }]
3219
+ });
3394
3220
  }
3395
- }
3221
+ }),
3222
+ ignore
3223
+ );
3224
+ }
3225
+ }
3226
+ })
3227
+ });
3228
+
3229
+ // src/diagnostics.ts
3230
+ var diagnostics = [
3231
+ duplicatePackage,
3232
+ missingEffectContext,
3233
+ missingEffectError,
3234
+ floatingEffect,
3235
+ missingStarInYieldEffectGen,
3236
+ unnecessaryEffectGen,
3237
+ missingReturnYieldStar,
3238
+ leakingRequirements,
3239
+ unnecessaryPipe,
3240
+ genericEffectServices,
3241
+ returnEffectInGen,
3242
+ importFromBarrel
3243
+ ];
3244
+
3245
+ // src/completions/effectDiagnosticsComment.ts
3246
+ var effectDiagnosticsComment = createCompletion({
3247
+ name: "effectDiagnosticsComment",
3248
+ apply: fn("effectDiagnosticsComment")(function* (sourceFile, position) {
3249
+ const ts = yield* service(TypeScriptApi);
3250
+ const sourceText = sourceFile.text;
3251
+ const match2 = /(\/\/|\/\*(?:\*?))\s*(@)\s*$/id.exec(sourceText.substring(0, position));
3252
+ if (match2 && match2.indices) {
3253
+ const lastIndex = match2.indices[2][0];
3254
+ const replacementSpan = {
3255
+ start: lastIndex,
3256
+ length: Math.max(0, position - lastIndex)
3257
+ };
3258
+ const allDiagnostics = sort(Object.values(diagnostics).map((diagnostic) => diagnostic.name), string2).join(",");
3259
+ const disableSnippet = "${1|" + allDiagnostics + "|}:${2|off,warning,error,message,suggestion|}$0";
3260
+ return [{
3261
+ name: `@effect-diagnostics`,
3262
+ kind: ts.ScriptElementKind.string,
3263
+ insertText: "@effect-diagnostics " + disableSnippet,
3264
+ isSnippet: true,
3265
+ replacementSpan
3266
+ }, {
3267
+ name: `@effect-diagnostics-next-line`,
3268
+ kind: ts.ScriptElementKind.string,
3269
+ insertText: "@effect-diagnostics-next-line " + disableSnippet,
3270
+ isSnippet: true,
3271
+ replacementSpan
3272
+ }];
3273
+ }
3274
+ return [];
3275
+ })
3276
+ });
3277
+
3278
+ // src/completions/effectSchemaSelfInClasses.ts
3279
+ var effectSchemaSelfInClasses = createCompletion({
3280
+ name: "effectSchemaSelfInClasses",
3281
+ apply: fn("effectSchemaSelfInClasses")(function* (sourceFile, position) {
3282
+ const ts = yield* service(TypeScriptApi);
3283
+ const maybeInfos = yield* option(
3284
+ parseDataForExtendsClassCompletion(sourceFile, position)
3285
+ );
3286
+ if (isNone2(maybeInfos)) return [];
3287
+ const { accessedObject, className, replacementSpan } = maybeInfos.value;
3288
+ const effectSchemaName = yield* option(
3289
+ findImportedModuleIdentifierByPackageAndNameOrBarrel(
3290
+ sourceFile,
3291
+ "effect",
3292
+ "Schema"
3293
+ )
3294
+ );
3295
+ const schemaIdentifier = match(effectSchemaName, {
3296
+ onNone: () => "Schema",
3297
+ onSome: (_) => _.text
3298
+ });
3299
+ if (schemaIdentifier !== accessedObject.text) return [];
3300
+ const name = className.text;
3301
+ return [{
3302
+ name: `Class<${name}>`,
3303
+ kind: ts.ScriptElementKind.constElement,
3304
+ insertText: `${schemaIdentifier}.Class<${name}>("${name}")({${"${0}"}}){}`,
3305
+ replacementSpan,
3306
+ isSnippet: true
3307
+ }, {
3308
+ name: `TaggedError<${name}>`,
3309
+ kind: ts.ScriptElementKind.constElement,
3310
+ insertText: `${schemaIdentifier}.TaggedError<${name}>("${name}")("${name}", {${"${0}"}}){}`,
3311
+ replacementSpan,
3312
+ isSnippet: true
3313
+ }, {
3314
+ name: `TaggedClass<${name}>`,
3315
+ kind: ts.ScriptElementKind.constElement,
3316
+ insertText: `${schemaIdentifier}.TaggedClass<${name}>("${name}")("${name}", {${"${0}"}}){}`,
3317
+ replacementSpan,
3318
+ isSnippet: true
3319
+ }, {
3320
+ name: `TaggedRequest<${name}>`,
3321
+ kind: ts.ScriptElementKind.constElement,
3322
+ insertText: `${schemaIdentifier}.TaggedRequest<${name}>("${name}")("${name}", {${"${0}"}}){}`,
3323
+ replacementSpan,
3324
+ isSnippet: true
3325
+ }];
3326
+ })
3327
+ });
3328
+
3329
+ // src/completions/effectSelfInClasses.ts
3330
+ var effectSelfInClasses = createCompletion({
3331
+ name: "effectSelfInClasses",
3332
+ apply: fn("effectSelfInClasses")(function* (sourceFile, position) {
3333
+ const ts = yield* service(TypeScriptApi);
3334
+ const maybeInfos = yield* option(
3335
+ parseDataForExtendsClassCompletion(sourceFile, position)
3336
+ );
3337
+ if (isNone2(maybeInfos)) return [];
3338
+ const { accessedObject, className, replacementSpan } = maybeInfos.value;
3339
+ const effectName = yield* option(
3340
+ findImportedModuleIdentifierByPackageAndNameOrBarrel(
3341
+ sourceFile,
3342
+ "effect",
3343
+ "Effect"
3344
+ )
3345
+ );
3346
+ const effectIdentifier = match(effectName, {
3347
+ onNone: () => "Effect",
3348
+ onSome: (_) => _.text
3349
+ });
3350
+ if (effectIdentifier !== accessedObject.text) return [];
3351
+ const name = className.text;
3352
+ return [{
3353
+ name: `Service<${name}>`,
3354
+ kind: ts.ScriptElementKind.constElement,
3355
+ insertText: `${effectIdentifier}.Service<${name}>()("${name}", {${"${0}"}}){}`,
3356
+ replacementSpan,
3357
+ isSnippet: true
3358
+ }];
3359
+ })
3360
+ });
3361
+
3362
+ // src/completions/fnFunctionStar.ts
3363
+ var fnFunctionStar = createCompletion({
3364
+ name: "fnFunctionStar",
3365
+ apply: fn("fnFunctionStar")(function* (sourceFile, position) {
3366
+ const ts = yield* service(TypeScriptApi);
3367
+ const typeParser = yield* service(TypeParser);
3368
+ const maybeInfos = yield* option(
3369
+ parseAccessedExpressionForCompletion(sourceFile, position)
3370
+ );
3371
+ if (isNone2(maybeInfos)) return [];
3372
+ const { accessedObject } = maybeInfos.value;
3373
+ const isEffectModule = yield* option(typeParser.importedEffectModule(accessedObject));
3374
+ if (isNone2(isEffectModule)) return [];
3375
+ const span = ts.createTextSpan(
3376
+ accessedObject.end + 1,
3377
+ Math.max(0, position - accessedObject.end - 1)
3378
+ );
3379
+ const maybeFnName = pipe(
3380
+ yield* getAncestorNodesInRange(sourceFile, toTextRange(accessedObject.pos)),
3381
+ filter(ts.isVariableDeclaration),
3382
+ map3((_) => _.name && ts.isIdentifier(_.name) ? _.name.text : ""),
3383
+ filter((_) => _.length > 0),
3384
+ head,
3385
+ map2((name) => [
3386
+ {
3387
+ name: `fn("${name}")`,
3388
+ kind: ts.ScriptElementKind.constElement,
3389
+ insertText: `fn("${name}")(function*(${"${1}"}){${"${0}"}})`,
3390
+ replacementSpan: span,
3391
+ isSnippet: true
3396
3392
  }
3397
- }
3398
- }
3393
+ ]),
3394
+ getOrElse2(() => [])
3395
+ );
3396
+ return maybeFnName.concat([{
3397
+ name: `fn(function*(){})`,
3398
+ kind: ts.ScriptElementKind.constElement,
3399
+ insertText: `fn(function*(${"${1}"}){${"${0}"}})`,
3400
+ replacementSpan: span,
3401
+ isSnippet: true
3402
+ }, {
3403
+ name: `fnUntraced(function*(){})`,
3404
+ kind: ts.ScriptElementKind.constElement,
3405
+ insertText: `fnUntraced(function*(${"${1}"}){${"${0}"}})`,
3406
+ replacementSpan: span,
3407
+ isSnippet: true
3408
+ }]);
3399
3409
  })
3400
3410
  });
3401
3411
 
3402
- // src/diagnostics/missingStarInYieldEffectGen.ts
3403
- var missingStarInYieldEffectGen = createDiagnostic({
3404
- name: "missingStarInYieldEffectGen",
3405
- code: 4,
3406
- severity: "error",
3407
- apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
3412
+ // src/completions/genFunctionStar.ts
3413
+ var genFunctionStar = createCompletion({
3414
+ name: "genFunctionStar",
3415
+ apply: fn("genFunctionStar")(function* (sourceFile, position) {
3408
3416
  const ts = yield* service(TypeScriptApi);
3409
- const typeParser = yield* service(TypeParser);
3410
- const brokenGenerators = /* @__PURE__ */ new Set();
3411
- const brokenYields = /* @__PURE__ */ new Set();
3412
- const nodeToVisit = [];
3413
- const appendNodeToVisit = (node) => {
3414
- nodeToVisit.push(node);
3415
- return void 0;
3416
- };
3417
- ts.forEachChild(sourceFile, appendNodeToVisit);
3418
- while (nodeToVisit.length > 0) {
3419
- const node = nodeToVisit.shift();
3420
- ts.forEachChild(node, appendNodeToVisit);
3421
- if (ts.isYieldExpression(node) && node.expression && node.asteriskToken === void 0) {
3422
- const functionStarNode = ts.findAncestor(
3423
- node,
3424
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_)
3425
- );
3426
- if (functionStarNode && functionStarNode.parent) {
3427
- const effectGenNode = functionStarNode.parent;
3428
- yield* pipe(
3429
- typeParser.effectGen(effectGenNode),
3430
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3431
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3432
- map4(({ functionStar }) => {
3433
- if (functionStar) {
3434
- brokenGenerators.add(functionStar);
3435
- }
3436
- brokenYields.add(node);
3437
- }),
3438
- ignore
3439
- );
3440
- }
3441
- }
3442
- }
3443
- brokenGenerators.forEach(
3444
- (node) => report({
3445
- node,
3446
- messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
3447
- fixes: []
3448
- })
3417
+ const typeChecker = yield* service(TypeCheckerApi);
3418
+ const maybeInfos = yield* option(
3419
+ parseAccessedExpressionForCompletion(sourceFile, position)
3449
3420
  );
3450
- brokenYields.forEach((node) => {
3451
- const fix = node.expression ? [{
3452
- fixName: "missingStarInYieldEffectGen_fix",
3453
- description: "Replace yield with yield*",
3454
- apply: gen(function* () {
3455
- const changeTracker = yield* service(ChangeTracker);
3456
- changeTracker.replaceNode(
3457
- sourceFile,
3458
- node,
3459
- ts.factory.createYieldExpression(
3460
- ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3461
- node.expression
3462
- )
3463
- );
3464
- })
3465
- }] : [];
3466
- report({
3467
- node,
3468
- messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
3469
- fixes: fix
3470
- });
3471
- });
3421
+ if (isNone2(maybeInfos)) return [];
3422
+ const { accessedObject } = maybeInfos.value;
3423
+ const type = typeChecker.getTypeAtLocation(accessedObject);
3424
+ const genMemberSymbol = type.getProperty("gen");
3425
+ if (!genMemberSymbol) return [];
3426
+ const genType = typeChecker.getTypeOfSymbolAtLocation(genMemberSymbol, accessedObject);
3427
+ if (genType.getCallSignatures().length === 0) return [];
3428
+ const span = ts.createTextSpan(
3429
+ accessedObject.end + 1,
3430
+ Math.max(0, position - accessedObject.end - 1)
3431
+ );
3432
+ return [{
3433
+ name: `gen(function*(){})`,
3434
+ kind: ts.ScriptElementKind.constElement,
3435
+ insertText: `gen(function*(){${"${0}"}})`,
3436
+ replacementSpan: span,
3437
+ isSnippet: true
3438
+ }];
3472
3439
  })
3473
3440
  });
3474
3441
 
3475
- // src/diagnostics/returnEffectInGen.ts
3476
- var returnEffectInGen = createDiagnostic({
3477
- name: "returnEffectInGen",
3478
- code: 11,
3479
- severity: "suggestion",
3480
- apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
3442
+ // src/completions/rpcMakeClasses.ts
3443
+ var rpcMakeClasses = createCompletion({
3444
+ name: "rpcMakeClasses",
3445
+ apply: fn("rpcMakeClasses")(function* (sourceFile, position) {
3481
3446
  const ts = yield* service(TypeScriptApi);
3482
- const typeChecker = yield* service(TypeCheckerApi);
3483
- const typeParser = yield* service(TypeParser);
3484
- const nodeToVisit = [];
3485
- const appendNodeToVisit = (node) => {
3486
- nodeToVisit.push(node);
3487
- return void 0;
3488
- };
3489
- ts.forEachChild(sourceFile, appendNodeToVisit);
3490
- while (nodeToVisit.length > 0) {
3491
- const node = nodeToVisit.shift();
3492
- ts.forEachChild(node, appendNodeToVisit);
3493
- if (ts.isReturnStatement(node) && node.expression) {
3494
- if (ts.isYieldExpression(node.expression)) continue;
3495
- const generatorOrRegularFunction = ts.findAncestor(
3496
- node,
3497
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
3498
- );
3499
- if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
3500
- const type = typeChecker.getTypeAtLocation(node.expression);
3501
- const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
3502
- if (isSome2(maybeEffect)) {
3503
- if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
3504
- const effectGenNode = generatorOrRegularFunction.parent;
3505
- yield* pipe(
3506
- typeParser.effectGen(effectGenNode),
3507
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3508
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3509
- map4(() => {
3510
- const fix = node.expression ? [{
3511
- fixName: "returnEffectInGen_fix",
3512
- description: "Add yield* statement",
3513
- apply: gen(function* () {
3514
- const changeTracker = yield* service(ChangeTracker);
3515
- changeTracker.replaceNode(
3516
- sourceFile,
3517
- node.expression,
3518
- ts.factory.createYieldExpression(
3519
- ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3520
- node.expression
3521
- )
3522
- );
3523
- })
3524
- }] : [];
3525
- report({
3526
- node,
3527
- messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>.
3528
- Maybe you wanted to return yield* instead?
3529
- Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect, if so you can safely disable this diagnostic for this line through quickfixes.`,
3530
- fixes: fix
3531
- });
3532
- }),
3533
- ignore
3534
- );
3447
+ const maybeInfos = yield* option(
3448
+ parseDataForExtendsClassCompletion(sourceFile, position)
3449
+ );
3450
+ if (isNone2(maybeInfos)) return [];
3451
+ const { accessedObject, className, replacementSpan } = maybeInfos.value;
3452
+ const rpcName = yield* option(
3453
+ findImportedModuleIdentifierByPackageAndNameOrBarrel(
3454
+ sourceFile,
3455
+ "@effect/rpc",
3456
+ "Rpc"
3457
+ )
3458
+ );
3459
+ const rpcIdentifier = match(rpcName, {
3460
+ onNone: () => "Rpc",
3461
+ onSome: (_) => _.text
3462
+ });
3463
+ if (rpcIdentifier !== accessedObject.text) return [];
3464
+ const name = className.text;
3465
+ return [{
3466
+ name: `make("${name}")`,
3467
+ kind: ts.ScriptElementKind.constElement,
3468
+ insertText: `${rpcIdentifier}.make("${name}", {${"${0}"}}) {}`,
3469
+ replacementSpan,
3470
+ isSnippet: true
3471
+ }];
3472
+ })
3473
+ });
3474
+
3475
+ // src/completions.ts
3476
+ var completions = [
3477
+ effectSchemaSelfInClasses,
3478
+ effectSelfInClasses,
3479
+ contextSelfInClasses,
3480
+ rpcMakeClasses,
3481
+ genFunctionStar,
3482
+ fnFunctionStar,
3483
+ effectDataClasses,
3484
+ effectDiagnosticsComment
3485
+ ];
3486
+
3487
+ // src/completions/middlewareNamespaceImports.ts
3488
+ var importablePackagesMetadataCache = /* @__PURE__ */ new Map();
3489
+ var makeImportablePackagesMetadata = fn("makeImportablePackagesMetadata")(function* (sourceFile) {
3490
+ const ts = yield* service(TypeScriptApi);
3491
+ const program = yield* service(TypeScriptProgram);
3492
+ const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
3493
+ const host = program;
3494
+ const namespaceByFileName = /* @__PURE__ */ new Map();
3495
+ const excludedByFileName = /* @__PURE__ */ new Map();
3496
+ const unbarreledModulePathByFileName = /* @__PURE__ */ new Map();
3497
+ for (const packageName of languageServicePluginOptions.namespaceImportPackages) {
3498
+ const barrelModule = ts.resolveModuleName(packageName, sourceFile.fileName, program.getCompilerOptions(), host);
3499
+ if (barrelModule.resolvedModule) {
3500
+ const barrelPath = barrelModule.resolvedModule.resolvedFileName;
3501
+ const barrelSource = program.getSourceFile(barrelPath) || ts.createSourceFile(barrelPath, host.readFile(barrelPath) || "", sourceFile.languageVersion, true);
3502
+ if (barrelSource) {
3503
+ for (const statement of barrelSource.statements) {
3504
+ if (ts.isExportDeclaration(statement)) {
3505
+ const exportClause = statement.exportClause;
3506
+ const moduleSpecifier = statement.moduleSpecifier;
3507
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
3508
+ const unbarreledModulePathResolved = ts.resolveModuleName(
3509
+ moduleSpecifier.text,
3510
+ barrelSource.fileName,
3511
+ program.getCompilerOptions(),
3512
+ host
3513
+ );
3514
+ if (unbarreledModulePathResolved.resolvedModule) {
3515
+ const unbarreledModulePath = unbarreledModulePathResolved.resolvedModule.resolvedFileName;
3516
+ if (exportClause && ts.isNamespaceExport(exportClause) && ts.isIdentifier(exportClause.name)) {
3517
+ namespaceByFileName.set(unbarreledModulePath, exportClause.name.text);
3518
+ const existingUnbarreledModulePath = unbarreledModulePathByFileName.get(barrelSource.fileName) || [];
3519
+ existingUnbarreledModulePath.push([exportClause.name.text, unbarreledModulePath]);
3520
+ unbarreledModulePathByFileName.set(barrelSource.fileName, existingUnbarreledModulePath);
3521
+ }
3522
+ if (exportClause && ts.isNamedExports(exportClause)) {
3523
+ for (const element of exportClause.elements) {
3524
+ if (!ts.isIdentifier(element.name)) continue;
3525
+ const methodName = element.name.text;
3526
+ const excludedMethods = excludedByFileName.get(methodName) || [];
3527
+ excludedMethods.push(unbarreledModulePath);
3528
+ excludedByFileName.set(methodName, excludedMethods);
3529
+ }
3530
+ }
3531
+ }
3532
+ }
3535
3533
  }
3536
3534
  }
3537
3535
  }
3538
3536
  }
3539
- })
3537
+ }
3538
+ return {
3539
+ getImportNamespaceByFileName: (fileName) => namespaceByFileName.get(fileName),
3540
+ isExcludedFromNamespaceImport: (fileName, exportName) => (excludedByFileName.get(exportName) || []).includes(fileName),
3541
+ getUnbarreledModulePath: (fileName, exportName) => unbarreledModulePathByFileName.get(fileName)?.find(([name]) => name === exportName)?.[1]
3542
+ };
3540
3543
  });
3541
-
3542
- // src/diagnostics/unnecessaryEffectGen.ts
3543
- var unnecessaryEffectGen = createDiagnostic({
3544
- name: "unnecessaryEffectGen",
3545
- code: 5,
3546
- severity: "suggestion",
3547
- apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
3548
- const ts = yield* service(TypeScriptApi);
3549
- const typeParser = yield* service(TypeParser);
3550
- const nodeToVisit = [];
3551
- const appendNodeToVisit = (node) => {
3552
- nodeToVisit.push(node);
3553
- return void 0;
3554
- };
3555
- ts.forEachChild(sourceFile, appendNodeToVisit);
3556
- while (nodeToVisit.length > 0) {
3557
- const node = nodeToVisit.shift();
3558
- ts.forEachChild(node, appendNodeToVisit);
3559
- if (ts.isCallExpression(node)) {
3560
- yield* pipe(
3561
- typeParser.unnecessaryEffectGen(node),
3562
- map4(
3563
- ({ replacementNode }) => report({
3564
- node,
3565
- messageText: `This Effect.gen contains a single return statement.`,
3566
- fixes: [{
3567
- fixName: "unnecessaryEffectGen_fix",
3568
- description: "Remove the Effect.gen, and keep the body",
3569
- apply: gen(function* () {
3570
- const textChanges = yield* service(
3571
- ChangeTracker
3572
- );
3573
- textChanges.replaceNode(sourceFile, node, yield* replacementNode);
3574
- })
3575
- }]
3576
- })
3577
- ),
3578
- ignore
3579
- );
3580
- }
3544
+ var appendEffectCompletionEntryData = fn("collectNamespaceImports")(
3545
+ function* (sourceFile, applicableCompletions) {
3546
+ const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
3547
+ if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletions;
3548
+ const packagesMetadata = importablePackagesMetadataCache.get(sourceFile.fileName) || (yield* makeImportablePackagesMetadata(sourceFile));
3549
+ importablePackagesMetadataCache.set(sourceFile.fileName, packagesMetadata);
3550
+ if (applicableCompletions) {
3551
+ return {
3552
+ ...applicableCompletions,
3553
+ entries: applicableCompletions.entries.map((entry) => {
3554
+ if (entry.data && entry.data.fileName && !entry.insertText && !entry.filterText && entry.data.exportName && entry.data.moduleSpecifier) {
3555
+ const isExcluded = packagesMetadata.isExcludedFromNamespaceImport(
3556
+ entry.data.fileName,
3557
+ entry.data.exportName
3558
+ );
3559
+ if (isExcluded) return entry;
3560
+ const unbarreledModulePath = packagesMetadata.getUnbarreledModulePath(
3561
+ entry.data.fileName,
3562
+ entry.data.exportName
3563
+ );
3564
+ const namespaceName = packagesMetadata.getImportNamespaceByFileName(
3565
+ unbarreledModulePath || entry.data.fileName
3566
+ );
3567
+ if (namespaceName) {
3568
+ return {
3569
+ ...entry,
3570
+ // insertText: unbarreledModulePath ? namespaceName : namespaceName + "." + entry.name,
3571
+ // filterText: entry.name,
3572
+ data: {
3573
+ ...entry.data,
3574
+ effectNamespaceName: namespaceName,
3575
+ effectUnbarreledModulePath: unbarreledModulePath || "",
3576
+ effectReplaceSpan: entry.replacementSpan || applicableCompletions.optionalReplacementSpan
3577
+ }
3578
+ };
3579
+ }
3580
+ }
3581
+ return entry;
3582
+ })
3583
+ };
3581
3584
  }
3582
- })
3583
- });
3584
-
3585
- // src/diagnostics/unnecessaryPipe.ts
3586
- var unnecessaryPipe = createDiagnostic({
3587
- name: "unnecessaryPipe",
3588
- code: 9,
3589
- severity: "suggestion",
3590
- apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
3585
+ return applicableCompletions;
3586
+ }
3587
+ );
3588
+ var postprocessCompletionEntryDetails = fn("postprocessCompletionEntryDetails")(
3589
+ function* (sourceFile, data, applicableCompletionEntryDetails, formatOptions, preferences, languageServiceHost) {
3590
+ const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
3591
+ if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletionEntryDetails;
3591
3592
  const ts = yield* service(TypeScriptApi);
3592
- const typeParser = yield* service(TypeParser);
3593
- const nodeToVisit = [];
3594
- const appendNodeToVisit = (node) => {
3595
- nodeToVisit.push(node);
3596
- return void 0;
3597
- };
3598
- ts.forEachChild(sourceFile, appendNodeToVisit);
3599
- while (nodeToVisit.length > 0) {
3600
- const node = nodeToVisit.shift();
3601
- ts.forEachChild(node, appendNodeToVisit);
3602
- if (ts.isCallExpression(node)) {
3603
- yield* pipe(
3604
- typeParser.pipeCall(node),
3605
- map4(({ args, subject }) => {
3606
- if (args.length === 0) {
3607
- report({
3608
- node,
3609
- messageText: `This pipe call contains no arguments.`,
3610
- fixes: [{
3611
- fixName: "unnecessaryPipe_fix",
3612
- description: "Remove the pipe call",
3613
- apply: gen(function* () {
3614
- const textChanges = yield* service(
3615
- ChangeTracker
3616
- );
3617
- textChanges.replaceNode(sourceFile, node, subject);
3618
- })
3619
- }]
3620
- });
3593
+ const program = yield* service(TypeScriptProgram);
3594
+ const getModuleSpecifier = makeGetModuleSpecifier(ts);
3595
+ if (!getModuleSpecifier) return applicableCompletionEntryDetails;
3596
+ if (!applicableCompletionEntryDetails) return applicableCompletionEntryDetails;
3597
+ if (!data) return applicableCompletionEntryDetails;
3598
+ if (!("effectNamespaceName" in data && "effectUnbarreledModulePath" in data && "effectReplaceSpan" in data)) {
3599
+ return applicableCompletionEntryDetails;
3600
+ }
3601
+ const effectReplaceSpan = data.effectReplaceSpan;
3602
+ const codeActions = applicableCompletionEntryDetails.codeActions;
3603
+ if (codeActions && codeActions.length === 1) {
3604
+ const action = codeActions[0];
3605
+ if (action.changes.length === 1) {
3606
+ const fileTextChanges = action.changes[0];
3607
+ if (fileTextChanges.fileName === sourceFile.fileName && fileTextChanges.textChanges.length === 1) {
3608
+ const change = fileTextChanges.textChanges[0];
3609
+ let hasImportActions = false;
3610
+ if (change.newText.trim().toLowerCase().startsWith("import") && change.newText.indexOf(data.exportName) > -1) {
3611
+ hasImportActions = true;
3612
+ }
3613
+ if (!hasImportActions && change.newText.indexOf(data.exportName) > -1) {
3614
+ const ancestorNodes = yield* getAncestorNodesInRange(sourceFile, {
3615
+ pos: change.span.start,
3616
+ end: change.span.start
3617
+ });
3618
+ const importNodes = ancestorNodes.filter((node) => ts.isImportDeclaration(node));
3619
+ hasImportActions = importNodes.length > 0;
3620
+ }
3621
+ if (!hasImportActions) return applicableCompletionEntryDetails;
3622
+ const formatContext = ts.formatting.getFormatContext(
3623
+ formatOptions || {},
3624
+ languageServiceHost
3625
+ );
3626
+ const changes = ts.textChanges.ChangeTracker.with(
3627
+ {
3628
+ formatContext,
3629
+ host: languageServiceHost,
3630
+ preferences: preferences || {}
3631
+ },
3632
+ (changeTracker) => {
3633
+ const isBarrelRedirect = String(data.effectUnbarreledModulePath).length > 0;
3634
+ const moduleSpecifier = isBarrelRedirect ? getModuleSpecifier(
3635
+ program.getCompilerOptions(),
3636
+ sourceFile,
3637
+ sourceFile.fileName,
3638
+ String(data.effectUnbarreledModulePath),
3639
+ program
3640
+ ) : String(data.moduleSpecifier);
3641
+ ts.insertImports(
3642
+ changeTracker,
3643
+ sourceFile,
3644
+ ts.factory.createImportDeclaration(
3645
+ void 0,
3646
+ ts.factory.createImportClause(
3647
+ false,
3648
+ void 0,
3649
+ ts.factory.createNamespaceImport(ts.factory.createIdentifier(String(data.effectNamespaceName)))
3650
+ ),
3651
+ ts.factory.createStringLiteral(moduleSpecifier)
3652
+ ),
3653
+ true,
3654
+ preferences || {}
3655
+ );
3656
+ if (!isBarrelRedirect) {
3657
+ changeTracker.insertText(
3658
+ sourceFile,
3659
+ effectReplaceSpan.start,
3660
+ String(data.effectNamespaceName) + "."
3661
+ );
3662
+ }
3621
3663
  }
3622
- }),
3623
- ignore
3624
- );
3664
+ );
3665
+ return {
3666
+ ...applicableCompletionEntryDetails,
3667
+ codeActions: [
3668
+ {
3669
+ description: "Import * as " + data.effectNamespaceName + " from " + data.effectUnbarreledModulePath,
3670
+ changes
3671
+ }
3672
+ ]
3673
+ };
3674
+ }
3625
3675
  }
3626
3676
  }
3627
- })
3628
- });
3629
-
3630
- // src/diagnostics.ts
3631
- var diagnostics = [
3632
- duplicatePackage,
3633
- missingEffectContext,
3634
- missingEffectError,
3635
- floatingEffect,
3636
- missingStarInYieldEffectGen,
3637
- unnecessaryEffectGen,
3638
- missingReturnYieldStar,
3639
- leakingRequirements,
3640
- unnecessaryPipe,
3641
- genericEffectServices,
3642
- returnEffectInGen,
3643
- importFromBarrel
3644
- ];
3677
+ return applicableCompletionEntryDetails;
3678
+ }
3679
+ );
3645
3680
 
3646
3681
  // src/goto/effectRpcDefinition.ts
3647
3682
  function effectRpcDefinition(applicableGotoDefinition, sourceFile, position) {