@effect/language-service 0.22.1 → 0.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/index.js +1398 -1352
- package/index.js.map +1 -1
- 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/
|
|
1736
|
-
var
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
const
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
)
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
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
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
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/
|
|
1820
|
-
var
|
|
1821
|
-
var
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
const
|
|
1831
|
-
|
|
1832
|
-
|
|
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
|
|
1822
|
+
return result;
|
|
1835
1823
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
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
|
-
|
|
1840
|
+
current = current.parent;
|
|
1842
1841
|
}
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
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
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
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
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
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
|
}
|
|
@@ -2247,686 +2473,59 @@ function make4(ts, typeChecker) {
|
|
|
2247
2473
|
varianceStructInvariantType(type, atLocation, "_Service")
|
|
2248
2474
|
),
|
|
2249
2475
|
([Identifier, Service]) => ({ Identifier, Service })
|
|
2250
|
-
);
|
|
2251
|
-
const contextTag = cachedBy(
|
|
2252
|
-
fn("TypeParser.contextTag")(function* (type, atLocation) {
|
|
2253
|
-
yield* pipeableType(type, atLocation);
|
|
2254
|
-
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2255
|
-
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2256
|
-
);
|
|
2257
|
-
propertiesSymbols.sort((a, b) => b.name.indexOf("TypeId") - a.name.indexOf("TypeId"));
|
|
2258
|
-
for (const propertySymbol of propertiesSymbols) {
|
|
2259
|
-
const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
|
|
2260
|
-
const varianceArgs = yield* option(contextTagVarianceStruct(
|
|
2261
|
-
propertyType,
|
|
2262
|
-
atLocation
|
|
2263
|
-
));
|
|
2264
|
-
if (isSome2(varianceArgs)) {
|
|
2265
|
-
return varianceArgs.value;
|
|
2266
|
-
}
|
|
2267
|
-
}
|
|
2268
|
-
return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
|
|
2269
|
-
}),
|
|
2270
|
-
"TypeParser.contextTag",
|
|
2271
|
-
(type) => type
|
|
2272
|
-
);
|
|
2273
|
-
const pipeCall = cachedBy(
|
|
2274
|
-
function(node) {
|
|
2275
|
-
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
|
|
2276
|
-
return succeed({ node, subject: node.expression.expression, args: Array.from(node.arguments) });
|
|
2277
|
-
}
|
|
2278
|
-
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
|
|
2279
|
-
const [subject, ...args] = node.arguments;
|
|
2280
|
-
return succeed({ node, subject, args });
|
|
2281
|
-
}
|
|
2282
|
-
return typeParserIssue("Node is not a pipe call", void 0, node);
|
|
2283
|
-
},
|
|
2284
|
-
"TypeParser.pipeCall",
|
|
2285
|
-
(node) => node
|
|
2286
|
-
);
|
|
2287
|
-
return {
|
|
2288
|
-
effectType,
|
|
2289
|
-
strictEffectType,
|
|
2290
|
-
layerType,
|
|
2291
|
-
fiberType,
|
|
2292
|
-
effectSubtype,
|
|
2293
|
-
importedEffectModule,
|
|
2294
|
-
effectGen,
|
|
2295
|
-
effectFnUntracedGen,
|
|
2296
|
-
effectFnGen,
|
|
2297
|
-
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
2298
|
-
effectSchemaType,
|
|
2299
|
-
contextTag,
|
|
2300
|
-
pipeCall
|
|
2301
|
-
};
|
|
2302
|
-
}
|
|
2303
|
-
|
|
2304
|
-
// src/completions/fnFunctionStar.ts
|
|
2305
|
-
var fnFunctionStar = createCompletion({
|
|
2306
|
-
name: "fnFunctionStar",
|
|
2307
|
-
apply: fn("fnFunctionStar")(function* (sourceFile, position) {
|
|
2308
|
-
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
|
-
};
|
|
2476
|
+
);
|
|
2477
|
+
const contextTag = cachedBy(
|
|
2478
|
+
fn("TypeParser.contextTag")(function* (type, atLocation) {
|
|
2479
|
+
yield* pipeableType(type, atLocation);
|
|
2480
|
+
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
2481
|
+
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
|
|
2482
|
+
);
|
|
2483
|
+
propertiesSymbols.sort((a, b) => b.name.indexOf("TypeId") - a.name.indexOf("TypeId"));
|
|
2484
|
+
for (const propertySymbol of propertiesSymbols) {
|
|
2485
|
+
const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
|
|
2486
|
+
const varianceArgs = yield* option(contextTagVarianceStruct(
|
|
2487
|
+
propertyType,
|
|
2488
|
+
atLocation
|
|
2489
|
+
));
|
|
2490
|
+
if (isSome2(varianceArgs)) {
|
|
2491
|
+
return varianceArgs.value;
|
|
2876
2492
|
}
|
|
2877
2493
|
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
)
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
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
|
-
});
|
|
2494
|
+
return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
|
|
2495
|
+
}),
|
|
2496
|
+
"TypeParser.contextTag",
|
|
2497
|
+
(type) => type
|
|
2498
|
+
);
|
|
2499
|
+
const pipeCall = cachedBy(
|
|
2500
|
+
function(node) {
|
|
2501
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
|
|
2502
|
+
return succeed({ node, subject: node.expression.expression, args: Array.from(node.arguments) });
|
|
2926
2503
|
}
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
});
|
|
2504
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
|
|
2505
|
+
const [subject, ...args] = node.arguments;
|
|
2506
|
+
return succeed({ node, subject, args });
|
|
2507
|
+
}
|
|
2508
|
+
return typeParserIssue("Node is not a pipe call", void 0, node);
|
|
2509
|
+
},
|
|
2510
|
+
"TypeParser.pipeCall",
|
|
2511
|
+
(node) => node
|
|
2512
|
+
);
|
|
2513
|
+
return {
|
|
2514
|
+
effectType,
|
|
2515
|
+
strictEffectType,
|
|
2516
|
+
layerType,
|
|
2517
|
+
fiberType,
|
|
2518
|
+
effectSubtype,
|
|
2519
|
+
importedEffectModule,
|
|
2520
|
+
effectGen,
|
|
2521
|
+
effectFnUntracedGen,
|
|
2522
|
+
effectFnGen,
|
|
2523
|
+
unnecessaryEffectGen: unnecessaryEffectGen2,
|
|
2524
|
+
effectSchemaType,
|
|
2525
|
+
contextTag,
|
|
2526
|
+
pipeCall
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2930
2529
|
|
|
2931
2530
|
// src/diagnostics/floatingEffect.ts
|
|
2932
2531
|
var floatingEffect = createDiagnostic({
|
|
@@ -2981,8 +2580,226 @@ var genericEffectServices = createDiagnostic({
|
|
|
2981
2580
|
severity: "warning",
|
|
2982
2581
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
2983
2582
|
const ts = yield* service(TypeScriptApi);
|
|
2984
|
-
const typeParser = yield* service(TypeParser);
|
|
2583
|
+
const typeParser = yield* service(TypeParser);
|
|
2584
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2585
|
+
const nodeToVisit = [];
|
|
2586
|
+
const appendNodeToVisit = (node) => {
|
|
2587
|
+
nodeToVisit.push(node);
|
|
2588
|
+
return void 0;
|
|
2589
|
+
};
|
|
2590
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2591
|
+
while (nodeToVisit.length > 0) {
|
|
2592
|
+
const node = nodeToVisit.shift();
|
|
2593
|
+
const typesToCheck = [];
|
|
2594
|
+
if (ts.isClassDeclaration(node) && node.name && node.typeParameters && node.heritageClauses) {
|
|
2595
|
+
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2596
|
+
if (classSym) {
|
|
2597
|
+
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
2598
|
+
typesToCheck.push([type, node.name]);
|
|
2599
|
+
}
|
|
2600
|
+
} else {
|
|
2601
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2602
|
+
continue;
|
|
2603
|
+
}
|
|
2604
|
+
for (const [type, reportAt] of typesToCheck) {
|
|
2605
|
+
yield* pipe(
|
|
2606
|
+
typeParser.contextTag(type, node),
|
|
2607
|
+
map4(() => {
|
|
2608
|
+
report({
|
|
2609
|
+
node: reportAt,
|
|
2610
|
+
messageText: `Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior.`,
|
|
2611
|
+
fixes: []
|
|
2612
|
+
});
|
|
2613
|
+
}),
|
|
2614
|
+
orElse2(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
2615
|
+
ignore
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
})
|
|
2620
|
+
});
|
|
2621
|
+
|
|
2622
|
+
// src/diagnostics/importFromBarrel.ts
|
|
2623
|
+
var importFromBarrel = createDiagnostic({
|
|
2624
|
+
name: "importFromBarrel",
|
|
2625
|
+
code: 12,
|
|
2626
|
+
severity: "off",
|
|
2627
|
+
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
2628
|
+
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
2629
|
+
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
2630
|
+
const ts = yield* service(TypeScriptApi);
|
|
2631
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2632
|
+
const program = yield* service(TypeScriptProgram);
|
|
2633
|
+
const isImportedFromBarrelExport = (element, languageServicePluginOptions2) => {
|
|
2634
|
+
const getModuleSpecifier = makeGetModuleSpecifier(ts);
|
|
2635
|
+
const resolveExternalModuleName = makeResolveExternalModuleName(typeChecker);
|
|
2636
|
+
if (!(getModuleSpecifier && resolveExternalModuleName)) return;
|
|
2637
|
+
const importDeclaration = ts.findAncestor(element, (node) => ts.isImportDeclaration(node));
|
|
2638
|
+
if (!importDeclaration) return;
|
|
2639
|
+
if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return;
|
|
2640
|
+
const importClause = importDeclaration.importClause;
|
|
2641
|
+
if (!importClause) return;
|
|
2642
|
+
const namedBindings = importClause.namedBindings;
|
|
2643
|
+
if (!namedBindings) return;
|
|
2644
|
+
if (!ts.isNamedImports(namedBindings)) return;
|
|
2645
|
+
const barrelModuleName = importDeclaration.moduleSpecifier.text;
|
|
2646
|
+
if (languageServicePluginOptions2.namespaceImportPackages.indexOf(barrelModuleName.toLowerCase()) === -1) return;
|
|
2647
|
+
const moduleSymbol = resolveExternalModuleName(importDeclaration.moduleSpecifier);
|
|
2648
|
+
if (!moduleSymbol) return;
|
|
2649
|
+
if (!moduleSymbol.exports) return;
|
|
2650
|
+
const sourceFile2 = importDeclaration.getSourceFile();
|
|
2651
|
+
const nodeForSymbol = element.propertyName || element.name;
|
|
2652
|
+
if (!ts.isIdentifier(nodeForSymbol)) return;
|
|
2653
|
+
const importedName = nodeForSymbol.text;
|
|
2654
|
+
const reexportedSymbol = moduleSymbol.exports.get(ts.escapeLeadingUnderscores(importedName));
|
|
2655
|
+
if (!reexportedSymbol) return;
|
|
2656
|
+
if (!(reexportedSymbol.declarations && reexportedSymbol.declarations.length === 1)) return;
|
|
2657
|
+
const namespaceExport = reexportedSymbol.declarations[0];
|
|
2658
|
+
if (!ts.isNamespaceExport(namespaceExport)) return;
|
|
2659
|
+
const exportDeclaration = namespaceExport.parent;
|
|
2660
|
+
if (!ts.isExportDeclaration(exportDeclaration)) return;
|
|
2661
|
+
if (!exportDeclaration.moduleSpecifier) return;
|
|
2662
|
+
const originalModuleSymbol = resolveExternalModuleName(exportDeclaration.moduleSpecifier);
|
|
2663
|
+
if (!originalModuleSymbol) return;
|
|
2664
|
+
if (!originalModuleSymbol.valueDeclaration) return;
|
|
2665
|
+
const originalSourceFile = originalModuleSymbol.valueDeclaration.getSourceFile();
|
|
2666
|
+
const unbarrelledFileName = getModuleSpecifier(
|
|
2667
|
+
program.getCompilerOptions(),
|
|
2668
|
+
sourceFile2,
|
|
2669
|
+
sourceFile2.fileName,
|
|
2670
|
+
originalSourceFile.fileName,
|
|
2671
|
+
program
|
|
2672
|
+
);
|
|
2673
|
+
if (unbarrelledFileName.toLowerCase().indexOf(barrelModuleName.toLowerCase() + "/") === -1) return;
|
|
2674
|
+
return { unbarrelledFileName, importedName, barrelModuleName, importClause, namedBindings, importDeclaration };
|
|
2675
|
+
};
|
|
2676
|
+
const nodeToVisit = [];
|
|
2677
|
+
const appendNodeToVisit = (node) => {
|
|
2678
|
+
nodeToVisit.push(node);
|
|
2679
|
+
return void 0;
|
|
2680
|
+
};
|
|
2681
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2682
|
+
while (nodeToVisit.length > 0) {
|
|
2683
|
+
const node = nodeToVisit.shift();
|
|
2684
|
+
const parent = node.parent;
|
|
2685
|
+
if (!(ts.isImportSpecifier(node) && ts.isNamedImports(parent))) {
|
|
2686
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2687
|
+
continue;
|
|
2688
|
+
}
|
|
2689
|
+
const result = isImportedFromBarrelExport(node, languageServicePluginOptions);
|
|
2690
|
+
if (!result) continue;
|
|
2691
|
+
const { barrelModuleName, importClause, importDeclaration, importedName, namedBindings, unbarrelledFileName } = result;
|
|
2692
|
+
report({
|
|
2693
|
+
node,
|
|
2694
|
+
messageText: `Importing from barrel module ${barrelModuleName} is not allowed.`,
|
|
2695
|
+
fixes: [
|
|
2696
|
+
{
|
|
2697
|
+
fixName: "replaceWithUnbarrelledImport",
|
|
2698
|
+
description: `Import * as ${importedName} from ${unbarrelledFileName}`,
|
|
2699
|
+
apply: gen(function* () {
|
|
2700
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
2701
|
+
const newImport = ts.factory.createImportDeclaration(
|
|
2702
|
+
void 0,
|
|
2703
|
+
ts.factory.createImportClause(
|
|
2704
|
+
importClause.isTypeOnly || node.isTypeOnly,
|
|
2705
|
+
void 0,
|
|
2706
|
+
ts.factory.createNamespaceImport(ts.factory.createIdentifier(importedName))
|
|
2707
|
+
),
|
|
2708
|
+
ts.factory.createStringLiteral(unbarrelledFileName)
|
|
2709
|
+
);
|
|
2710
|
+
if (namedBindings.elements.length === 1) {
|
|
2711
|
+
changeTracker.replaceNode(
|
|
2712
|
+
sourceFile,
|
|
2713
|
+
importDeclaration,
|
|
2714
|
+
newImport
|
|
2715
|
+
);
|
|
2716
|
+
} else {
|
|
2717
|
+
changeTracker.insertNodeAfter(sourceFile, importDeclaration, newImport);
|
|
2718
|
+
changeTracker.replaceNode(
|
|
2719
|
+
sourceFile,
|
|
2720
|
+
namedBindings,
|
|
2721
|
+
ts.factory.updateNamedImports(
|
|
2722
|
+
namedBindings,
|
|
2723
|
+
namedBindings.elements.filter((e) => e !== node)
|
|
2724
|
+
)
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
})
|
|
2728
|
+
}
|
|
2729
|
+
]
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
})
|
|
2733
|
+
});
|
|
2734
|
+
|
|
2735
|
+
// src/diagnostics/leakingRequirements.ts
|
|
2736
|
+
var leakingRequirements = createDiagnostic({
|
|
2737
|
+
name: "leakingRequirements",
|
|
2738
|
+
code: 8,
|
|
2739
|
+
severity: "suggestion",
|
|
2740
|
+
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
2741
|
+
const ts = yield* service(TypeScriptApi);
|
|
2985
2742
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2743
|
+
const typeParser = yield* service(TypeParser);
|
|
2744
|
+
const typeOrder = yield* deterministicTypeOrder;
|
|
2745
|
+
const parseLeakedRequirements = cachedBy(
|
|
2746
|
+
fn("leakingServices.checkServiceLeaking")(
|
|
2747
|
+
function* (service2, atLocation) {
|
|
2748
|
+
const properties = typeChecker.getPropertiesOfType(service2);
|
|
2749
|
+
if (properties.length < 1) return [];
|
|
2750
|
+
const memory = /* @__PURE__ */ new Map();
|
|
2751
|
+
let sharedRequirementsKeys = void 0;
|
|
2752
|
+
let effectMembers = 0;
|
|
2753
|
+
for (const property of properties) {
|
|
2754
|
+
const servicePropertyType = typeChecker.getTypeOfSymbolAtLocation(property, atLocation);
|
|
2755
|
+
let effectContextType = void 0;
|
|
2756
|
+
yield* pipe(
|
|
2757
|
+
typeParser.effectType(servicePropertyType, atLocation),
|
|
2758
|
+
map4((_) => effectContextType = _.R),
|
|
2759
|
+
orElse2(() => {
|
|
2760
|
+
const servicePropertyCallSignatures = servicePropertyType.getCallSignatures();
|
|
2761
|
+
if (servicePropertyCallSignatures.length === 1) {
|
|
2762
|
+
return pipe(
|
|
2763
|
+
typeParser.effectType(servicePropertyCallSignatures[0].getReturnType(), atLocation),
|
|
2764
|
+
map4((_) => {
|
|
2765
|
+
effectContextType = _.R;
|
|
2766
|
+
})
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2769
|
+
return void_;
|
|
2770
|
+
}),
|
|
2771
|
+
ignore
|
|
2772
|
+
);
|
|
2773
|
+
if (effectContextType) {
|
|
2774
|
+
effectMembers++;
|
|
2775
|
+
const { allIndexes } = yield* appendToUniqueTypesMap(memory, effectContextType, true);
|
|
2776
|
+
if (!sharedRequirementsKeys) {
|
|
2777
|
+
sharedRequirementsKeys = allIndexes;
|
|
2778
|
+
} else {
|
|
2779
|
+
sharedRequirementsKeys = intersection(sharedRequirementsKeys, allIndexes);
|
|
2780
|
+
if (sharedRequirementsKeys.length === 0) return [];
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
if (sharedRequirementsKeys && sharedRequirementsKeys.length > 0 && effectMembers >= 2) {
|
|
2785
|
+
return sharedRequirementsKeys.map((key) => memory.get(key));
|
|
2786
|
+
}
|
|
2787
|
+
return [];
|
|
2788
|
+
}
|
|
2789
|
+
),
|
|
2790
|
+
"leakingServices.checkServiceLeaking",
|
|
2791
|
+
(_, service2) => service2
|
|
2792
|
+
);
|
|
2793
|
+
function reportLeakingRequirements(node, requirements) {
|
|
2794
|
+
if (requirements.length === 0) return;
|
|
2795
|
+
report({
|
|
2796
|
+
node,
|
|
2797
|
+
messageText: `This Service is leaking the ${requirements.map((_) => typeChecker.typeToString(_)).join(" | ")} requirement.
|
|
2798
|
+
If these requirements cannot be cached and are expected to be provided per method invocation (e.g. HttpServerRequest), you can safely disable this diagnostic for this line through quickfixes.
|
|
2799
|
+
More info at https://effect.website/docs/requirements-management/layers/#avoiding-requirement-leakage`,
|
|
2800
|
+
fixes: []
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2986
2803
|
const nodeToVisit = [];
|
|
2987
2804
|
const appendNodeToVisit = (node) => {
|
|
2988
2805
|
nodeToVisit.push(node);
|
|
@@ -2992,7 +2809,9 @@ var genericEffectServices = createDiagnostic({
|
|
|
2992
2809
|
while (nodeToVisit.length > 0) {
|
|
2993
2810
|
const node = nodeToVisit.shift();
|
|
2994
2811
|
const typesToCheck = [];
|
|
2995
|
-
if (ts.
|
|
2812
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "GenericTag") {
|
|
2813
|
+
typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
|
|
2814
|
+
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
2996
2815
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2997
2816
|
if (classSym) {
|
|
2998
2817
|
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
@@ -3005,13 +2824,12 @@ var genericEffectServices = createDiagnostic({
|
|
|
3005
2824
|
for (const [type, reportAt] of typesToCheck) {
|
|
3006
2825
|
yield* pipe(
|
|
3007
2826
|
typeParser.contextTag(type, node),
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
node
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
}),
|
|
2827
|
+
flatMap2(
|
|
2828
|
+
({ Service }) => pipe(
|
|
2829
|
+
parseLeakedRequirements(Service, node),
|
|
2830
|
+
map4((requirements) => reportLeakingRequirements(reportAt, sort(requirements, typeOrder)))
|
|
2831
|
+
)
|
|
2832
|
+
),
|
|
3015
2833
|
orElse2(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
3016
2834
|
ignore
|
|
3017
2835
|
);
|
|
@@ -3020,60 +2838,176 @@ var genericEffectServices = createDiagnostic({
|
|
|
3020
2838
|
})
|
|
3021
2839
|
});
|
|
3022
2840
|
|
|
3023
|
-
// src/diagnostics/
|
|
3024
|
-
var
|
|
3025
|
-
name: "
|
|
3026
|
-
code:
|
|
3027
|
-
severity: "
|
|
3028
|
-
apply: fn("
|
|
3029
|
-
const
|
|
3030
|
-
|
|
2841
|
+
// src/diagnostics/missingEffectContext.ts
|
|
2842
|
+
var missingEffectContext = createDiagnostic({
|
|
2843
|
+
name: "missingEffectContext",
|
|
2844
|
+
code: 1,
|
|
2845
|
+
severity: "error",
|
|
2846
|
+
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
2847
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2848
|
+
const typeParser = yield* service(TypeParser);
|
|
2849
|
+
const typeOrder = yield* deterministicTypeOrder;
|
|
2850
|
+
const checkForMissingContextTypes = (node, expectedType, valueNode, realType) => pipe(
|
|
2851
|
+
all(
|
|
2852
|
+
typeParser.effectType(expectedType, node),
|
|
2853
|
+
typeParser.effectType(realType, valueNode)
|
|
2854
|
+
),
|
|
2855
|
+
flatMap2(
|
|
2856
|
+
([expectedEffect, realEffect]) => getMissingTypeEntriesInTargetType(
|
|
2857
|
+
realEffect.R,
|
|
2858
|
+
expectedEffect.R
|
|
2859
|
+
)
|
|
2860
|
+
)
|
|
2861
|
+
);
|
|
2862
|
+
const sortTypes = sort(typeOrder);
|
|
2863
|
+
const entries = yield* expectedAndRealType(sourceFile);
|
|
2864
|
+
for (const [node, expectedType, valueNode, realType] of entries) {
|
|
2865
|
+
if (expectedType !== realType) {
|
|
2866
|
+
yield* pipe(
|
|
2867
|
+
checkForMissingContextTypes(
|
|
2868
|
+
node,
|
|
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
|
|
2883
|
+
);
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
})
|
|
2887
|
+
});
|
|
2888
|
+
|
|
2889
|
+
// src/diagnostics/missingEffectError.ts
|
|
2890
|
+
var missingEffectError = createDiagnostic({
|
|
2891
|
+
name: "missingEffectError",
|
|
2892
|
+
code: 1,
|
|
2893
|
+
severity: "error",
|
|
2894
|
+
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
2895
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2896
|
+
const typeParser = yield* service(TypeParser);
|
|
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) {
|
|
3031
2943
|
const ts = yield* service(TypeScriptApi);
|
|
3032
2944
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3033
|
-
const
|
|
3034
|
-
const
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
const importDeclaration = ts.findAncestor(element, (node) => ts.isImportDeclaration(node));
|
|
3039
|
-
if (!importDeclaration) return;
|
|
3040
|
-
if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) return;
|
|
3041
|
-
const importClause = importDeclaration.importClause;
|
|
3042
|
-
if (!importClause) return;
|
|
3043
|
-
const namedBindings = importClause.namedBindings;
|
|
3044
|
-
if (!namedBindings) return;
|
|
3045
|
-
if (!ts.isNamedImports(namedBindings)) return;
|
|
3046
|
-
const barrelModuleName = importDeclaration.moduleSpecifier.text;
|
|
3047
|
-
if (languageServicePluginOptions2.namespaceImportPackages.indexOf(barrelModuleName.toLowerCase()) === -1) return;
|
|
3048
|
-
const moduleSymbol = resolveExternalModuleName(importDeclaration.moduleSpecifier);
|
|
3049
|
-
if (!moduleSymbol) return;
|
|
3050
|
-
if (!moduleSymbol.exports) return;
|
|
3051
|
-
const sourceFile2 = importDeclaration.getSourceFile();
|
|
3052
|
-
const nodeForSymbol = element.propertyName || element.name;
|
|
3053
|
-
if (!ts.isIdentifier(nodeForSymbol)) return;
|
|
3054
|
-
const importedName = nodeForSymbol.text;
|
|
3055
|
-
const reexportedSymbol = moduleSymbol.exports.get(ts.escapeLeadingUnderscores(importedName));
|
|
3056
|
-
if (!reexportedSymbol) return;
|
|
3057
|
-
if (!(reexportedSymbol.declarations && reexportedSymbol.declarations.length === 1)) return;
|
|
3058
|
-
const namespaceExport = reexportedSymbol.declarations[0];
|
|
3059
|
-
if (!ts.isNamespaceExport(namespaceExport)) return;
|
|
3060
|
-
const exportDeclaration = namespaceExport.parent;
|
|
3061
|
-
if (!ts.isExportDeclaration(exportDeclaration)) return;
|
|
3062
|
-
if (!exportDeclaration.moduleSpecifier) return;
|
|
3063
|
-
const originalModuleSymbol = resolveExternalModuleName(exportDeclaration.moduleSpecifier);
|
|
3064
|
-
if (!originalModuleSymbol) return;
|
|
3065
|
-
if (!originalModuleSymbol.valueDeclaration) return;
|
|
3066
|
-
const originalSourceFile = originalModuleSymbol.valueDeclaration.getSourceFile();
|
|
3067
|
-
const unbarrelledFileName = getModuleSpecifier(
|
|
3068
|
-
program.getCompilerOptions(),
|
|
3069
|
-
sourceFile2,
|
|
3070
|
-
sourceFile2.fileName,
|
|
3071
|
-
originalSourceFile.fileName,
|
|
3072
|
-
program
|
|
3073
|
-
);
|
|
3074
|
-
if (unbarrelledFileName.toLowerCase().indexOf(barrelModuleName.toLowerCase() + "/") === -1) return;
|
|
3075
|
-
return { unbarrelledFileName, importedName, barrelModuleName, importClause, namedBindings, importDeclaration };
|
|
2945
|
+
const typeParser = yield* service(TypeParser);
|
|
2946
|
+
const nodeToVisit = [];
|
|
2947
|
+
const appendNodeToVisit = (node) => {
|
|
2948
|
+
nodeToVisit.push(node);
|
|
2949
|
+
return void 0;
|
|
3076
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();
|
|
3077
3011
|
const nodeToVisit = [];
|
|
3078
3012
|
const appendNodeToVisit = (node) => {
|
|
3079
3013
|
nodeToVisit.push(node);
|
|
@@ -3082,125 +3016,136 @@ var importFromBarrel = createDiagnostic({
|
|
|
3082
3016
|
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3083
3017
|
while (nodeToVisit.length > 0) {
|
|
3084
3018
|
const node = nodeToVisit.shift();
|
|
3085
|
-
|
|
3086
|
-
if (
|
|
3087
|
-
ts.
|
|
3088
|
-
|
|
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
|
+
}
|
|
3089
3040
|
}
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
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
|
+
}] : [];
|
|
3093
3065
|
report({
|
|
3094
3066
|
node,
|
|
3095
|
-
messageText: `
|
|
3096
|
-
fixes:
|
|
3097
|
-
{
|
|
3098
|
-
fixName: "replaceWithUnbarrelledImport",
|
|
3099
|
-
description: `Import * as ${importedName} from ${unbarrelledFileName}`,
|
|
3100
|
-
apply: gen(function* () {
|
|
3101
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
3102
|
-
const newImport = ts.factory.createImportDeclaration(
|
|
3103
|
-
void 0,
|
|
3104
|
-
ts.factory.createImportClause(
|
|
3105
|
-
importClause.isTypeOnly || node.isTypeOnly,
|
|
3106
|
-
void 0,
|
|
3107
|
-
ts.factory.createNamespaceImport(ts.factory.createIdentifier(importedName))
|
|
3108
|
-
),
|
|
3109
|
-
ts.factory.createStringLiteral(unbarrelledFileName)
|
|
3110
|
-
);
|
|
3111
|
-
if (namedBindings.elements.length === 1) {
|
|
3112
|
-
changeTracker.replaceNode(
|
|
3113
|
-
sourceFile,
|
|
3114
|
-
importDeclaration,
|
|
3115
|
-
newImport
|
|
3116
|
-
);
|
|
3117
|
-
} else {
|
|
3118
|
-
changeTracker.insertNodeAfter(sourceFile, importDeclaration, newImport);
|
|
3119
|
-
changeTracker.replaceNode(
|
|
3120
|
-
sourceFile,
|
|
3121
|
-
namedBindings,
|
|
3122
|
-
ts.factory.updateNamedImports(
|
|
3123
|
-
namedBindings,
|
|
3124
|
-
namedBindings.elements.filter((e) => e !== node)
|
|
3125
|
-
)
|
|
3126
|
-
);
|
|
3127
|
-
}
|
|
3128
|
-
})
|
|
3129
|
-
}
|
|
3130
|
-
]
|
|
3067
|
+
messageText: `When yielding Effects inside Effect.gen, you should use yield* instead of yield.`,
|
|
3068
|
+
fixes: fix
|
|
3131
3069
|
});
|
|
3132
|
-
}
|
|
3070
|
+
});
|
|
3133
3071
|
})
|
|
3134
3072
|
});
|
|
3135
3073
|
|
|
3136
|
-
// src/diagnostics/
|
|
3137
|
-
var
|
|
3138
|
-
name: "
|
|
3139
|
-
code:
|
|
3074
|
+
// src/diagnostics/returnEffectInGen.ts
|
|
3075
|
+
var returnEffectInGen = createDiagnostic({
|
|
3076
|
+
name: "returnEffectInGen",
|
|
3077
|
+
code: 11,
|
|
3140
3078
|
severity: "suggestion",
|
|
3141
|
-
apply: fn("
|
|
3079
|
+
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
3142
3080
|
const ts = yield* service(TypeScriptApi);
|
|
3143
3081
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3144
3082
|
const typeParser = yield* service(TypeParser);
|
|
3145
|
-
const
|
|
3146
|
-
const
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
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;
|
|
3157
3104
|
yield* pipe(
|
|
3158
|
-
typeParser.
|
|
3159
|
-
|
|
3160
|
-
orElse2(() =>
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
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
|
+
});
|
|
3171
3131
|
}),
|
|
3172
3132
|
ignore
|
|
3173
3133
|
);
|
|
3174
|
-
if (effectContextType) {
|
|
3175
|
-
effectMembers++;
|
|
3176
|
-
const { allIndexes } = yield* appendToUniqueTypesMap(memory, effectContextType, true);
|
|
3177
|
-
if (!sharedRequirementsKeys) {
|
|
3178
|
-
sharedRequirementsKeys = allIndexes;
|
|
3179
|
-
} else {
|
|
3180
|
-
sharedRequirementsKeys = intersection(sharedRequirementsKeys, allIndexes);
|
|
3181
|
-
if (sharedRequirementsKeys.length === 0) return [];
|
|
3182
|
-
}
|
|
3183
|
-
}
|
|
3184
|
-
}
|
|
3185
|
-
if (sharedRequirementsKeys && sharedRequirementsKeys.length > 0 && effectMembers >= 2) {
|
|
3186
|
-
return sharedRequirementsKeys.map((key) => memory.get(key));
|
|
3187
3134
|
}
|
|
3188
|
-
return [];
|
|
3189
3135
|
}
|
|
3190
|
-
|
|
3191
|
-
"leakingServices.checkServiceLeaking",
|
|
3192
|
-
(_, service2) => service2
|
|
3193
|
-
);
|
|
3194
|
-
function reportLeakingRequirements(node, requirements) {
|
|
3195
|
-
if (requirements.length === 0) return;
|
|
3196
|
-
report({
|
|
3197
|
-
node,
|
|
3198
|
-
messageText: `This Service is leaking the ${requirements.map((_) => typeChecker.typeToString(_)).join(" | ")} requirement.
|
|
3199
|
-
If these requirements cannot be cached and are expected to be provided per method invocation (e.g. HttpServerRequest), you can safely disable this diagnostic for this line through quickfixes.
|
|
3200
|
-
More info at https://effect.website/docs/requirements-management/layers/#avoiding-requirement-leakage`,
|
|
3201
|
-
fixes: []
|
|
3202
|
-
});
|
|
3136
|
+
}
|
|
3203
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);
|
|
3204
3149
|
const nodeToVisit = [];
|
|
3205
3150
|
const appendNodeToVisit = (node) => {
|
|
3206
3151
|
nodeToVisit.push(node);
|
|
@@ -3209,29 +3154,26 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
3209
3154
|
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3210
3155
|
while (nodeToVisit.length > 0) {
|
|
3211
3156
|
const node = nodeToVisit.shift();
|
|
3212
|
-
|
|
3213
|
-
if (ts.isCallExpression(node)
|
|
3214
|
-
typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
|
|
3215
|
-
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
3216
|
-
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
3217
|
-
if (classSym) {
|
|
3218
|
-
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
3219
|
-
typesToCheck.push([type, node.name]);
|
|
3220
|
-
}
|
|
3221
|
-
} else {
|
|
3222
|
-
ts.forEachChild(node, appendNodeToVisit);
|
|
3223
|
-
continue;
|
|
3224
|
-
}
|
|
3225
|
-
for (const [type, reportAt] of typesToCheck) {
|
|
3157
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3158
|
+
if (ts.isCallExpression(node)) {
|
|
3226
3159
|
yield* pipe(
|
|
3227
|
-
typeParser.
|
|
3228
|
-
|
|
3229
|
-
({
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
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
|
+
})
|
|
3233
3176
|
),
|
|
3234
|
-
orElse2(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
3235
3177
|
ignore
|
|
3236
3178
|
);
|
|
3237
3179
|
}
|
|
@@ -3239,47 +3181,44 @@ More info at https://effect.website/docs/requirements-management/layers/#avoidin
|
|
|
3239
3181
|
})
|
|
3240
3182
|
});
|
|
3241
3183
|
|
|
3242
|
-
// src/diagnostics/
|
|
3243
|
-
var
|
|
3244
|
-
name: "
|
|
3245
|
-
code:
|
|
3246
|
-
severity: "
|
|
3247
|
-
apply: fn("
|
|
3248
|
-
const
|
|
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) {
|
|
3190
|
+
const ts = yield* service(TypeScriptApi);
|
|
3249
3191
|
const typeParser = yield* service(TypeParser);
|
|
3250
|
-
const
|
|
3251
|
-
const
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
)
|
|
3261
|
-
)
|
|
3262
|
-
);
|
|
3263
|
-
const sortTypes = sort(typeOrder);
|
|
3264
|
-
const entries = yield* expectedAndRealType(sourceFile);
|
|
3265
|
-
for (const [node, expectedType, valueNode, realType] of entries) {
|
|
3266
|
-
if (expectedType !== realType) {
|
|
3192
|
+
const nodeToVisit = [];
|
|
3193
|
+
const appendNodeToVisit = (node) => {
|
|
3194
|
+
nodeToVisit.push(node);
|
|
3195
|
+
return void 0;
|
|
3196
|
+
};
|
|
3197
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3198
|
+
while (nodeToVisit.length > 0) {
|
|
3199
|
+
const node = nodeToVisit.shift();
|
|
3200
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3201
|
+
if (ts.isCallExpression(node)) {
|
|
3267
3202
|
yield* pipe(
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
realType
|
|
3273
|
-
),
|
|
3274
|
-
map4(
|
|
3275
|
-
(missingTypes) => missingTypes.length > 0 ? report(
|
|
3276
|
-
{
|
|
3203
|
+
typeParser.pipeCall(node),
|
|
3204
|
+
map4(({ args, subject }) => {
|
|
3205
|
+
if (args.length === 0) {
|
|
3206
|
+
report({
|
|
3277
3207
|
node,
|
|
3278
|
-
messageText: `
|
|
3279
|
-
fixes: [
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3208
|
+
messageText: `This pipe call contains no arguments.`,
|
|
3209
|
+
fixes: [{
|
|
3210
|
+
fixName: "unnecessaryPipe_fix",
|
|
3211
|
+
description: "Remove the pipe call",
|
|
3212
|
+
apply: gen(function* () {
|
|
3213
|
+
const textChanges = yield* service(
|
|
3214
|
+
ChangeTracker
|
|
3215
|
+
);
|
|
3216
|
+
textChanges.replaceNode(sourceFile, node, subject);
|
|
3217
|
+
})
|
|
3218
|
+
}]
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
}),
|
|
3283
3222
|
ignore
|
|
3284
3223
|
);
|
|
3285
3224
|
}
|
|
@@ -3287,361 +3226,468 @@ var missingEffectContext = createDiagnostic({
|
|
|
3287
3226
|
})
|
|
3288
3227
|
});
|
|
3289
3228
|
|
|
3290
|
-
// src/diagnostics
|
|
3291
|
-
var
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
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
|
|
3392
|
+
}
|
|
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
|
+
}]);
|
|
3409
|
+
})
|
|
3410
|
+
});
|
|
3411
|
+
|
|
3412
|
+
// src/completions/genFunctionStar.ts
|
|
3413
|
+
var genFunctionStar = createCompletion({
|
|
3414
|
+
name: "genFunctionStar",
|
|
3415
|
+
apply: fn("genFunctionStar")(function* (sourceFile, position) {
|
|
3416
|
+
const ts = yield* service(TypeScriptApi);
|
|
3296
3417
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
3297
|
-
const
|
|
3298
|
-
|
|
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
|
-
)
|
|
3418
|
+
const maybeInfos = yield* option(
|
|
3419
|
+
parseAccessedExpressionForCompletion(sourceFile, position)
|
|
3310
3420
|
);
|
|
3311
|
-
|
|
3312
|
-
const
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
) : void 0
|
|
3330
|
-
),
|
|
3331
|
-
ignore
|
|
3332
|
-
);
|
|
3333
|
-
}
|
|
3334
|
-
}
|
|
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
|
+
}];
|
|
3335
3439
|
})
|
|
3336
3440
|
});
|
|
3337
3441
|
|
|
3338
|
-
// src/
|
|
3339
|
-
var
|
|
3340
|
-
name: "
|
|
3341
|
-
|
|
3342
|
-
severity: "error",
|
|
3343
|
-
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
3442
|
+
// src/completions/rpcMakeClasses.ts
|
|
3443
|
+
var rpcMakeClasses = createCompletion({
|
|
3444
|
+
name: "rpcMakeClasses",
|
|
3445
|
+
apply: fn("rpcMakeClasses")(function* (sourceFile, position) {
|
|
3344
3446
|
const ts = yield* service(TypeScriptApi);
|
|
3345
|
-
const
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
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",
|
|
3377
|
-
apply: gen(function* () {
|
|
3378
|
-
const changeTracker = yield* service(ChangeTracker);
|
|
3379
|
-
changeTracker.replaceNode(
|
|
3380
|
-
sourceFile,
|
|
3381
|
-
node,
|
|
3382
|
-
ts.factory.createReturnStatement(
|
|
3383
|
-
node
|
|
3384
|
-
)
|
|
3385
|
-
);
|
|
3386
|
-
})
|
|
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
|
-
}
|
|
3394
|
-
}
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
}
|
|
3398
|
-
}
|
|
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
|
+
}];
|
|
3399
3472
|
})
|
|
3400
3473
|
});
|
|
3401
3474
|
|
|
3402
|
-
// src/
|
|
3403
|
-
var
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
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
|
+
const barreledModulePathByFileName = /* @__PURE__ */ new Map();
|
|
3498
|
+
for (const packageName of languageServicePluginOptions.namespaceImportPackages) {
|
|
3499
|
+
const barrelModule = ts.resolveModuleName(packageName, sourceFile.fileName, program.getCompilerOptions(), host);
|
|
3500
|
+
if (barrelModule.resolvedModule) {
|
|
3501
|
+
const barrelPath = barrelModule.resolvedModule.resolvedFileName;
|
|
3502
|
+
const barrelSource = program.getSourceFile(barrelPath) || ts.createSourceFile(barrelPath, host.readFile(barrelPath) || "", sourceFile.languageVersion, true);
|
|
3503
|
+
if (barrelSource) {
|
|
3504
|
+
for (const statement of barrelSource.statements) {
|
|
3505
|
+
if (ts.isExportDeclaration(statement)) {
|
|
3506
|
+
const exportClause = statement.exportClause;
|
|
3507
|
+
const moduleSpecifier = statement.moduleSpecifier;
|
|
3508
|
+
if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
|
|
3509
|
+
const unbarreledModulePathResolved = ts.resolveModuleName(
|
|
3510
|
+
moduleSpecifier.text,
|
|
3511
|
+
barrelSource.fileName,
|
|
3512
|
+
program.getCompilerOptions(),
|
|
3513
|
+
host
|
|
3514
|
+
);
|
|
3515
|
+
if (unbarreledModulePathResolved.resolvedModule) {
|
|
3516
|
+
const unbarreledModulePath = unbarreledModulePathResolved.resolvedModule.resolvedFileName;
|
|
3517
|
+
if (exportClause && ts.isNamespaceExport(exportClause) && ts.isIdentifier(exportClause.name)) {
|
|
3518
|
+
namespaceByFileName.set(unbarreledModulePath, exportClause.name.text);
|
|
3519
|
+
const existingUnbarreledModulePath = unbarreledModulePathByFileName.get(barrelSource.fileName) || [];
|
|
3520
|
+
existingUnbarreledModulePath.push({
|
|
3521
|
+
fileName: unbarreledModulePath,
|
|
3522
|
+
exportName: exportClause.name.text
|
|
3523
|
+
});
|
|
3524
|
+
unbarreledModulePathByFileName.set(barrelSource.fileName, existingUnbarreledModulePath);
|
|
3525
|
+
barreledModulePathByFileName.set(unbarreledModulePath, {
|
|
3526
|
+
fileName: barrelSource.fileName,
|
|
3527
|
+
exportName: exportClause.name.text
|
|
3528
|
+
});
|
|
3529
|
+
}
|
|
3530
|
+
if (exportClause && ts.isNamedExports(exportClause)) {
|
|
3531
|
+
for (const element of exportClause.elements) {
|
|
3532
|
+
if (!ts.isIdentifier(element.name)) continue;
|
|
3533
|
+
const methodName = element.name.text;
|
|
3534
|
+
const excludedMethods = excludedByFileName.get(methodName) || [];
|
|
3535
|
+
excludedMethods.push(unbarreledModulePath);
|
|
3536
|
+
excludedByFileName.set(methodName, excludedMethods);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3435
3539
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
ignore
|
|
3439
|
-
);
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3440
3542
|
}
|
|
3441
3543
|
}
|
|
3442
3544
|
}
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
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
|
-
});
|
|
3472
|
-
})
|
|
3545
|
+
}
|
|
3546
|
+
return {
|
|
3547
|
+
getImportNamespaceByFileName: (fileName) => namespaceByFileName.get(fileName),
|
|
3548
|
+
isExcludedFromNamespaceImport: (fileName, exportName) => (excludedByFileName.get(exportName) || []).includes(fileName),
|
|
3549
|
+
getUnbarreledModulePath: (fileName, exportName) => unbarreledModulePathByFileName.get(fileName)?.find((_) => _.exportName === exportName)?.fileName,
|
|
3550
|
+
getBarreledModulePath: (fileName) => barreledModulePathByFileName.get(fileName)
|
|
3551
|
+
};
|
|
3473
3552
|
});
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
if (
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
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
|
-
);
|
|
3553
|
+
var appendEffectCompletionEntryData = fn("appendEffectCompletionEntryData")(
|
|
3554
|
+
function* (_sourceFile, applicableCompletions) {
|
|
3555
|
+
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
3556
|
+
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletions;
|
|
3557
|
+
if (applicableCompletions) {
|
|
3558
|
+
return {
|
|
3559
|
+
...applicableCompletions,
|
|
3560
|
+
entries: applicableCompletions.entries.map(
|
|
3561
|
+
(entry) => entry.data ? {
|
|
3562
|
+
...entry,
|
|
3563
|
+
data: {
|
|
3564
|
+
...entry.data,
|
|
3565
|
+
effectReplaceSpan: entry.replacementSpan || applicableCompletions.optionalReplacementSpan
|
|
3566
|
+
}
|
|
3567
|
+
} : entry
|
|
3568
|
+
)
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
return applicableCompletions;
|
|
3572
|
+
}
|
|
3573
|
+
);
|
|
3574
|
+
var postprocessCompletionEntryDetails = fn("postprocessCompletionEntryDetails")(
|
|
3575
|
+
function* (sourceFile, data, applicableCompletionEntryDetails, formatOptions, preferences, languageServiceHost) {
|
|
3576
|
+
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
3577
|
+
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return applicableCompletionEntryDetails;
|
|
3578
|
+
const isAutoImportOnlyCodeActions = fn("isAutoImportOnlyCodeActions")(
|
|
3579
|
+
function* (codeActions, exportName2) {
|
|
3580
|
+
if (!codeActions) return;
|
|
3581
|
+
if (codeActions.length !== 1) return;
|
|
3582
|
+
const action = codeActions[0];
|
|
3583
|
+
const changes2 = action.changes;
|
|
3584
|
+
if (changes2.length !== 1) return;
|
|
3585
|
+
const fileTextChanges = action.changes[0];
|
|
3586
|
+
if (fileTextChanges.fileName !== sourceFile.fileName) return;
|
|
3587
|
+
const textChanges = fileTextChanges.textChanges;
|
|
3588
|
+
if (textChanges.length !== 1) return;
|
|
3589
|
+
const change = textChanges[0];
|
|
3590
|
+
if (change.newText.trim().toLowerCase().startsWith("import") && change.newText.indexOf(exportName2) > -1) {
|
|
3591
|
+
return {
|
|
3592
|
+
type: "create"
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
if (change.newText.indexOf(exportName2) > -1) {
|
|
3596
|
+
const ancestorNodes = yield* getAncestorNodesInRange(sourceFile, {
|
|
3597
|
+
pos: change.span.start,
|
|
3598
|
+
end: change.span.start
|
|
3599
|
+
});
|
|
3600
|
+
const importNodes = ancestorNodes.filter((node) => ts.isImportDeclaration(node));
|
|
3601
|
+
if (importNodes.length > 0) {
|
|
3602
|
+
return {
|
|
3603
|
+
type: "update"
|
|
3604
|
+
};
|
|
3535
3605
|
}
|
|
3536
3606
|
}
|
|
3537
3607
|
}
|
|
3538
|
-
|
|
3539
|
-
})
|
|
3540
|
-
});
|
|
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) {
|
|
3608
|
+
);
|
|
3548
3609
|
const ts = yield* service(TypeScriptApi);
|
|
3549
|
-
const
|
|
3550
|
-
const
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
};
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3610
|
+
const program = yield* service(TypeScriptProgram);
|
|
3611
|
+
const getModuleSpecifier = makeGetModuleSpecifier(ts);
|
|
3612
|
+
if (!getModuleSpecifier) return applicableCompletionEntryDetails;
|
|
3613
|
+
if (!applicableCompletionEntryDetails) return applicableCompletionEntryDetails;
|
|
3614
|
+
if (!data) return applicableCompletionEntryDetails;
|
|
3615
|
+
const { exportName, fileName, moduleSpecifier } = data;
|
|
3616
|
+
if (!fileName) return applicableCompletionEntryDetails;
|
|
3617
|
+
if (!exportName) return applicableCompletionEntryDetails;
|
|
3618
|
+
if (!moduleSpecifier) return applicableCompletionEntryDetails;
|
|
3619
|
+
if (!("effectReplaceSpan" in data)) return applicableCompletionEntryDetails;
|
|
3620
|
+
const effectReplaceSpan = data.effectReplaceSpan;
|
|
3621
|
+
const result = yield* isAutoImportOnlyCodeActions(applicableCompletionEntryDetails.codeActions, exportName);
|
|
3622
|
+
if (!result) return applicableCompletionEntryDetails;
|
|
3623
|
+
const packagesMetadata = importablePackagesMetadataCache.get(sourceFile.fileName) || (yield* makeImportablePackagesMetadata(sourceFile));
|
|
3624
|
+
importablePackagesMetadataCache.set(sourceFile.fileName, packagesMetadata);
|
|
3625
|
+
const formatContext = ts.formatting.getFormatContext(
|
|
3626
|
+
formatOptions || {},
|
|
3627
|
+
languageServiceHost
|
|
3628
|
+
);
|
|
3629
|
+
const isExcluded = packagesMetadata.isExcludedFromNamespaceImport(
|
|
3630
|
+
fileName,
|
|
3631
|
+
exportName
|
|
3632
|
+
);
|
|
3633
|
+
if (isExcluded) return applicableCompletionEntryDetails;
|
|
3634
|
+
const effectUnbarreledModulePath = packagesMetadata.getUnbarreledModulePath(
|
|
3635
|
+
fileName,
|
|
3636
|
+
exportName
|
|
3637
|
+
);
|
|
3638
|
+
const effectNamespaceName = packagesMetadata.getImportNamespaceByFileName(
|
|
3639
|
+
effectUnbarreledModulePath || fileName
|
|
3640
|
+
);
|
|
3641
|
+
if (!effectNamespaceName) return applicableCompletionEntryDetails;
|
|
3642
|
+
const newModuleSpecifier = effectUnbarreledModulePath ? getModuleSpecifier(
|
|
3643
|
+
program.getCompilerOptions(),
|
|
3644
|
+
sourceFile,
|
|
3645
|
+
sourceFile.fileName,
|
|
3646
|
+
String(effectUnbarreledModulePath || fileName),
|
|
3647
|
+
program
|
|
3648
|
+
) : moduleSpecifier;
|
|
3649
|
+
const changes = ts.textChanges.ChangeTracker.with(
|
|
3650
|
+
{
|
|
3651
|
+
formatContext,
|
|
3652
|
+
host: languageServiceHost,
|
|
3653
|
+
preferences: preferences || {}
|
|
3654
|
+
},
|
|
3655
|
+
(changeTracker) => {
|
|
3656
|
+
ts.insertImports(
|
|
3657
|
+
changeTracker,
|
|
3658
|
+
sourceFile,
|
|
3659
|
+
ts.factory.createImportDeclaration(
|
|
3660
|
+
void 0,
|
|
3661
|
+
ts.factory.createImportClause(
|
|
3662
|
+
false,
|
|
3663
|
+
void 0,
|
|
3664
|
+
ts.factory.createNamespaceImport(ts.factory.createIdentifier(effectNamespaceName))
|
|
3665
|
+
),
|
|
3666
|
+
ts.factory.createStringLiteral(newModuleSpecifier)
|
|
3577
3667
|
),
|
|
3578
|
-
|
|
3668
|
+
true,
|
|
3669
|
+
preferences || {}
|
|
3579
3670
|
);
|
|
3671
|
+
if (!effectUnbarreledModulePath) {
|
|
3672
|
+
changeTracker.insertText(
|
|
3673
|
+
sourceFile,
|
|
3674
|
+
effectReplaceSpan.start,
|
|
3675
|
+
effectNamespaceName + "."
|
|
3676
|
+
);
|
|
3677
|
+
}
|
|
3580
3678
|
}
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
3591
|
-
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;
|
|
3679
|
+
);
|
|
3680
|
+
return {
|
|
3681
|
+
...applicableCompletionEntryDetails,
|
|
3682
|
+
codeActions: [
|
|
3683
|
+
{
|
|
3684
|
+
description: "Import * as " + effectNamespaceName + " from " + newModuleSpecifier,
|
|
3685
|
+
changes
|
|
3686
|
+
}
|
|
3687
|
+
]
|
|
3597
3688
|
};
|
|
3598
|
-
|
|
3599
|
-
|
|
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
|
-
});
|
|
3621
|
-
}
|
|
3622
|
-
}),
|
|
3623
|
-
ignore
|
|
3624
|
-
);
|
|
3625
|
-
}
|
|
3626
|
-
}
|
|
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
|
-
];
|
|
3689
|
+
}
|
|
3690
|
+
);
|
|
3645
3691
|
|
|
3646
3692
|
// src/goto/effectRpcDefinition.ts
|
|
3647
3693
|
function effectRpcDefinition(applicableGotoDefinition, sourceFile, position) {
|