@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/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -2757,7 +2757,7 @@
|
|
|
2757
2757
|
"suggestion"
|
|
2758
2758
|
],
|
|
2759
2759
|
"default": "suggestion",
|
|
2760
|
-
"description": "Suggests using Runtime methods instead of Effect.run* inside Effect contexts Default severity: suggestion."
|
|
2760
|
+
"description": "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts Default severity: suggestion."
|
|
2761
2761
|
},
|
|
2762
2762
|
"schemaStructWithTag": {
|
|
2763
2763
|
"type": "string",
|
package/transform.js
CHANGED
|
@@ -3118,10 +3118,42 @@ function makeTypeCheckerUtils(ts, typeChecker, tsUtils) {
|
|
|
3118
3118
|
if (node.parent && ts.isJsxOpeningElement(node.parent) && node.parent.tagName === node) return;
|
|
3119
3119
|
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return;
|
|
3120
3120
|
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return;
|
|
3121
|
+
if (isInsideTypeOnlyHeritageExpression(node)) return;
|
|
3121
3122
|
if (ts.isExpression(node) || ts.isTypeNode(node)) {
|
|
3122
3123
|
return typeChecker.getTypeAtLocation(node);
|
|
3123
3124
|
}
|
|
3124
3125
|
}
|
|
3126
|
+
function isInsideTypeOnlyHeritageExpression(node) {
|
|
3127
|
+
if (ts.isExpressionWithTypeArguments(node)) {
|
|
3128
|
+
return isTypeOnlyHeritageClause(node.parent);
|
|
3129
|
+
}
|
|
3130
|
+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
|
|
3131
|
+
return false;
|
|
3132
|
+
}
|
|
3133
|
+
for (let current = node.parent; current; current = current.parent) {
|
|
3134
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
if (ts.isExpressionWithTypeArguments(current)) {
|
|
3138
|
+
return isTypeOnlyHeritageClause(current.parent);
|
|
3139
|
+
}
|
|
3140
|
+
return false;
|
|
3141
|
+
}
|
|
3142
|
+
return false;
|
|
3143
|
+
}
|
|
3144
|
+
function isTypeOnlyHeritageClause(node) {
|
|
3145
|
+
if (!node || !ts.isHeritageClause(node)) {
|
|
3146
|
+
return false;
|
|
3147
|
+
}
|
|
3148
|
+
const container = node.parent;
|
|
3149
|
+
if (!container) {
|
|
3150
|
+
return false;
|
|
3151
|
+
}
|
|
3152
|
+
if (ts.isInterfaceDeclaration(container)) {
|
|
3153
|
+
return true;
|
|
3154
|
+
}
|
|
3155
|
+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword;
|
|
3156
|
+
}
|
|
3125
3157
|
function resolveToGlobalSymbol(symbol3) {
|
|
3126
3158
|
if (symbol3.flags & ts.SymbolFlags.Alias) {
|
|
3127
3159
|
symbol3 = typeChecker.getAliasedSymbol(symbol3);
|
|
@@ -5933,12 +5965,14 @@ var getParameterName = (typescript, name) => {
|
|
|
5933
5965
|
}
|
|
5934
5966
|
return "parameter";
|
|
5935
5967
|
};
|
|
5936
|
-
var hasOuterContextualFunctionType = (typescript, typeChecker, node) => {
|
|
5968
|
+
var hasOuterContextualFunctionType = (typescript, typeChecker, typeCheckerUtils, node) => {
|
|
5937
5969
|
const contextualType = typeChecker.getContextualType(node);
|
|
5938
5970
|
if (!contextualType) {
|
|
5939
5971
|
return false;
|
|
5940
5972
|
}
|
|
5941
|
-
return
|
|
5973
|
+
return typeCheckerUtils.unrollUnionMembers(contextualType).some(
|
|
5974
|
+
(type) => typeChecker.getSignaturesOfType(type, typescript.SignatureKind.Call).length > 0
|
|
5975
|
+
);
|
|
5942
5976
|
};
|
|
5943
5977
|
var effectFnImplicitAny = createDiagnostic({
|
|
5944
5978
|
name: "effectFnImplicitAny",
|
|
@@ -5952,6 +5986,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5952
5986
|
const ts = yield* service(TypeScriptApi);
|
|
5953
5987
|
const program = yield* service(TypeScriptProgram);
|
|
5954
5988
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
5989
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
5955
5990
|
const typeParser = yield* service(TypeParser);
|
|
5956
5991
|
const noImplicitAny = program.getCompilerOptions().noImplicitAny ?? program.getCompilerOptions().strict ?? false;
|
|
5957
5992
|
if (!noImplicitAny) {
|
|
@@ -5991,7 +6026,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
5991
6026
|
),
|
|
5992
6027
|
orUndefined
|
|
5993
6028
|
);
|
|
5994
|
-
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, parsed.call)) {
|
|
6029
|
+
if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, typeCheckerUtils, parsed.call)) {
|
|
5995
6030
|
continue;
|
|
5996
6031
|
}
|
|
5997
6032
|
for (const parameter of parsed.fn.parameters) {
|
|
@@ -11155,16 +11190,16 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
|
|
|
11155
11190
|
var runEffectInsideEffect = createDiagnostic({
|
|
11156
11191
|
name: "runEffectInsideEffect",
|
|
11157
11192
|
code: 32,
|
|
11158
|
-
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
11193
|
+
description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
|
|
11159
11194
|
group: "antipattern",
|
|
11160
11195
|
severity: "suggestion",
|
|
11161
11196
|
fixable: true,
|
|
11162
|
-
supportedEffect: ["v3"],
|
|
11197
|
+
supportedEffect: ["v3", "v4"],
|
|
11163
11198
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
11164
11199
|
const ts = yield* service(TypeScriptApi);
|
|
11165
11200
|
const typeParser = yield* service(TypeParser);
|
|
11166
11201
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
11167
|
-
|
|
11202
|
+
const supportedEffect = typeParser.supportedEffect();
|
|
11168
11203
|
const parseEffectMethod = (node, methodName) => pipe(
|
|
11169
11204
|
typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
|
|
11170
11205
|
map4(() => ({ node, methodName }))
|
|
@@ -11197,9 +11232,10 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11197
11232
|
if (scopeNode && scopeNode !== effectGen.generatorFunction) {
|
|
11198
11233
|
const fixAddRuntime = gen(function* () {
|
|
11199
11234
|
const changeTracker = yield* service(ChangeTracker);
|
|
11200
|
-
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
11201
11235
|
const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
|
|
11236
|
+
const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
|
|
11202
11237
|
let runtimeIdentifier = void 0;
|
|
11238
|
+
let servicesIdentifier = void 0;
|
|
11203
11239
|
for (const statement of effectGen.generatorFunction.body.statements) {
|
|
11204
11240
|
if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
|
|
11205
11241
|
const declaration = statement.declarationList.declarations[0];
|
|
@@ -11213,11 +11249,46 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11213
11249
|
if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
|
|
11214
11250
|
runtimeIdentifier = ts.idText(declaration.name);
|
|
11215
11251
|
}
|
|
11252
|
+
const maybeEffectServices = yield* pipe(
|
|
11253
|
+
typeParser.isNodeReferenceToEffectModuleApi("services")(yieldedExpression.expression),
|
|
11254
|
+
option
|
|
11255
|
+
);
|
|
11256
|
+
if (isSome2(maybeEffectServices) && ts.isIdentifier(declaration.name)) {
|
|
11257
|
+
servicesIdentifier = ts.idText(declaration.name);
|
|
11258
|
+
}
|
|
11216
11259
|
}
|
|
11217
11260
|
}
|
|
11218
11261
|
}
|
|
11219
11262
|
}
|
|
11220
|
-
if (!
|
|
11263
|
+
if (supportedEffect === "v4" && !servicesIdentifier) {
|
|
11264
|
+
changeTracker.insertNodeAt(
|
|
11265
|
+
sourceFile,
|
|
11266
|
+
effectGen.body.statements[0].pos,
|
|
11267
|
+
ts.factory.createVariableStatement(
|
|
11268
|
+
void 0,
|
|
11269
|
+
ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
|
|
11270
|
+
"effectServices",
|
|
11271
|
+
void 0,
|
|
11272
|
+
void 0,
|
|
11273
|
+
ts.factory.createYieldExpression(
|
|
11274
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
11275
|
+
ts.factory.createCallExpression(
|
|
11276
|
+
ts.factory.createPropertyAccessExpression(
|
|
11277
|
+
ts.factory.createIdentifier(effectModuleIdentifier),
|
|
11278
|
+
"services"
|
|
11279
|
+
),
|
|
11280
|
+
[ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)],
|
|
11281
|
+
[]
|
|
11282
|
+
)
|
|
11283
|
+
)
|
|
11284
|
+
)], ts.NodeFlags.Const)
|
|
11285
|
+
),
|
|
11286
|
+
{
|
|
11287
|
+
prefix: "\n",
|
|
11288
|
+
suffix: "\n"
|
|
11289
|
+
}
|
|
11290
|
+
);
|
|
11291
|
+
} else if (supportedEffect === "v3" && !runtimeIdentifier) {
|
|
11221
11292
|
changeTracker.insertNodeAt(
|
|
11222
11293
|
sourceFile,
|
|
11223
11294
|
effectGen.body.statements[0].pos,
|
|
@@ -11253,16 +11324,19 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
11253
11324
|
changeTracker.insertText(
|
|
11254
11325
|
sourceFile,
|
|
11255
11326
|
node.arguments[0].pos,
|
|
11256
|
-
`${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
11327
|
+
supportedEffect === "v4" ? `${effectModuleIdentifier}.${isEffectRunCall.value.methodName}With(${servicesIdentifier || "effectServices"})(` : `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
|
|
11257
11328
|
);
|
|
11258
11329
|
});
|
|
11330
|
+
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
11331
|
+
const messageText = supportedEffect === "v4" ? `Using ${nodeText} inside an Effect is not recommended. The same services should generally be used instead to run child effects.
|
|
11332
|
+
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.
|
|
11333
|
+
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
11259
11334
|
report({
|
|
11260
11335
|
location: node.expression,
|
|
11261
|
-
messageText
|
|
11262
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
|
|
11336
|
+
messageText,
|
|
11263
11337
|
fixes: [{
|
|
11264
11338
|
fixName: "runEffectInsideEffect_fix",
|
|
11265
|
-
description: "Use a runtime to run the Effect",
|
|
11339
|
+
description: supportedEffect === "v4" ? "Use the current services to run the Effect" : "Use a runtime to run the Effect",
|
|
11266
11340
|
apply: fixAddRuntime
|
|
11267
11341
|
}]
|
|
11268
11342
|
});
|