@effect/language-service 0.22.0 → 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.
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;
@@ -832,29 +833,11 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
832
833
  });
833
834
 
834
835
  // src/core/Nano.ts
835
- var NanoInternalSuccessProto = {
836
- _tag: "Right"
837
- };
838
836
  function makeInternalSuccess(value) {
839
- const result = Object.create(NanoInternalSuccessProto);
840
- result.value = value;
841
- return result;
842
- }
843
- var NanoInternalFailureProto = {
844
- _tag: "Left"
845
- };
846
- function makeInternalFailure(value) {
847
- const result = Object.create(NanoInternalFailureProto);
848
- result.value = value;
849
- return result;
837
+ return { _tag: "Right", value };
850
838
  }
851
- var NanoInternalDefectProto = {
852
- _tag: "Defect"
853
- };
854
839
  function makeInternalDefect(value) {
855
- const result = Object.create(NanoInternalDefectProto);
856
- result.value = value;
857
- return result;
840
+ return { _tag: "Defect", value };
858
841
  }
859
842
  var NanoDefectException = class {
860
843
  constructor(message) {
@@ -869,17 +852,14 @@ var NanoTag = class {
869
852
  };
870
853
  var Tag = (identifier) => new NanoTag(identifier);
871
854
  var contextEmpty = { value: {} };
872
- var Proto = {
873
- run: () => {
874
- },
875
- [Symbol.iterator]() {
876
- return new SingleShotGen(new YieldWrap(this));
877
- }
878
- };
879
855
  function make3(run2) {
880
- const result = Object.create(Proto);
881
- result.run = run2;
882
- return result;
856
+ const nano = {
857
+ run: run2,
858
+ [Symbol.iterator]() {
859
+ return new SingleShotGen(new YieldWrap(this));
860
+ }
861
+ };
862
+ return nano;
883
863
  }
884
864
  var unsafeRun = (fa) => {
885
865
  const program = provideService(internalNanoCache, {})(fa);
@@ -900,9 +880,33 @@ var run = (fa) => {
900
880
  return left2(new NanoDefectException(e));
901
881
  }
902
882
  };
903
- var succeed = (value) => make3(() => makeInternalSuccess(value));
904
- var fail = (value) => make3(() => makeInternalFailure(value));
905
- var sync = (value) => make3(() => makeInternalSuccess(value()));
883
+ var succeed = (value) => {
884
+ const nano = {
885
+ run: () => ({ _tag: "Right", value }),
886
+ [Symbol.iterator]() {
887
+ return new SingleShotGen(new YieldWrap(this));
888
+ }
889
+ };
890
+ return nano;
891
+ };
892
+ var fail = (value) => {
893
+ const nano = {
894
+ run: () => ({ _tag: "Left", value }),
895
+ [Symbol.iterator]() {
896
+ return new SingleShotGen(new YieldWrap(this));
897
+ }
898
+ };
899
+ return nano;
900
+ };
901
+ var sync = (value) => {
902
+ const nano = {
903
+ run: () => ({ _tag: "Right", value: value() }),
904
+ [Symbol.iterator]() {
905
+ return new SingleShotGen(new YieldWrap(this));
906
+ }
907
+ };
908
+ return nano;
909
+ };
906
910
  var flatMap2 = dual(2, (fa, f) => make3((ctx) => {
907
911
  const result = fa.run(ctx);
908
912
  if (result._tag !== "Right") return result;
@@ -995,8 +999,9 @@ function cachedBy(fa, key, lookupKey) {
995
999
  cacheObj[key] = cache;
996
1000
  }
997
1001
  const lookup = lookupKey(...args);
998
- if (cache.has(lookup)) {
999
- return cache.get(lookup);
1002
+ const cached2 = cache.get(lookup);
1003
+ if (cached2 !== void 0) {
1004
+ return cached2;
1000
1005
  }
1001
1006
  const result = fa(...args).run(ctx);
1002
1007
  cache.set(lookup, result);
@@ -1728,122 +1733,347 @@ var effectDataClasses = createCompletion({
1728
1733
  })
1729
1734
  });
1730
1735
 
1731
- // src/completions/effectSchemaSelfInClasses.ts
1732
- var effectSchemaSelfInClasses = createCompletion({
1733
- name: "effectSchemaSelfInClasses",
1734
- apply: fn("effectSchemaSelfInClasses")(function* (sourceFile, position) {
1735
- const ts = yield* service(TypeScriptApi);
1736
- const maybeInfos = yield* option(
1737
- parseDataForExtendsClassCompletion(sourceFile, position)
1738
- );
1739
- if (isNone2(maybeInfos)) return [];
1740
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
1741
- const effectSchemaName = yield* option(
1742
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
1743
- sourceFile,
1744
- "effect",
1745
- "Schema"
1746
- )
1747
- );
1748
- const schemaIdentifier = match(effectSchemaName, {
1749
- onNone: () => "Schema",
1750
- onSome: (_) => _.text
1751
- });
1752
- if (schemaIdentifier !== accessedObject.text) return [];
1753
- const name = className.text;
1754
- return [{
1755
- name: `Class<${name}>`,
1756
- kind: ts.ScriptElementKind.constElement,
1757
- insertText: `${schemaIdentifier}.Class<${name}>("${name}")({${"${0}"}}){}`,
1758
- replacementSpan,
1759
- isSnippet: true
1760
- }, {
1761
- name: `TaggedError<${name}>`,
1762
- kind: ts.ScriptElementKind.constElement,
1763
- insertText: `${schemaIdentifier}.TaggedError<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1764
- replacementSpan,
1765
- isSnippet: true
1766
- }, {
1767
- name: `TaggedClass<${name}>`,
1768
- kind: ts.ScriptElementKind.constElement,
1769
- insertText: `${schemaIdentifier}.TaggedClass<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1770
- replacementSpan,
1771
- isSnippet: true
1772
- }, {
1773
- name: `TaggedRequest<${name}>`,
1774
- kind: ts.ScriptElementKind.constElement,
1775
- insertText: `${schemaIdentifier}.TaggedRequest<${name}>("${name}")("${name}", {${"${0}"}}){}`,
1776
- replacementSpan,
1777
- isSnippet: true
1778
- }];
1779
- })
1780
- });
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]))}.
1781
1775
 
1782
- // src/completions/effectSelfInClasses.ts
1783
- var effectSelfInClasses = createCompletion({
1784
- name: "effectSelfInClasses",
1785
- apply: fn("effectSelfInClasses")(function* (sourceFile, position) {
1786
- const ts = yield* service(TypeScriptApi);
1787
- const maybeInfos = yield* option(
1788
- parseDataForExtendsClassCompletion(sourceFile, position)
1789
- );
1790
- if (isNone2(maybeInfos)) return [];
1791
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
1792
- const effectName = yield* option(
1793
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
1794
- sourceFile,
1795
- "effect",
1796
- "Effect"
1797
- )
1798
- );
1799
- const effectIdentifier = match(effectName, {
1800
- onNone: () => "Effect",
1801
- onSome: (_) => _.text
1802
- });
1803
- if (effectIdentifier !== accessedObject.text) return [];
1804
- const name = className.text;
1805
- return [{
1806
- name: `Service<${name}>`,
1807
- kind: ts.ScriptElementKind.constElement,
1808
- insertText: `${effectIdentifier}.Service<${name}>()("${name}", {${"${0}"}}){}`,
1809
- replacementSpan,
1810
- isSnippet: true
1811
- }];
1776
+ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
1777
+ fixes: []
1778
+ });
1779
+ }
1780
+ }
1812
1781
  })
1813
1782
  });
1814
1783
 
1815
- // src/core/TypeParser.ts
1816
- var TypeParser = Tag("@effect/language-service/TypeParser");
1817
- var TypeParserIssue = class _TypeParserIssue {
1818
- _tag = "@effect/language-service/TypeParserIssue";
1819
- static issue = fail(new _TypeParserIssue());
1820
- };
1821
- function make4(ts, typeChecker) {
1822
- function typeParserIssue(_message, _type, _node) {
1823
- return TypeParserIssue.issue;
1824
- }
1825
- function covariantTypeArgument(type) {
1826
- const signatures = type.getCallSignatures();
1827
- if (signatures.length !== 1) {
1828
- 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
+ }
1829
1821
  }
1830
- return succeed(signatures[0].getReturnType());
1822
+ return result;
1831
1823
  }
1832
- function contravariantTypeArgument(type) {
1833
- const signatures = type.getCallSignatures();
1834
- if (signatures.length !== 1) {
1835
- 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;
1836
1839
  }
1837
- return succeed(signatures[0].getTypeParameterAtPosition(0));
1840
+ current = current.parent;
1838
1841
  }
1839
- function invariantTypeArgument(type) {
1840
- const signatures = type.getCallSignatures();
1841
- if (signatures.length !== 1) {
1842
- 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
+ );
1843
1870
  }
1844
- return succeed(signatures[0].getReturnType());
1845
1871
  }
1846
- const pipeableType = cachedBy(
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);
1880
+ }
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(
1847
2077
  function(type, atLocation) {
1848
2078
  const pipeSymbol = typeChecker.getPropertyOfType(type, "pipe");
1849
2079
  if (!pipeSymbol) {
@@ -2297,641 +2527,14 @@ function make4(ts, typeChecker) {
2297
2527
  };
2298
2528
  }
2299
2529
 
2300
- // src/completions/fnFunctionStar.ts
2301
- var fnFunctionStar = createCompletion({
2302
- name: "fnFunctionStar",
2303
- 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) {
2304
2536
  const ts = yield* service(TypeScriptApi);
2305
- const typeParser = yield* service(TypeParser);
2306
- const maybeInfos = yield* option(
2307
- parseAccessedExpressionForCompletion(sourceFile, position)
2308
- );
2309
- if (isNone2(maybeInfos)) return [];
2310
- const { accessedObject } = maybeInfos.value;
2311
- const isEffectModule = yield* option(typeParser.importedEffectModule(accessedObject));
2312
- if (isNone2(isEffectModule)) return [];
2313
- const span = ts.createTextSpan(
2314
- accessedObject.end + 1,
2315
- Math.max(0, position - accessedObject.end - 1)
2316
- );
2317
- const maybeFnName = pipe(
2318
- yield* getAncestorNodesInRange(sourceFile, toTextRange(accessedObject.pos)),
2319
- filter(ts.isVariableDeclaration),
2320
- map3((_) => _.name && ts.isIdentifier(_.name) ? _.name.text : ""),
2321
- filter((_) => _.length > 0),
2322
- head,
2323
- map2((name) => [
2324
- {
2325
- name: `fn("${name}")`,
2326
- kind: ts.ScriptElementKind.constElement,
2327
- insertText: `fn("${name}")(function*(${"${1}"}){${"${0}"}})`,
2328
- replacementSpan: span,
2329
- isSnippet: true
2330
- }
2331
- ]),
2332
- getOrElse2(() => [])
2333
- );
2334
- return maybeFnName.concat([{
2335
- name: `fn(function*(){})`,
2336
- kind: ts.ScriptElementKind.constElement,
2337
- insertText: `fn(function*(${"${1}"}){${"${0}"}})`,
2338
- replacementSpan: span,
2339
- isSnippet: true
2340
- }, {
2341
- name: `fnUntraced(function*(){})`,
2342
- kind: ts.ScriptElementKind.constElement,
2343
- insertText: `fnUntraced(function*(${"${1}"}){${"${0}"}})`,
2344
- replacementSpan: span,
2345
- isSnippet: true
2346
- }]);
2347
- })
2348
- });
2349
-
2350
- // src/core/TypeCheckerApi.ts
2351
- var TypeCheckerApi = Tag("TypeChecker");
2352
- var TypeCheckerApiCache = Tag("TypeCheckerApiCache");
2353
- function makeTypeCheckerApiCache() {
2354
- return {
2355
- expectedAndRealType: /* @__PURE__ */ new WeakMap()
2356
- };
2357
- }
2358
- var deterministicTypeOrder = gen(function* () {
2359
- const typeChecker = yield* service(TypeCheckerApi);
2360
- return make2((a, b) => {
2361
- const aName = typeChecker.typeToString(a);
2362
- const bName = typeChecker.typeToString(b);
2363
- if (aName < bName) return -1;
2364
- if (aName > bName) return 1;
2365
- return 0;
2366
- });
2367
- });
2368
- var getMissingTypeEntriesInTargetType = fn(
2369
- "TypeCheckerApi.getMissingTypeEntriesInTargetType"
2370
- )(
2371
- function* (realType, expectedType) {
2372
- if (realType === expectedType) return [];
2373
- const typeChecker = yield* service(TypeCheckerApi);
2374
- const result = [];
2375
- let toTest = [realType];
2376
- while (toTest.length > 0) {
2377
- const type = toTest.pop();
2378
- if (!type) return result;
2379
- if (type.isUnion()) {
2380
- toTest = toTest.concat(type.types);
2381
- } else {
2382
- const assignable = typeChecker.isTypeAssignableTo(type, expectedType);
2383
- if (!assignable) {
2384
- result.push(type);
2385
- }
2386
- }
2387
- }
2388
- return result;
2389
- }
2390
- );
2391
- var CannotFindAncestorConvertibleDeclarationError = class {
2392
- constructor(node) {
2393
- this.node = node;
2394
- }
2395
- _tag = "@effect/language-service/CannotFindAncestorConvertibleDeclarationError";
2396
- };
2397
- var getAncestorConvertibleDeclaration = fn(
2398
- "TypeCheckerApi.getAncestorConvertibleDeclaration"
2399
- )(function* (node) {
2400
- const ts = yield* service(TypeScriptApi);
2401
- let current = node;
2402
- while (current) {
2403
- if (ts.isFunctionDeclaration(current) || ts.isFunctionExpression(current) || ts.isArrowFunction(current) || ts.isMethodDeclaration(current)) {
2404
- return current;
2405
- }
2406
- current = current.parent;
2407
- }
2408
- return yield* fail(new CannotFindAncestorConvertibleDeclarationError(node));
2409
- });
2410
- var CannotInferReturnTypeFromEmptyBody = class {
2411
- constructor(declaration) {
2412
- this.declaration = declaration;
2413
- }
2414
- _tag = "@effect/language-service/CannotInferReturnTypeFromEmptyBody";
2415
- };
2416
- var CannotInferReturnType = class {
2417
- constructor(declaration) {
2418
- this.declaration = declaration;
2419
- }
2420
- _tag = "@effect/language-service/CannotInferReturnType";
2421
- };
2422
- var getInferredReturnType = fn("TypeCheckerApi.getInferredReturnType")(function* (declaration) {
2423
- const typeChecker = yield* service(TypeCheckerApi);
2424
- if (!declaration.body) {
2425
- return yield* fail(
2426
- new CannotInferReturnTypeFromEmptyBody(declaration)
2427
- );
2428
- }
2429
- let returnType;
2430
- if (typeChecker.isImplementationOfOverload(declaration)) {
2431
- const signatures = typeChecker.getTypeAtLocation(declaration).getCallSignatures();
2432
- if (signatures.length > 1) {
2433
- returnType = typeChecker.getUnionType(
2434
- signatures.map((s) => s.getReturnType()).filter((_) => !!_)
2435
- );
2436
- }
2437
- }
2438
- if (!returnType) {
2439
- const signature = typeChecker.getSignatureFromDeclaration(declaration);
2440
- if (signature) {
2441
- const typePredicate = typeChecker.getTypePredicateOfSignature(signature);
2442
- if (typePredicate && typePredicate.type) {
2443
- return typePredicate.type;
2444
- } else {
2445
- returnType = typeChecker.getReturnTypeOfSignature(signature);
2446
- }
2447
- }
2448
- }
2449
- if (!returnType) {
2450
- return yield* fail(
2451
- new CannotInferReturnType(declaration)
2452
- );
2453
- }
2454
- return returnType;
2455
- });
2456
- var expectedAndRealType = fn("TypeCheckerApi.expectedAndRealType")(function* (sourceFile) {
2457
- const cache = yield* service(TypeCheckerApiCache);
2458
- const resultCached = cache.expectedAndRealType.get(sourceFile);
2459
- if (resultCached) return resultCached;
2460
- const typeChecker = yield* service(TypeCheckerApi);
2461
- const ts = yield* service(TypeScriptApi);
2462
- const result = [];
2463
- const nodeToVisit = [sourceFile];
2464
- const appendNodeToVisit = (node) => {
2465
- nodeToVisit.push(node);
2466
- return void 0;
2467
- };
2468
- while (nodeToVisit.length > 0) {
2469
- const node = nodeToVisit.shift();
2470
- if (ts.isVariableDeclaration(node) && node.initializer) {
2471
- const expectedType = typeChecker.getTypeAtLocation(node.name);
2472
- const realType = typeChecker.getTypeAtLocation(node.initializer);
2473
- result.push([node.name, expectedType, node.initializer, realType]);
2474
- appendNodeToVisit(node.initializer);
2475
- continue;
2476
- } else if (ts.isCallExpression(node)) {
2477
- const resolvedSignature = typeChecker.getResolvedSignature(node);
2478
- if (resolvedSignature) {
2479
- resolvedSignature.getParameters().map((parameter, index) => {
2480
- const expectedType = typeChecker.getTypeOfSymbolAtLocation(parameter, node);
2481
- const realType = typeChecker.getTypeAtLocation(node.arguments[index]);
2482
- result.push([
2483
- node.arguments[index],
2484
- expectedType,
2485
- node.arguments[index],
2486
- realType
2487
- ]);
2488
- });
2489
- }
2490
- ts.forEachChild(node, appendNodeToVisit);
2491
- continue;
2492
- } else if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
2493
- const parent = node.parent;
2494
- if (ts.isObjectLiteralElement(parent)) {
2495
- if (ts.isObjectLiteralExpression(parent.parent) && parent.name === node) {
2496
- const type = typeChecker.getContextualType(parent.parent);
2497
- if (type) {
2498
- const symbol3 = typeChecker.getPropertyOfType(type, node.text);
2499
- if (symbol3) {
2500
- const expectedType = typeChecker.getTypeOfSymbolAtLocation(symbol3, node);
2501
- const realType = typeChecker.getTypeAtLocation(node);
2502
- result.push([node, expectedType, node, realType]);
2503
- }
2504
- }
2505
- }
2506
- }
2507
- ts.forEachChild(node, appendNodeToVisit);
2508
- continue;
2509
- } else if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
2510
- const expectedType = typeChecker.getTypeAtLocation(node.left);
2511
- const realType = typeChecker.getTypeAtLocation(node.right);
2512
- result.push([node.left, expectedType, node.right, realType]);
2513
- appendNodeToVisit(node.right);
2514
- continue;
2515
- } else if (ts.isReturnStatement(node) && node.expression) {
2516
- const parentDeclaration = yield* option(getAncestorConvertibleDeclaration(node));
2517
- if (isSome2(parentDeclaration)) {
2518
- const expectedType = yield* option(getInferredReturnType(parentDeclaration.value));
2519
- const realType = typeChecker.getTypeAtLocation(node.expression);
2520
- if (isSome2(expectedType)) {
2521
- result.push([node, expectedType.value, node, realType]);
2522
- }
2523
- }
2524
- ts.forEachChild(node, appendNodeToVisit);
2525
- continue;
2526
- } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length === 0 && ts.isExpression(node.body)) {
2527
- const body = node.body;
2528
- const expectedType = typeChecker.getContextualType(body);
2529
- const realType = typeChecker.getTypeAtLocation(body);
2530
- if (expectedType) {
2531
- result.push([body, expectedType, body, realType]);
2532
- }
2533
- ts.forEachChild(body, appendNodeToVisit);
2534
- continue;
2535
- } else if (ts.isArrowFunction(node) && (node.typeParameters || []).length > 0 && ts.isExpression(node.body)) {
2536
- const body = node.body;
2537
- const expectedType = yield* option(getInferredReturnType(node));
2538
- const realType = typeChecker.getTypeAtLocation(body);
2539
- if (isSome2(expectedType)) {
2540
- result.push([body, expectedType.value, body, realType]);
2541
- }
2542
- ts.forEachChild(body, appendNodeToVisit);
2543
- continue;
2544
- } else if (ts.isSatisfiesExpression(node)) {
2545
- const expectedType = typeChecker.getTypeAtLocation(node.type);
2546
- const realType = typeChecker.getTypeAtLocation(node.expression);
2547
- result.push([node.expression, expectedType, node.expression, realType]);
2548
- appendNodeToVisit(node.expression);
2549
- continue;
2550
- }
2551
- ts.forEachChild(node, appendNodeToVisit);
2552
- }
2553
- cache.expectedAndRealType.set(sourceFile, result);
2554
- return result;
2555
- });
2556
- var appendToUniqueTypesMap = fn(
2557
- "TypeCheckerApi.appendToUniqueTypesMap"
2558
- )(
2559
- function* (memory, initialType, excludeNever) {
2560
- const ts = yield* service(TypeScriptApi);
2561
- const typeChecker = yield* service(TypeCheckerApi);
2562
- const newIndexes = /* @__PURE__ */ new Set();
2563
- const knownIndexes = /* @__PURE__ */ new Set();
2564
- let toTest = [initialType];
2565
- while (toTest.length > 0) {
2566
- const type = toTest.pop();
2567
- if (!type) break;
2568
- if (excludeNever && type.flags & ts.TypeFlags.Never) {
2569
- continue;
2570
- }
2571
- if (type.isUnion()) {
2572
- toTest = toTest.concat(type.types);
2573
- } else {
2574
- const foundMatch = [];
2575
- for (const [typeId, knownType] of memory.entries()) {
2576
- const areSame = typeChecker.isTypeAssignableTo(knownType, type) && typeChecker.isTypeAssignableTo(type, knownType);
2577
- if (areSame) {
2578
- foundMatch.push(typeId);
2579
- break;
2580
- }
2581
- }
2582
- if (foundMatch.length === 0) {
2583
- const newId = "t" + (memory.size + 1);
2584
- memory.set(newId, type);
2585
- newIndexes.add(newId);
2586
- } else {
2587
- knownIndexes.add(foundMatch[0]);
2588
- }
2589
- }
2590
- }
2591
- return {
2592
- newIndexes,
2593
- knownIndexes,
2594
- allIndexes: pipe(
2595
- fromIterable(newIndexes),
2596
- appendAll(fromIterable(knownIndexes))
2597
- )
2598
- };
2599
- }
2600
- );
2601
- function makeResolveExternalModuleName(typeChecker) {
2602
- if (!(hasProperty(typeChecker, "resolveExternalModuleName") && isFunction(typeChecker.resolveExternalModuleName))) {
2603
- return;
2604
- }
2605
- const _internal = typeChecker.resolveExternalModuleName;
2606
- return (moduleSpecifier) => {
2607
- return _internal(moduleSpecifier);
2608
- };
2609
- }
2610
-
2611
- // src/completions/genFunctionStar.ts
2612
- var genFunctionStar = createCompletion({
2613
- name: "genFunctionStar",
2614
- apply: fn("genFunctionStar")(function* (sourceFile, position) {
2615
- const ts = yield* service(TypeScriptApi);
2616
- const typeChecker = yield* service(TypeCheckerApi);
2617
- const maybeInfos = yield* option(
2618
- parseAccessedExpressionForCompletion(sourceFile, position)
2619
- );
2620
- if (isNone2(maybeInfos)) return [];
2621
- const { accessedObject } = maybeInfos.value;
2622
- const type = typeChecker.getTypeAtLocation(accessedObject);
2623
- const genMemberSymbol = type.getProperty("gen");
2624
- if (!genMemberSymbol) return [];
2625
- const genType = typeChecker.getTypeOfSymbolAtLocation(genMemberSymbol, accessedObject);
2626
- if (genType.getCallSignatures().length === 0) return [];
2627
- const span = ts.createTextSpan(
2628
- accessedObject.end + 1,
2629
- Math.max(0, position - accessedObject.end - 1)
2630
- );
2631
- return [{
2632
- name: `gen(function*(){})`,
2633
- kind: ts.ScriptElementKind.constElement,
2634
- insertText: `gen(function*(){${"${0}"}})`,
2635
- replacementSpan: span,
2636
- isSnippet: true
2637
- }];
2638
- })
2639
- });
2640
-
2641
- // src/completions/rpcMakeClasses.ts
2642
- var rpcMakeClasses = createCompletion({
2643
- name: "rpcMakeClasses",
2644
- apply: fn("rpcMakeClasses")(function* (sourceFile, position) {
2645
- const ts = yield* service(TypeScriptApi);
2646
- const maybeInfos = yield* option(
2647
- parseDataForExtendsClassCompletion(sourceFile, position)
2648
- );
2649
- if (isNone2(maybeInfos)) return [];
2650
- const { accessedObject, className, replacementSpan } = maybeInfos.value;
2651
- const rpcName = yield* option(
2652
- findImportedModuleIdentifierByPackageAndNameOrBarrel(
2653
- sourceFile,
2654
- "@effect/rpc",
2655
- "Rpc"
2656
- )
2657
- );
2658
- const rpcIdentifier = match(rpcName, {
2659
- onNone: () => "Rpc",
2660
- onSome: (_) => _.text
2661
- });
2662
- if (rpcIdentifier !== accessedObject.text) return [];
2663
- const name = className.text;
2664
- return [{
2665
- name: `make("${name}")`,
2666
- kind: ts.ScriptElementKind.constElement,
2667
- insertText: `${rpcIdentifier}.make("${name}", {${"${0}"}}) {}`,
2668
- replacementSpan,
2669
- isSnippet: true
2670
- }];
2671
- })
2672
- });
2673
-
2674
- // src/completions.ts
2675
- var completions = [
2676
- effectSchemaSelfInClasses,
2677
- effectSelfInClasses,
2678
- contextSelfInClasses,
2679
- rpcMakeClasses,
2680
- genFunctionStar,
2681
- fnFunctionStar,
2682
- effectDataClasses
2683
- ];
2684
-
2685
- // src/completions/middlewareNamespaceImports.ts
2686
- var importablePackagesMetadataCache = /* @__PURE__ */ new Map();
2687
- var makeImportablePackagesMetadata = fn("makeImportablePackagesMetadata")(function* (sourceFile) {
2688
- const ts = yield* service(TypeScriptApi);
2689
- const program = yield* service(TypeScriptProgram);
2690
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2691
- const host = program;
2692
- const namespaceByFileName = /* @__PURE__ */ new Map();
2693
- const excludedByFileName = /* @__PURE__ */ new Map();
2694
- const unbarreledModulePathByFileName = /* @__PURE__ */ new Map();
2695
- for (const packageName of languageServicePluginOptions.namespaceImportPackages) {
2696
- const barrelModule = ts.resolveModuleName(packageName, sourceFile.fileName, program.getCompilerOptions(), host);
2697
- if (barrelModule.resolvedModule) {
2698
- const barrelPath = barrelModule.resolvedModule.resolvedFileName;
2699
- const barrelSource = program.getSourceFile(barrelPath) || ts.createSourceFile(barrelPath, host.readFile(barrelPath) || "", sourceFile.languageVersion, true);
2700
- if (barrelSource) {
2701
- for (const statement of barrelSource.statements) {
2702
- if (ts.isExportDeclaration(statement)) {
2703
- const exportClause = statement.exportClause;
2704
- const moduleSpecifier = statement.moduleSpecifier;
2705
- if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
2706
- const unbarreledModulePathResolved = ts.resolveModuleName(
2707
- moduleSpecifier.text,
2708
- barrelSource.fileName,
2709
- program.getCompilerOptions(),
2710
- host
2711
- );
2712
- if (unbarreledModulePathResolved.resolvedModule) {
2713
- const unbarreledModulePath = unbarreledModulePathResolved.resolvedModule.resolvedFileName;
2714
- if (exportClause && ts.isNamespaceExport(exportClause) && ts.isIdentifier(exportClause.name)) {
2715
- namespaceByFileName.set(unbarreledModulePath, exportClause.name.text);
2716
- const existingUnbarreledModulePath = unbarreledModulePathByFileName.get(barrelSource.fileName) || [];
2717
- existingUnbarreledModulePath.push([exportClause.name.text, unbarreledModulePath]);
2718
- unbarreledModulePathByFileName.set(barrelSource.fileName, existingUnbarreledModulePath);
2719
- }
2720
- if (exportClause && ts.isNamedExports(exportClause)) {
2721
- for (const element of exportClause.elements) {
2722
- if (!ts.isIdentifier(element.name)) continue;
2723
- const methodName = element.name.text;
2724
- const excludedMethods = excludedByFileName.get(methodName) || [];
2725
- excludedMethods.push(unbarreledModulePath);
2726
- excludedByFileName.set(methodName, excludedMethods);
2727
- }
2728
- }
2729
- }
2730
- }
2731
- }
2732
- }
2733
- }
2734
- }
2735
- }
2736
- return {
2737
- getImportNamespaceByFileName: (fileName) => namespaceByFileName.get(fileName),
2738
- isExcludedFromNamespaceImport: (fileName, exportName) => (excludedByFileName.get(exportName) || []).includes(fileName),
2739
- getUnbarreledModulePath: (fileName, exportName) => unbarreledModulePathByFileName.get(fileName)?.find(([name]) => name === exportName)?.[1]
2740
- };
2741
- });
2742
- var appendEffectCompletionEntryData = fn("collectNamespaceImports")(
2743
- function* (sourceFile, applicableCompletions) {
2744
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2745
- if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletions;
2746
- const packagesMetadata = importablePackagesMetadataCache.get(sourceFile.fileName) || (yield* makeImportablePackagesMetadata(sourceFile));
2747
- importablePackagesMetadataCache.set(sourceFile.fileName, packagesMetadata);
2748
- if (applicableCompletions) {
2749
- return {
2750
- ...applicableCompletions,
2751
- entries: applicableCompletions.entries.map((entry) => {
2752
- if (entry.data && entry.data.fileName && !entry.insertText && !entry.filterText && entry.data.exportName && entry.data.moduleSpecifier) {
2753
- const isExcluded = packagesMetadata.isExcludedFromNamespaceImport(
2754
- entry.data.fileName,
2755
- entry.data.exportName
2756
- );
2757
- if (isExcluded) return entry;
2758
- const unbarreledModulePath = packagesMetadata.getUnbarreledModulePath(
2759
- entry.data.fileName,
2760
- entry.data.exportName
2761
- );
2762
- const namespaceName = packagesMetadata.getImportNamespaceByFileName(
2763
- unbarreledModulePath || entry.data.fileName
2764
- );
2765
- if (namespaceName) {
2766
- return {
2767
- ...entry,
2768
- // insertText: unbarreledModulePath ? namespaceName : namespaceName + "." + entry.name,
2769
- // filterText: entry.name,
2770
- data: {
2771
- ...entry.data,
2772
- effectNamespaceName: namespaceName,
2773
- effectUnbarreledModulePath: unbarreledModulePath || "",
2774
- effectReplaceSpan: entry.replacementSpan || applicableCompletions.optionalReplacementSpan
2775
- }
2776
- };
2777
- }
2778
- }
2779
- return entry;
2780
- })
2781
- };
2782
- }
2783
- return applicableCompletions;
2784
- }
2785
- );
2786
- var postprocessCompletionEntryDetails = fn("postprocessCompletionEntryDetails")(
2787
- function* (sourceFile, data, applicableCompletionEntryDetails, formatOptions, preferences, languageServiceHost) {
2788
- const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
2789
- if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletionEntryDetails;
2790
- const ts = yield* service(TypeScriptApi);
2791
- const program = yield* service(TypeScriptProgram);
2792
- const getModuleSpecifier = makeGetModuleSpecifier(ts);
2793
- if (!getModuleSpecifier) return applicableCompletionEntryDetails;
2794
- if (!applicableCompletionEntryDetails) return applicableCompletionEntryDetails;
2795
- if (!data) return applicableCompletionEntryDetails;
2796
- if (!("effectNamespaceName" in data && "effectUnbarreledModulePath" in data && "effectReplaceSpan" in data)) {
2797
- return applicableCompletionEntryDetails;
2798
- }
2799
- const effectReplaceSpan = data.effectReplaceSpan;
2800
- const codeActions = applicableCompletionEntryDetails.codeActions;
2801
- if (codeActions && codeActions.length === 1) {
2802
- const action = codeActions[0];
2803
- if (action.changes.length === 1) {
2804
- const fileTextChanges = action.changes[0];
2805
- if (fileTextChanges.fileName === sourceFile.fileName && fileTextChanges.textChanges.length === 1) {
2806
- const change = fileTextChanges.textChanges[0];
2807
- let hasImportActions = false;
2808
- if (change.newText.trim().toLowerCase().startsWith("import") && change.newText.indexOf(data.exportName) > -1) {
2809
- hasImportActions = true;
2810
- }
2811
- if (!hasImportActions && change.newText.indexOf(data.exportName) > -1) {
2812
- const ancestorNodes = yield* getAncestorNodesInRange(sourceFile, {
2813
- pos: change.span.start,
2814
- end: change.span.start
2815
- });
2816
- const importNodes = ancestorNodes.filter((node) => ts.isImportDeclaration(node));
2817
- hasImportActions = importNodes.length > 0;
2818
- }
2819
- if (!hasImportActions) return applicableCompletionEntryDetails;
2820
- const formatContext = ts.formatting.getFormatContext(
2821
- formatOptions || {},
2822
- languageServiceHost
2823
- );
2824
- const changes = ts.textChanges.ChangeTracker.with(
2825
- {
2826
- formatContext,
2827
- host: languageServiceHost,
2828
- preferences: preferences || {}
2829
- },
2830
- (changeTracker) => {
2831
- const isBarrelRedirect = String(data.effectUnbarreledModulePath).length > 0;
2832
- const moduleSpecifier = isBarrelRedirect ? getModuleSpecifier(
2833
- program.getCompilerOptions(),
2834
- sourceFile,
2835
- sourceFile.fileName,
2836
- String(data.effectUnbarreledModulePath),
2837
- program
2838
- ) : String(data.moduleSpecifier);
2839
- ts.insertImports(
2840
- changeTracker,
2841
- sourceFile,
2842
- ts.factory.createImportDeclaration(
2843
- void 0,
2844
- ts.factory.createImportClause(
2845
- false,
2846
- void 0,
2847
- ts.factory.createNamespaceImport(ts.factory.createIdentifier(String(data.effectNamespaceName)))
2848
- ),
2849
- ts.factory.createStringLiteral(moduleSpecifier)
2850
- ),
2851
- true,
2852
- preferences || {}
2853
- );
2854
- if (!isBarrelRedirect) {
2855
- changeTracker.insertText(
2856
- sourceFile,
2857
- effectReplaceSpan.start,
2858
- String(data.effectNamespaceName) + "."
2859
- );
2860
- }
2861
- }
2862
- );
2863
- return {
2864
- ...applicableCompletionEntryDetails,
2865
- codeActions: [
2866
- {
2867
- description: "Import * as " + data.effectNamespaceName + " from " + data.effectUnbarreledModulePath,
2868
- changes
2869
- }
2870
- ]
2871
- };
2872
- }
2873
- }
2874
- }
2875
- return applicableCompletionEntryDetails;
2876
- }
2877
- );
2878
-
2879
- // src/diagnostics/duplicatePackage.ts
2880
- var checkedPackagesCache = /* @__PURE__ */ new Map();
2881
- var programResolvedCacheSize = /* @__PURE__ */ new Map();
2882
- var duplicatePackage = createDiagnostic({
2883
- name: "duplicatePackage",
2884
- code: 6,
2885
- severity: "warning",
2886
- apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
2887
- const program = yield* service(TypeScriptProgram);
2888
- const options = yield* service(LanguageServicePluginOptions);
2889
- if (sourceFile.statements.length < 1) return;
2890
- let resolvedPackages = checkedPackagesCache.get(sourceFile.fileName) || {};
2891
- const newResolvedModuleSize = hasProperty(program, "resolvedModules") && hasProperty(program.resolvedModules, "size") && isNumber(program.resolvedModules.size) ? program.resolvedModules.size : 0;
2892
- const oldResolvedSize = programResolvedCacheSize.get(sourceFile.fileName) || -1;
2893
- if (newResolvedModuleSize !== oldResolvedSize) {
2894
- const seenPackages = /* @__PURE__ */ new Set();
2895
- resolvedPackages = {};
2896
- program.getSourceFiles().map((_) => {
2897
- const packageInfo = parsePackageContentNameAndVersionFromScope(_);
2898
- if (!packageInfo) return;
2899
- const packageNameAndVersion = packageInfo.name + "@" + packageInfo.version;
2900
- if (seenPackages.has(packageNameAndVersion)) return;
2901
- seenPackages.add(packageNameAndVersion);
2902
- if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
2903
- if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
2904
- resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
2905
- resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
2906
- });
2907
- checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
2908
- programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
2909
- }
2910
- for (const packageName of Object.keys(resolvedPackages)) {
2911
- if (Object.keys(resolvedPackages[packageName]).length > 1) {
2912
- const versions = Object.keys(resolvedPackages[packageName]);
2913
- report({
2914
- node: sourceFile.statements[0],
2915
- messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
2916
- Cleanup your dependencies and your package lockfile to avoid multiple instances of this package and reload the project.
2917
- If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
2918
-
2919
- ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
2920
- fixes: []
2921
- });
2922
- }
2923
- }
2924
- })
2925
- });
2926
-
2927
- // src/diagnostics/floatingEffect.ts
2928
- var floatingEffect = createDiagnostic({
2929
- name: "floatingEffect",
2930
- code: 3,
2931
- severity: "error",
2932
- apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
2933
- const ts = yield* service(TypeScriptApi);
2934
- const typeChecker = yield* service(TypeCheckerApi);
2537
+ const typeChecker = yield* service(TypeCheckerApi);
2935
2538
  const typeParser = yield* service(TypeParser);
2936
2539
  function isFloatingExpression(node) {
2937
2540
  if (!ts.isExpressionStatement(node)) return false;
@@ -3259,22 +2862,24 @@ var missingEffectContext = createDiagnostic({
3259
2862
  const sortTypes = sort(typeOrder);
3260
2863
  const entries = yield* expectedAndRealType(sourceFile);
3261
2864
  for (const [node, expectedType, valueNode, realType] of entries) {
3262
- const missingContext = yield* pipe(
3263
- checkForMissingContextTypes(
3264
- node,
3265
- expectedType,
3266
- valueNode,
3267
- realType
3268
- ),
3269
- orElse2(() => succeed([]))
3270
- );
3271
- if (missingContext.length > 0) {
3272
- report(
3273
- {
2865
+ if (expectedType !== realType) {
2866
+ yield* pipe(
2867
+ checkForMissingContextTypes(
3274
2868
  node,
3275
- messageText: `Missing '${sortTypes(missingContext).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect context.`,
3276
- fixes: []
3277
- }
2869
+ expectedType,
2870
+ valueNode,
2871
+ realType
2872
+ ),
2873
+ map4(
2874
+ (missingTypes) => missingTypes.length > 0 ? report(
2875
+ {
2876
+ node,
2877
+ messageText: `Missing '${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect context.`,
2878
+ fixes: []
2879
+ }
2880
+ ) : void 0
2881
+ ),
2882
+ ignore
3278
2883
  );
3279
2884
  }
3280
2885
  }
@@ -3305,36 +2910,284 @@ var missingEffectError = createDiagnostic({
3305
2910
  const sortTypes = sort(typeOrder);
3306
2911
  const entries = yield* expectedAndRealType(sourceFile);
3307
2912
  for (const [node, expectedType, valueNode, realType] of entries) {
3308
- const missingContext = yield* pipe(
3309
- checkForMissingErrorTypes(
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(
3310
3022
  node,
3311
- expectedType,
3312
- valueNode,
3313
- realType
3314
- ),
3315
- orElse2(() => succeed([]))
3316
- );
3317
- if (missingContext.length > 0) {
3318
- report(
3319
- {
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,
3320
3057
  node,
3321
- messageText: `Missing '${sortTypes(missingContext).map((_) => typeChecker.typeToString(_)).join(" | ")}' in the expected Effect errors.`,
3322
- fixes: []
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
+ );
3323
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)) {
3159
+ yield* pipe(
3160
+ typeParser.unnecessaryEffectGen(node),
3161
+ map4(
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
+ })
3176
+ ),
3177
+ ignore
3324
3178
  );
3325
3179
  }
3326
3180
  }
3327
3181
  })
3328
3182
  });
3329
3183
 
3330
- // src/diagnostics/missingReturnYieldStar.ts
3331
- var missingReturnYieldStar = createDiagnostic({
3332
- name: "missingReturnYieldStar",
3333
- code: 7,
3334
- severity: "error",
3335
- 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) {
3336
3190
  const ts = yield* service(TypeScriptApi);
3337
- const typeChecker = yield* service(TypeCheckerApi);
3338
3191
  const typeParser = yield* service(TypeParser);
3339
3192
  const nodeToVisit = [];
3340
3193
  const appendNodeToVisit = (node) => {
@@ -3345,295 +3198,485 @@ var missingReturnYieldStar = createDiagnostic({
3345
3198
  while (nodeToVisit.length > 0) {
3346
3199
  const node = nodeToVisit.shift();
3347
3200
  ts.forEachChild(node, appendNodeToVisit);
3348
- if (ts.isYieldExpression(node) && node.expression && node.asteriskToken) {
3349
- const type = typeChecker.getTypeAtLocation(node.expression);
3350
- const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
3351
- if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
3352
- const generatorFunctionOrReturnStatement = ts.findAncestor(
3353
- node,
3354
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_)
3355
- );
3356
- if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement)) {
3357
- if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
3358
- const effectGenNode = generatorFunctionOrReturnStatement.parent;
3359
- const effectGenLike = yield* pipe(
3360
- typeParser.effectGen(effectGenNode),
3361
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3362
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3363
- option
3364
- );
3365
- if (isSome2(effectGenLike)) {
3366
- const fix = node.expression ? [{
3367
- fixName: "missingReturnYieldStar_fix",
3368
- 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",
3369
3212
  apply: gen(function* () {
3370
- const changeTracker = yield* service(ChangeTracker);
3371
- changeTracker.replaceNode(
3372
- sourceFile,
3373
- node,
3374
- ts.factory.createReturnStatement(
3375
- node
3376
- )
3213
+ const textChanges = yield* service(
3214
+ ChangeTracker
3377
3215
  );
3216
+ textChanges.replaceNode(sourceFile, node, subject);
3378
3217
  })
3379
- }] : [];
3380
- report({
3381
- node,
3382
- messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
3383
- fixes: fix
3384
- });
3385
- }
3218
+ }]
3219
+ });
3386
3220
  }
3387
- }
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
3388
3392
  }
3389
- }
3390
- }
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
+ }]);
3391
3409
  })
3392
3410
  });
3393
3411
 
3394
- // src/diagnostics/missingStarInYieldEffectGen.ts
3395
- var missingStarInYieldEffectGen = createDiagnostic({
3396
- name: "missingStarInYieldEffectGen",
3397
- code: 4,
3398
- severity: "error",
3399
- 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) {
3400
3416
  const ts = yield* service(TypeScriptApi);
3401
- const typeParser = yield* service(TypeParser);
3402
- const brokenGenerators = /* @__PURE__ */ new Set();
3403
- const brokenYields = /* @__PURE__ */ new Set();
3404
- const nodeToVisit = [];
3405
- const appendNodeToVisit = (node) => {
3406
- nodeToVisit.push(node);
3407
- return void 0;
3408
- };
3409
- ts.forEachChild(sourceFile, appendNodeToVisit);
3410
- while (nodeToVisit.length > 0) {
3411
- const node = nodeToVisit.shift();
3412
- ts.forEachChild(node, appendNodeToVisit);
3413
- if (ts.isYieldExpression(node) && node.expression && node.asteriskToken === void 0) {
3414
- const functionStarNode = ts.findAncestor(
3415
- node,
3416
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_)
3417
- );
3418
- if (functionStarNode && functionStarNode.parent) {
3419
- const effectGenNode = functionStarNode.parent;
3420
- yield* pipe(
3421
- typeParser.effectGen(effectGenNode),
3422
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3423
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3424
- map4(({ functionStar }) => {
3425
- if (functionStar) {
3426
- brokenGenerators.add(functionStar);
3427
- }
3428
- brokenYields.add(node);
3429
- }),
3430
- ignore
3431
- );
3432
- }
3433
- }
3434
- }
3435
- brokenGenerators.forEach(
3436
- (node) => report({
3437
- node,
3438
- messageText: `Seems like you used yield instead of yield* inside this Effect.gen.`,
3439
- fixes: []
3440
- })
3417
+ const typeChecker = yield* service(TypeCheckerApi);
3418
+ const maybeInfos = yield* option(
3419
+ parseAccessedExpressionForCompletion(sourceFile, position)
3441
3420
  );
3442
- brokenYields.forEach((node) => {
3443
- const fix = node.expression ? [{
3444
- fixName: "missingStarInYieldEffectGen_fix",
3445
- description: "Replace yield with yield*",
3446
- apply: gen(function* () {
3447
- const changeTracker = yield* service(ChangeTracker);
3448
- changeTracker.replaceNode(
3449
- sourceFile,
3450
- node,
3451
- ts.factory.createYieldExpression(
3452
- ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3453
- node.expression
3454
- )
3455
- );
3456
- })
3457
- }] : [];
3458
- report({
3459
- node,
3460
- messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
3461
- fixes: fix
3462
- });
3463
- });
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
+ }];
3464
3439
  })
3465
3440
  });
3466
3441
 
3467
- // src/diagnostics/returnEffectInGen.ts
3468
- var returnEffectInGen = createDiagnostic({
3469
- name: "returnEffectInGen",
3470
- code: 11,
3471
- severity: "suggestion",
3472
- 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) {
3473
3446
  const ts = yield* service(TypeScriptApi);
3474
- const typeChecker = yield* service(TypeCheckerApi);
3475
- const typeParser = yield* service(TypeParser);
3476
- const nodeToVisit = [];
3477
- const appendNodeToVisit = (node) => {
3478
- nodeToVisit.push(node);
3479
- return void 0;
3480
- };
3481
- ts.forEachChild(sourceFile, appendNodeToVisit);
3482
- while (nodeToVisit.length > 0) {
3483
- const node = nodeToVisit.shift();
3484
- ts.forEachChild(node, appendNodeToVisit);
3485
- if (ts.isReturnStatement(node) && node.expression) {
3486
- if (ts.isYieldExpression(node.expression)) continue;
3487
- const generatorOrRegularFunction = ts.findAncestor(
3488
- node,
3489
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
3490
- );
3491
- if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
3492
- const type = typeChecker.getTypeAtLocation(node.expression);
3493
- const maybeEffect = yield* option(typeParser.strictEffectType(type, node.expression));
3494
- if (isSome2(maybeEffect)) {
3495
- if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
3496
- const effectGenNode = generatorOrRegularFunction.parent;
3497
- yield* pipe(
3498
- typeParser.effectGen(effectGenNode),
3499
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
3500
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
3501
- map4(() => {
3502
- const fix = node.expression ? [{
3503
- fixName: "returnEffectInGen_fix",
3504
- description: "Add yield* statement",
3505
- apply: gen(function* () {
3506
- const changeTracker = yield* service(ChangeTracker);
3507
- changeTracker.replaceNode(
3508
- sourceFile,
3509
- node.expression,
3510
- ts.factory.createYieldExpression(
3511
- ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
3512
- node.expression
3513
- )
3514
- );
3515
- })
3516
- }] : [];
3517
- report({
3518
- node,
3519
- messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>.
3520
- Maybe you wanted to return yield* instead?
3521
- 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.`,
3522
- fixes: fix
3523
- });
3524
- }),
3525
- ignore
3526
- );
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
+ }
3527
3533
  }
3528
3534
  }
3529
3535
  }
3530
3536
  }
3531
- })
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
+ };
3532
3543
  });
3533
-
3534
- // src/diagnostics/unnecessaryEffectGen.ts
3535
- var unnecessaryEffectGen = createDiagnostic({
3536
- name: "unnecessaryEffectGen",
3537
- code: 5,
3538
- severity: "suggestion",
3539
- apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
3540
- const ts = yield* service(TypeScriptApi);
3541
- const typeParser = yield* service(TypeParser);
3542
- const nodeToVisit = [];
3543
- const appendNodeToVisit = (node) => {
3544
- nodeToVisit.push(node);
3545
- return void 0;
3546
- };
3547
- ts.forEachChild(sourceFile, appendNodeToVisit);
3548
- while (nodeToVisit.length > 0) {
3549
- const node = nodeToVisit.shift();
3550
- ts.forEachChild(node, appendNodeToVisit);
3551
- if (ts.isCallExpression(node)) {
3552
- yield* pipe(
3553
- typeParser.unnecessaryEffectGen(node),
3554
- map4(
3555
- ({ replacementNode }) => report({
3556
- node,
3557
- messageText: `This Effect.gen contains a single return statement.`,
3558
- fixes: [{
3559
- fixName: "unnecessaryEffectGen_fix",
3560
- description: "Remove the Effect.gen, and keep the body",
3561
- apply: gen(function* () {
3562
- const textChanges = yield* service(
3563
- ChangeTracker
3564
- );
3565
- textChanges.replaceNode(sourceFile, node, yield* replacementNode);
3566
- })
3567
- }]
3568
- })
3569
- ),
3570
- ignore
3571
- );
3572
- }
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
+ };
3573
3584
  }
3574
- })
3575
- });
3576
-
3577
- // src/diagnostics/unnecessaryPipe.ts
3578
- var unnecessaryPipe = createDiagnostic({
3579
- name: "unnecessaryPipe",
3580
- code: 9,
3581
- severity: "suggestion",
3582
- 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;
3583
3592
  const ts = yield* service(TypeScriptApi);
3584
- const typeParser = yield* service(TypeParser);
3585
- const nodeToVisit = [];
3586
- const appendNodeToVisit = (node) => {
3587
- nodeToVisit.push(node);
3588
- return void 0;
3589
- };
3590
- ts.forEachChild(sourceFile, appendNodeToVisit);
3591
- while (nodeToVisit.length > 0) {
3592
- const node = nodeToVisit.shift();
3593
- ts.forEachChild(node, appendNodeToVisit);
3594
- if (ts.isCallExpression(node)) {
3595
- yield* pipe(
3596
- typeParser.pipeCall(node),
3597
- map4(({ args, subject }) => {
3598
- if (args.length === 0) {
3599
- report({
3600
- node,
3601
- messageText: `This pipe call contains no arguments.`,
3602
- fixes: [{
3603
- fixName: "unnecessaryPipe_fix",
3604
- description: "Remove the pipe call",
3605
- apply: gen(function* () {
3606
- const textChanges = yield* service(
3607
- ChangeTracker
3608
- );
3609
- textChanges.replaceNode(sourceFile, node, subject);
3610
- })
3611
- }]
3612
- });
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
+ }
3613
3663
  }
3614
- }),
3615
- ignore
3616
- );
3664
+ );
3665
+ return {
3666
+ ...applicableCompletionEntryDetails,
3667
+ codeActions: [
3668
+ {
3669
+ description: "Import * as " + data.effectNamespaceName + " from " + data.effectUnbarreledModulePath,
3670
+ changes
3671
+ }
3672
+ ]
3673
+ };
3674
+ }
3617
3675
  }
3618
3676
  }
3619
- })
3620
- });
3621
-
3622
- // src/diagnostics.ts
3623
- var diagnostics = [
3624
- duplicatePackage,
3625
- missingEffectContext,
3626
- missingEffectError,
3627
- floatingEffect,
3628
- missingStarInYieldEffectGen,
3629
- unnecessaryEffectGen,
3630
- missingReturnYieldStar,
3631
- leakingRequirements,
3632
- unnecessaryPipe,
3633
- genericEffectServices,
3634
- returnEffectInGen,
3635
- importFromBarrel
3636
- ];
3677
+ return applicableCompletionEntryDetails;
3678
+ }
3679
+ );
3637
3680
 
3638
3681
  // src/goto/effectRpcDefinition.ts
3639
3682
  function effectRpcDefinition(applicableGotoDefinition, sourceFile, position) {