@effect/language-service 0.21.3 → 0.21.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +124 -2
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +124 -2
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -2939,6 +2939,54 @@ var floatingEffect = createDiagnostic({
|
|
|
2939
2939
|
})
|
|
2940
2940
|
});
|
|
2941
2941
|
|
|
2942
|
+
// src/diagnostics/genericEffectServices.ts
|
|
2943
|
+
var genericEffectServices = createDiagnostic({
|
|
2944
|
+
name: "genericEffectServices",
|
|
2945
|
+
code: 10,
|
|
2946
|
+
apply: fn("genericEffectServices.apply")(function* (sourceFile) {
|
|
2947
|
+
const ts = yield* service(TypeScriptApi);
|
|
2948
|
+
const typeParser = yield* service(TypeParser);
|
|
2949
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2950
|
+
const effectDiagnostics = [];
|
|
2951
|
+
const nodeToVisit = [];
|
|
2952
|
+
const appendNodeToVisit = (node) => {
|
|
2953
|
+
nodeToVisit.push(node);
|
|
2954
|
+
return void 0;
|
|
2955
|
+
};
|
|
2956
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2957
|
+
while (nodeToVisit.length > 0) {
|
|
2958
|
+
const node = nodeToVisit.shift();
|
|
2959
|
+
const typesToCheck = [];
|
|
2960
|
+
if (ts.isClassDeclaration(node) && node.name && node.typeParameters && node.heritageClauses) {
|
|
2961
|
+
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2962
|
+
if (classSym) {
|
|
2963
|
+
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
2964
|
+
typesToCheck.push([type, node.name]);
|
|
2965
|
+
}
|
|
2966
|
+
} else {
|
|
2967
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2968
|
+
continue;
|
|
2969
|
+
}
|
|
2970
|
+
for (const [type, reportAt] of typesToCheck) {
|
|
2971
|
+
yield* pipe(
|
|
2972
|
+
typeParser.contextTag(type, node),
|
|
2973
|
+
map4(() => {
|
|
2974
|
+
effectDiagnostics.push({
|
|
2975
|
+
node: reportAt,
|
|
2976
|
+
category: ts.DiagnosticCategory.Warning,
|
|
2977
|
+
messageText: `Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior.`,
|
|
2978
|
+
fixes: []
|
|
2979
|
+
});
|
|
2980
|
+
}),
|
|
2981
|
+
orElse3(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
2982
|
+
ignore
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
return effectDiagnostics;
|
|
2987
|
+
})
|
|
2988
|
+
});
|
|
2989
|
+
|
|
2942
2990
|
// src/diagnostics/leakingRequirements.ts
|
|
2943
2991
|
var leakingRequirements = createDiagnostic({
|
|
2944
2992
|
name: "leakingRequirements",
|
|
@@ -3017,7 +3065,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
3017
3065
|
const typesToCheck = [];
|
|
3018
3066
|
if (ts.isCallExpression(node)) {
|
|
3019
3067
|
typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
|
|
3020
|
-
} else if (ts.isClassDeclaration(node) && node.name) {
|
|
3068
|
+
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
3021
3069
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
3022
3070
|
if (classSym) {
|
|
3023
3071
|
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
@@ -3297,6 +3345,78 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
3297
3345
|
})
|
|
3298
3346
|
});
|
|
3299
3347
|
|
|
3348
|
+
// src/diagnostics/returnEffectInGen.ts
|
|
3349
|
+
var returnEffectInGen = createDiagnostic({
|
|
3350
|
+
name: "returnEffectInGen",
|
|
3351
|
+
code: 11,
|
|
3352
|
+
apply: fn("returnEffectInGen.apply")(function* (sourceFile) {
|
|
3353
|
+
const ts = yield* service(TypeScriptApi);
|
|
3354
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
3355
|
+
const typeParser = yield* service(TypeParser);
|
|
3356
|
+
const effectDiagnostics = [];
|
|
3357
|
+
const brokenReturnStatements = /* @__PURE__ */ new Set();
|
|
3358
|
+
const nodeToVisit = [];
|
|
3359
|
+
const appendNodeToVisit = (node) => {
|
|
3360
|
+
nodeToVisit.push(node);
|
|
3361
|
+
return void 0;
|
|
3362
|
+
};
|
|
3363
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
3364
|
+
while (nodeToVisit.length > 0) {
|
|
3365
|
+
const node = nodeToVisit.shift();
|
|
3366
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
3367
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
3368
|
+
if (ts.isYieldExpression(node.expression)) continue;
|
|
3369
|
+
const generatorOrRegularFunction = ts.findAncestor(
|
|
3370
|
+
node,
|
|
3371
|
+
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
|
|
3372
|
+
);
|
|
3373
|
+
if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
|
|
3374
|
+
const type = typeChecker.getTypeAtLocation(node.expression);
|
|
3375
|
+
const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
|
|
3376
|
+
if (isSome2(maybeEffect)) {
|
|
3377
|
+
const maybeEffectSubtype = yield* option(typeParser.effectSubtype(type, node.expression));
|
|
3378
|
+
if (isNone2(maybeEffectSubtype)) {
|
|
3379
|
+
if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
|
|
3380
|
+
const effectGenNode = generatorOrRegularFunction.parent;
|
|
3381
|
+
yield* pipe(
|
|
3382
|
+
typeParser.effectGen(effectGenNode),
|
|
3383
|
+
orElse3(() => typeParser.effectFnUntracedGen(effectGenNode)),
|
|
3384
|
+
orElse3(() => typeParser.effectFnGen(effectGenNode)),
|
|
3385
|
+
map4(() => brokenReturnStatements.add(node)),
|
|
3386
|
+
ignore
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
brokenReturnStatements.forEach((node) => {
|
|
3394
|
+
const fix = node.expression ? [{
|
|
3395
|
+
fixName: "returnEffectInGen_fix",
|
|
3396
|
+
description: "Add yield* statement",
|
|
3397
|
+
apply: gen2(function* () {
|
|
3398
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
3399
|
+
changeTracker.replaceNode(
|
|
3400
|
+
sourceFile,
|
|
3401
|
+
node.expression,
|
|
3402
|
+
ts.factory.createYieldExpression(
|
|
3403
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
3404
|
+
node.expression
|
|
3405
|
+
)
|
|
3406
|
+
);
|
|
3407
|
+
})
|
|
3408
|
+
}] : [];
|
|
3409
|
+
effectDiagnostics.push({
|
|
3410
|
+
node,
|
|
3411
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
3412
|
+
messageText: `You are returning an Effect-able type inside a generator function, and will result in nested Effect<Effect<...>>. Maybe you wanted to return yield* instead? Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect.`,
|
|
3413
|
+
fixes: fix
|
|
3414
|
+
});
|
|
3415
|
+
});
|
|
3416
|
+
return effectDiagnostics;
|
|
3417
|
+
})
|
|
3418
|
+
});
|
|
3419
|
+
|
|
3300
3420
|
// src/diagnostics/unnecessaryEffectGen.ts
|
|
3301
3421
|
var unnecessaryEffectGen = createDiagnostic({
|
|
3302
3422
|
name: "unnecessaryEffectGen",
|
|
@@ -3401,7 +3521,9 @@ var diagnostics = [
|
|
|
3401
3521
|
unnecessaryEffectGen,
|
|
3402
3522
|
missingReturnYieldStar,
|
|
3403
3523
|
leakingRequirements,
|
|
3404
|
-
unnecessaryPipe
|
|
3524
|
+
unnecessaryPipe,
|
|
3525
|
+
genericEffectServices,
|
|
3526
|
+
returnEffectInGen
|
|
3405
3527
|
];
|
|
3406
3528
|
|
|
3407
3529
|
// src/goto/effectRpcDefinition.ts
|