@effect/language-service 0.21.2 → 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.2",
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
@@ -1014,6 +1014,8 @@ function parsePackageContentNameAndVersionFromScope(v) {
1014
1014
  const packageJsonContent = packageJsonScope.contents.packageJsonContent;
1015
1015
  if (!hasProperty(packageJsonContent, "name")) return;
1016
1016
  if (!hasProperty(packageJsonContent, "version")) return;
1017
+ if (!hasProperty(packageJsonScope, "packageDirectory")) return;
1018
+ if (!isString(packageJsonScope.packageDirectory)) return;
1017
1019
  const { name, version } = packageJsonContent;
1018
1020
  if (!isString(name)) return;
1019
1021
  if (!isString(version)) return;
@@ -1022,7 +1024,8 @@ function parsePackageContentNameAndVersionFromScope(v) {
1022
1024
  name: name.toLowerCase(),
1023
1025
  version: version.toLowerCase(),
1024
1026
  hasEffectInPeerDependencies,
1025
- contents: packageJsonContent
1027
+ contents: packageJsonContent,
1028
+ packageDirectory: packageJsonScope.packageDirectory
1026
1029
  };
1027
1030
  }
1028
1031
 
@@ -2369,7 +2372,7 @@ var duplicatePackage = createDiagnostic({
2369
2372
  if (!(packageInfo.name === "effect" || packageInfo.hasEffectInPeerDependencies)) return;
2370
2373
  if (options.allowedDuplicatedPackages.indexOf(packageInfo.name) > -1) return;
2371
2374
  resolvedPackages[packageInfo.name] = resolvedPackages[packageInfo.name] || {};
2372
- resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.contents;
2375
+ resolvedPackages[packageInfo.name][packageInfo.version] = packageInfo.packageDirectory;
2373
2376
  });
2374
2377
  checkedPackagesCache.set(sourceFile.fileName, resolvedPackages);
2375
2378
  programResolvedCacheSize.set(sourceFile.fileName, newResolvedModuleSize);
@@ -2382,7 +2385,9 @@ var duplicatePackage = createDiagnostic({
2382
2385
  category: ts.DiagnosticCategory.Warning,
2383
2386
  messageText: `Package ${packageName} is referenced multiple times with different versions (${versions.join(", ")}) and may cause unexpected type errors.
2384
2387
  Cleanup your dependencies and your package lockfile to avoid multiple instances of this package and reload the project.
2385
- If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.`,
2388
+ If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
2389
+
2390
+ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
2386
2391
  fixes: []
2387
2392
  });
2388
2393
  }
@@ -2439,6 +2444,54 @@ var floatingEffect = createDiagnostic({
2439
2444
  })
2440
2445
  });
2441
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
+
2442
2495
  // src/diagnostics/leakingRequirements.ts
2443
2496
  var leakingRequirements = createDiagnostic({
2444
2497
  name: "leakingRequirements",
@@ -2517,7 +2570,7 @@ var leakingRequirements = createDiagnostic({
2517
2570
  const typesToCheck = [];
2518
2571
  if (ts.isCallExpression(node)) {
2519
2572
  typesToCheck.push([typeChecker.getTypeAtLocation(node), node]);
2520
- } else if (ts.isClassDeclaration(node) && node.name) {
2573
+ } else if (ts.isClassDeclaration(node) && node.name && node.heritageClauses) {
2521
2574
  const classSym = typeChecker.getSymbolAtLocation(node.name);
2522
2575
  if (classSym) {
2523
2576
  const type = typeChecker.getTypeOfSymbol(classSym);
@@ -2713,7 +2766,7 @@ var missingReturnYieldStar = createDiagnostic({
2713
2766
  effectDiagnostics.push({
2714
2767
  node,
2715
2768
  category: ts.DiagnosticCategory.Error,
2716
- messageText: `Yielded Effect never completes, so it is best to use a 'return yield*' instead.`,
2769
+ messageText: `Yielded Effect never succeeds, so it is best to use a 'return yield*' instead.`,
2717
2770
  fixes: fix
2718
2771
  });
2719
2772
  });
@@ -2797,6 +2850,78 @@ var missingStarInYieldEffectGen = createDiagnostic({
2797
2850
  })
2798
2851
  });
2799
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
+
2800
2925
  // src/diagnostics/unnecessaryEffectGen.ts
2801
2926
  var unnecessaryEffectGen = createDiagnostic({
2802
2927
  name: "unnecessaryEffectGen",
@@ -2901,7 +3026,9 @@ var diagnostics = [
2901
3026
  unnecessaryEffectGen,
2902
3027
  missingReturnYieldStar,
2903
3028
  leakingRequirements,
2904
- unnecessaryPipe
3029
+ unnecessaryPipe,
3030
+ genericEffectServices,
3031
+ returnEffectInGen
2905
3032
  ];
2906
3033
 
2907
3034
  // src/transform.ts