@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/package.json
CHANGED
package/transform.js
CHANGED
|
@@ -2444,6 +2444,54 @@ var floatingEffect = createDiagnostic({
|
|
|
2444
2444
|
})
|
|
2445
2445
|
});
|
|
2446
2446
|
|
|
2447
|
+
// src/diagnostics/genericEffectServices.ts
|
|
2448
|
+
var genericEffectServices = createDiagnostic({
|
|
2449
|
+
name: "genericEffectServices",
|
|
2450
|
+
code: 10,
|
|
2451
|
+
apply: fn("genericEffectServices.apply")(function* (sourceFile) {
|
|
2452
|
+
const ts = yield* service(TypeScriptApi);
|
|
2453
|
+
const typeParser = yield* service(TypeParser);
|
|
2454
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2455
|
+
const effectDiagnostics = [];
|
|
2456
|
+
const nodeToVisit = [];
|
|
2457
|
+
const appendNodeToVisit = (node) => {
|
|
2458
|
+
nodeToVisit.push(node);
|
|
2459
|
+
return void 0;
|
|
2460
|
+
};
|
|
2461
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2462
|
+
while (nodeToVisit.length > 0) {
|
|
2463
|
+
const node = nodeToVisit.shift();
|
|
2464
|
+
const typesToCheck = [];
|
|
2465
|
+
if (ts.isClassDeclaration(node) && node.name && node.typeParameters && node.heritageClauses) {
|
|
2466
|
+
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2467
|
+
if (classSym) {
|
|
2468
|
+
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
2469
|
+
typesToCheck.push([type, node.name]);
|
|
2470
|
+
}
|
|
2471
|
+
} else {
|
|
2472
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2473
|
+
continue;
|
|
2474
|
+
}
|
|
2475
|
+
for (const [type, reportAt] of typesToCheck) {
|
|
2476
|
+
yield* pipe(
|
|
2477
|
+
typeParser.contextTag(type, node),
|
|
2478
|
+
map3(() => {
|
|
2479
|
+
effectDiagnostics.push({
|
|
2480
|
+
node: reportAt,
|
|
2481
|
+
category: ts.DiagnosticCategory.Warning,
|
|
2482
|
+
messageText: `Effect Services with type parameters are not supported because they cannot be properly discriminated at runtime, which may cause unexpected behavior.`,
|
|
2483
|
+
fixes: []
|
|
2484
|
+
});
|
|
2485
|
+
}),
|
|
2486
|
+
orElse2(() => sync(() => ts.forEachChild(node, appendNodeToVisit))),
|
|
2487
|
+
ignore
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
return effectDiagnostics;
|
|
2492
|
+
})
|
|
2493
|
+
});
|
|
2494
|
+
|
|
2447
2495
|
// src/diagnostics/leakingRequirements.ts
|
|
2448
2496
|
var leakingRequirements = createDiagnostic({
|
|
2449
2497
|
name: "leakingRequirements",
|
|
@@ -2522,7 +2570,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
2522
2570
|
const typesToCheck = [];
|
|
2523
2571
|
if (ts.isCallExpression(node)) {
|
|
2524
2572
|
typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
|
|
2525
|
-
} else if (ts.isClassDeclaration(node) && node.name) {
|
|
2573
|
+
} else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
|
|
2526
2574
|
const classSym = typeChecker.getSymbolAtLocation(node.name);
|
|
2527
2575
|
if (classSym) {
|
|
2528
2576
|
const type = typeChecker.getTypeOfSymbol(classSym);
|
|
@@ -2802,6 +2850,78 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
2802
2850
|
})
|
|
2803
2851
|
});
|
|
2804
2852
|
|
|
2853
|
+
// src/diagnostics/returnEffectInGen.ts
|
|
2854
|
+
var returnEffectInGen = createDiagnostic({
|
|
2855
|
+
name: "returnEffectInGen",
|
|
2856
|
+
code: 11,
|
|
2857
|
+
apply: fn("returnEffectInGen.apply")(function* (sourceFile) {
|
|
2858
|
+
const ts = yield* service(TypeScriptApi);
|
|
2859
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
2860
|
+
const typeParser = yield* service(TypeParser);
|
|
2861
|
+
const effectDiagnostics = [];
|
|
2862
|
+
const brokenReturnStatements = /* @__PURE__ */ new Set();
|
|
2863
|
+
const nodeToVisit = [];
|
|
2864
|
+
const appendNodeToVisit = (node) => {
|
|
2865
|
+
nodeToVisit.push(node);
|
|
2866
|
+
return void 0;
|
|
2867
|
+
};
|
|
2868
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
2869
|
+
while (nodeToVisit.length > 0) {
|
|
2870
|
+
const node = nodeToVisit.shift();
|
|
2871
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
2872
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
2873
|
+
if (ts.isYieldExpression(node.expression)) continue;
|
|
2874
|
+
const generatorOrRegularFunction = ts.findAncestor(
|
|
2875
|
+
node,
|
|
2876
|
+
(_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isArrowFunction(_) || ts.isGetAccessor(_)
|
|
2877
|
+
);
|
|
2878
|
+
if (!(generatorOrRegularFunction && "asteriskToken" in generatorOrRegularFunction && generatorOrRegularFunction.asteriskToken)) continue;
|
|
2879
|
+
const type = typeChecker.getTypeAtLocation(node.expression);
|
|
2880
|
+
const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
|
|
2881
|
+
if (isSome2(maybeEffect)) {
|
|
2882
|
+
const maybeEffectSubtype = yield* option(typeParser.effectSubtype(type, node.expression));
|
|
2883
|
+
if (isNone2(maybeEffectSubtype)) {
|
|
2884
|
+
if (generatorOrRegularFunction && generatorOrRegularFunction.parent) {
|
|
2885
|
+
const effectGenNode = generatorOrRegularFunction.parent;
|
|
2886
|
+
yield* pipe(
|
|
2887
|
+
typeParser.effectGen(effectGenNode),
|
|
2888
|
+
orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
|
|
2889
|
+
orElse2(() => typeParser.effectFnGen(effectGenNode)),
|
|
2890
|
+
map3(() => brokenReturnStatements.add(node)),
|
|
2891
|
+
ignore
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
brokenReturnStatements.forEach((node) => {
|
|
2899
|
+
const fix = node.expression ? [{
|
|
2900
|
+
fixName: "returnEffectInGen_fix",
|
|
2901
|
+
description: "Add yield* statement",
|
|
2902
|
+
apply: gen(function* () {
|
|
2903
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
2904
|
+
changeTracker.replaceNode(
|
|
2905
|
+
sourceFile,
|
|
2906
|
+
node.expression,
|
|
2907
|
+
ts.factory.createYieldExpression(
|
|
2908
|
+
ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
|
|
2909
|
+
node.expression
|
|
2910
|
+
)
|
|
2911
|
+
);
|
|
2912
|
+
})
|
|
2913
|
+
}] : [];
|
|
2914
|
+
effectDiagnostics.push({
|
|
2915
|
+
node,
|
|
2916
|
+
category: ts.DiagnosticCategory.Suggestion,
|
|
2917
|
+
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.`,
|
|
2918
|
+
fixes: fix
|
|
2919
|
+
});
|
|
2920
|
+
});
|
|
2921
|
+
return effectDiagnostics;
|
|
2922
|
+
})
|
|
2923
|
+
});
|
|
2924
|
+
|
|
2805
2925
|
// src/diagnostics/unnecessaryEffectGen.ts
|
|
2806
2926
|
var unnecessaryEffectGen = createDiagnostic({
|
|
2807
2927
|
name: "unnecessaryEffectGen",
|
|
@@ -2906,7 +3026,9 @@ var diagnostics = [
|
|
|
2906
3026
|
unnecessaryEffectGen,
|
|
2907
3027
|
missingReturnYieldStar,
|
|
2908
3028
|
leakingRequirements,
|
|
2909
|
-
unnecessaryPipe
|
|
3029
|
+
unnecessaryPipe,
|
|
3030
|
+
genericEffectServices,
|
|
3031
|
+
returnEffectInGen
|
|
2910
3032
|
];
|
|
2911
3033
|
|
|
2912
3034
|
// src/transform.ts
|