@effect/language-service 0.84.0 → 0.84.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cli.js +91 -16
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +86 -12
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +86 -12
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/schema.json +1 -1
- package/transform.js +86 -12
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -3771,10 +3771,42 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3771
3771
|
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
3772
3772
|
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
3773
3773
|
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
3774
|
+
if (isInsideTypeOnlyHeritageExpression(node)) return;
|
|
3774
3775
|
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
3775
3776
|
return typeChecker.getTypeAtLocation(node);
|
|
3776
3777
|
}
|
|
3777
3778
|
}
|
|
3779
|
+
function isInsideTypeOnlyHeritageExpression(node) {
|
|
3780
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
3781
|
+
return isTypeOnlyHeritageClause(node.parent);
|
|
3782
|
+
}
|
|
3783
|
+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
|
|
3784
|
+
return false;
|
|
3785
|
+
}
|
|
3786
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
3787
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3790
|
+
if (ts.isExpressionWithTypeArguments(current)) {
|
|
3791
|
+
return isTypeOnlyHeritageClause(current.parent);
|
|
3792
|
+
}
|
|
3793
|
+
return false;
|
|
3794
|
+
}
|
|
3795
|
+
return false;
|
|
3796
|
+
}
|
|
3797
|
+
function isTypeOnlyHeritageClause(node) {
|
|
3798
|
+
if (!node || !ts.isHeritageClause(node)) {
|
|
3799
|
+
return false;
|
|
3800
|
+
}
|
|
3801
|
+
const container = node.parent;
|
|
3802
|
+
if (!container) {
|
|
3803
|
+
return false;
|
|
3804
|
+
}
|
|
3805
|
+
if (ts.isInterfaceDeclaration(container)) {
|
|
3806
|
+
return true;
|
|
3807
|
+
}
|
|
3808
|
+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword;
|
|
3809
|
+
}
|
|
3778
3810
|
function resolveToGlobalSymbol(symbol3) {
|
|
3779
3811
|
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3780
3812
|
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
@@ -7751,12 +7783,14 @@ var getParameterName = (typescript, name) => {
|
|
|
7751
7783
|
}
|
|
7752
7784
|
return "parameter";
|
|
7753
7785
|
};
|
|
7754
|
-
var hasOuterContextualFunctionType = (typescript, typeChecker, node) => {
|
|
7786
|
+
var hasOuterContextualFunctionType = (typescript, typeChecker, typeCheckerUtils, node) => {
|
|
7755
7787
|
const contextualType = typeChecker.getContextualType(node);
|
|
7756
7788
|
if (!contextualType) {
|
|
7757
7789
|
return false;
|
|
7758
7790
|
}
|
|
7759
|
-
return
|
|
7791
|
+
return typeCheckerUtils.unrollUnionMembers(contextualType).some(
|
|
7792
|
+
(type) => typeChecker.getSignaturesOfType(type, typescript.SignatureKind.Call).length > 0
|
|
7793
|
+
);
|
|
7760
7794
|
};
|
|
7761
7795
|
var effectFnImplicitAny = createDiagnostic({
|
|
7762
7796
|
name: "effectFnImplicitAny",
|
|
@@ -7770,6 +7804,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
7770
7804
|
const ts = yield* service(TypeScriptApi);
|
|
7771
7805
|
const program = yield* service(TypeScriptProgram);
|
|
7772
7806
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7807
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7773
7808
|
const typeParser = yield* service(TypeParser);
|
|
7774
7809
|
const noImplicitAny = program.getCompilerOptions().noImplicitAny ?? program.getCompilerOptions().strict ?? false;
|
|
7775
7810
|
if (!noImplicitAny) {
|
|
@@ -7809,7 +7844,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
7809
7844
|
),
|
|
7810
7845
|
orUndefined
|
|
7811
7846
|
);
|
|
7812
|
-
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, parsed.call)) {
|
|
7847
|
+
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, typeCheckerUtils, parsed.call)) {
|
|
7813
7848
|
continue;
|
|
7814
7849
|
}
|
|
7815
7850
|
for (const parameter of parsed.fn.parameters) {
|
|
@@ -11904,16 +11939,16 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
11904
11939
|
var runEffectInsideEffect = createDiagnostic({
|
|
11905
11940
|
name: "runEffectInsideEffect",
|
|
11906
11941
|
code: 32,
|
|
11907
|
-
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
11942
|
+
description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
|
|
11908
11943
|
group: "antipattern",
|
|
11909
11944
|
severity: "suggestion",
|
|
11910
11945
|
fixable: true,
|
|
11911
|
-
supportedEffect: ["v3"],
|
|
11946
|
+
supportedEffect: ["v3", "v4"],
|
|
11912
11947
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
11913
11948
|
const ts = yield* service(TypeScriptApi);
|
|
11914
11949
|
const typeParser = yield* service(TypeParser);
|
|
11915
11950
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
11916
|
-
|
|
11951
|
+
const supportedEffect = typeParser.supportedEffect();
|
|
11917
11952
|
const parseEffectMethod = (node, methodName) => pipe(
|
|
11918
11953
|
typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
|
|
11919
11954
|
map5(() => ({ node, methodName }))
|
|
@@ -11946,9 +11981,10 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11946
11981
|
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
11947
11982
|
const fixAddRuntime = gen(function* () {
|
|
11948
11983
|
const changeTracker = yield* service(ChangeTracker);
|
|
11949
|
-
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
11950
11984
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
11985
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
11951
11986
|
let runtimeIdentifier = void 0;
|
|
11987
|
+
let servicesIdentifier = void 0;
|
|
11952
11988
|
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
11953
11989
|
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
11954
11990
|
const declaration = statement.declarationList.declarations[0];
|
|
@@ -11962,11 +11998,46 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11962
11998
|
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
11963
11999
|
runtimeIdentifier = ts.idText(declaration.name);
|
|
11964
12000
|
}
|
|
12001
|
+
const maybeEffectServices = yield* pipe(
|
|
12002
|
+
typeParser.isNodeReferenceToEffectModuleApi("services")(yieldedExpression.expression),
|
|
12003
|
+
option
|
|
12004
|
+
);
|
|
12005
|
+
if (isSome2(maybeEffectServices) && ts.isIdentifier(declaration.name)) {
|
|
12006
|
+
servicesIdentifier = ts.idText(declaration.name);
|
|
12007
|
+
}
|
|
11965
12008
|
}
|
|
11966
12009
|
}
|
|
11967
12010
|
}
|
|
11968
12011
|
}
|
|
11969
|
-
if (!
|
|
12012
|
+
if (supportedEffect === "v4" && !servicesIdentifier) {
|
|
12013
|
+
changeTracker.insertNodeAt(
|
|
12014
|
+
sourceFile,
|
|
12015
|
+
effectGen.body.statements[0].pos,
|
|
12016
|
+
ts.factory.createVariableStatement(
|
|
12017
|
+
void 0,
|
|
12018
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
12019
|
+
"effectServices",
|
|
12020
|
+
void 0,
|
|
12021
|
+
void 0,
|
|
12022
|
+
ts.factory.createYieldExpression(
|
|
12023
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
12024
|
+
ts.factory.createCallExpression(
|
|
12025
|
+
ts.factory.createPropertyAccessExpression(
|
|
12026
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
12027
|
+
"services"
|
|
12028
|
+
),
|
|
12029
|
+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)],
|
|
12030
|
+
[]
|
|
12031
|
+
)
|
|
12032
|
+
)
|
|
12033
|
+
)], ts.NodeFlags.Const)
|
|
12034
|
+
),
|
|
12035
|
+
{
|
|
12036
|
+
prefix: "\n",
|
|
12037
|
+
suffix: "\n"
|
|
12038
|
+
}
|
|
12039
|
+
);
|
|
12040
|
+
} else if (supportedEffect === "v3" && !runtimeIdentifier) {
|
|
11970
12041
|
changeTracker.insertNodeAt(
|
|
11971
12042
|
sourceFile,
|
|
11972
12043
|
effectGen.body.statements[0].pos,
|
|
@@ -12002,16 +12073,19 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
12002
12073
|
changeTracker.insertText(
|
|
12003
12074
|
sourceFile,
|
|
12004
12075
|
node.arguments[0].pos,
|
|
12005
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
12076
|
+
supportedEffect === "v4" ? `${effectModuleIdentifier}.${isEffectRunCall.value.methodName}With(${servicesIdentifier || "effectServices"})(` : `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
12006
12077
|
);
|
|
12007
12078
|
});
|
|
12079
|
+
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
12080
|
+
const messageText = supportedEffect === "v4" ? `Using ${nodeText} inside an Effect is not recommended. The same services should generally be used instead to run child effects.
|
|
12081
|
+
Consider extracting the current services by using for example Effect.services and then use Effect.${v4MethodName} with the extracted services instead.` : `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
12082
|
+
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
12008
12083
|
report({
|
|
12009
12084
|
location: node.expression,
|
|
12010
|
-
messageText
|
|
12011
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
12085
|
+
messageText,
|
|
12012
12086
|
fixes: [{
|
|
12013
12087
|
fixName: "runEffectInsideEffect_fix",
|
|
12014
|
-
description: "Use a runtime to run the Effect",
|
|
12088
|
+
description: supportedEffect === "v4" ? "Use the current services to run the Effect" : "Use a runtime to run the Effect",
|
|
12015
12089
|
apply: fixAddRuntime
|
|
12016
12090
|
}]
|
|
12017
12091
|
});
|