@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.21.3",
3
+ "version": "0.21.4",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "repository": {
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