@effect/language-service 0.25.0 → 0.26.0

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.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "bin": {
package/transform.js CHANGED
@@ -902,6 +902,7 @@ var NanoFiber = class {
902
902
  _stack = [];
903
903
  _yielded = void 0;
904
904
  _services = {};
905
+ _cache = {};
905
906
  runLoop(nano) {
906
907
  let current = nano;
907
908
  while (true) {
@@ -1052,8 +1053,32 @@ var service = (tag) => {
1052
1053
  nano[args] = tag;
1053
1054
  return nano;
1054
1055
  };
1055
- function cachedBy(fa, _key, _lookupKey) {
1056
- return (...args2) => fa(...args2);
1056
+ var CachedProto = {
1057
+ ...PrimitiveProto,
1058
+ [evaluate](fiber) {
1059
+ const [fa, type, key] = this[args];
1060
+ const cache = fiber._cache[type] || /* @__PURE__ */ new WeakMap();
1061
+ fiber._cache[type] = cache;
1062
+ const cached2 = cache.get(key);
1063
+ if (cached2) return cached2;
1064
+ return match2(fa, {
1065
+ onSuccess: (_) => {
1066
+ cache.set(key, succeed(_));
1067
+ return succeed(_);
1068
+ },
1069
+ onFailure: (_) => {
1070
+ cache.set(key, fail(_));
1071
+ return fail(_);
1072
+ }
1073
+ });
1074
+ }
1075
+ };
1076
+ function cachedBy(fa, type, lookupKey) {
1077
+ return (...p) => {
1078
+ const nano = Object.create(CachedProto);
1079
+ nano[args] = [fa(...p), type, lookupKey(...p)];
1080
+ return nano;
1081
+ };
1057
1082
  }
1058
1083
  var option = (fa) => {
1059
1084
  const nano = Object.create(MatchProto);
@@ -1630,8 +1655,7 @@ var unrollUnionMembers = (type) => {
1630
1655
  var appendToUniqueTypesMap = fn(
1631
1656
  "TypeCheckerApi.appendToUniqueTypesMap"
1632
1657
  )(
1633
- function* (memory, initialType, excludeNever) {
1634
- const ts = yield* service(TypeScriptApi);
1658
+ function* (memory, initialType, shouldExclude) {
1635
1659
  const typeChecker = yield* service(TypeCheckerApi);
1636
1660
  const newIndexes = /* @__PURE__ */ new Set();
1637
1661
  const knownIndexes = /* @__PURE__ */ new Set();
@@ -1639,7 +1663,7 @@ var appendToUniqueTypesMap = fn(
1639
1663
  while (toTest.length > 0) {
1640
1664
  const type = toTest.pop();
1641
1665
  if (!type) break;
1642
- if (excludeNever && type.flags & ts.TypeFlags.Never) {
1666
+ if (yield* shouldExclude(type)) {
1643
1667
  continue;
1644
1668
  }
1645
1669
  if (type.isUnion()) {
@@ -2475,11 +2499,16 @@ function make2(ts, typeChecker) {
2475
2499
  const pipeCall = cachedBy(
2476
2500
  function(node) {
2477
2501
  if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name) && node.expression.name.text === "pipe") {
2478
- return succeed({ node, subject: node.expression.expression, args: Array.from(node.arguments) });
2502
+ return succeed({
2503
+ node,
2504
+ subject: node.expression.expression,
2505
+ args: Array.from(node.arguments),
2506
+ kind: "pipeable"
2507
+ });
2479
2508
  }
2480
2509
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
2481
2510
  const [subject, ...args2] = node.arguments;
2482
- return succeed({ node, subject, args: args2 });
2511
+ return succeed({ node, subject, args: args2, kind: "pipe" });
2483
2512
  }
2484
2513
  return typeParserIssue("Node is not a pipe call", void 0, node);
2485
2514
  },
@@ -2518,6 +2547,7 @@ function make2(ts, typeChecker) {
2518
2547
  unnecessaryEffectGen: unnecessaryEffectGen2,
2519
2548
  effectSchemaType,
2520
2549
  contextTag,
2550
+ pipeableType,
2521
2551
  pipeCall,
2522
2552
  scopeType
2523
2553
  };
@@ -2887,7 +2917,18 @@ var leakingRequirements = createDiagnostic({
2887
2917
  );
2888
2918
  if (effectContextType) {
2889
2919
  effectMembers++;
2890
- const { allIndexes } = yield* appendToUniqueTypesMap(memory, effectContextType, true);
2920
+ const { allIndexes } = yield* appendToUniqueTypesMap(
2921
+ memory,
2922
+ effectContextType,
2923
+ (type) => {
2924
+ if (type.flags & ts.TypeFlags.Never) return succeed(true);
2925
+ return pipe(
2926
+ typeParser.scopeType(type, atLocation),
2927
+ map3(() => true),
2928
+ orElse2(() => succeed(false))
2929
+ );
2930
+ }
2931
+ );
2891
2932
  if (!sharedRequirementsKeys) {
2892
2933
  sharedRequirementsKeys = allIndexes;
2893
2934
  } else {
@@ -3443,8 +3484,8 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
3443
3484
  // src/diagnostics/tryCatchInEffectGen.ts
3444
3485
  var tryCatchInEffectGen = createDiagnostic({
3445
3486
  name: "tryCatchInEffectGen",
3446
- code: 12,
3447
- severity: "warning",
3487
+ code: 15,
3488
+ severity: "suggestion",
3448
3489
  apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
3449
3490
  const ts = yield* service(TypeScriptApi);
3450
3491
  const typeParser = yield* service(TypeParser);
@@ -3573,6 +3614,80 @@ var unnecessaryPipe = createDiagnostic({
3573
3614
  })
3574
3615
  });
3575
3616
 
3617
+ // src/diagnostics/unnecessaryPipeChain.ts
3618
+ var unnecessaryPipeChain = createDiagnostic({
3619
+ name: "unnecessaryPipeChain",
3620
+ code: 16,
3621
+ severity: "suggestion",
3622
+ apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
3623
+ const ts = yield* service(TypeScriptApi);
3624
+ const typeParser = yield* service(TypeParser);
3625
+ const nodeToVisit = [];
3626
+ const appendNodeToVisit = (node) => {
3627
+ nodeToVisit.push(node);
3628
+ return void 0;
3629
+ };
3630
+ ts.forEachChild(sourceFile, appendNodeToVisit);
3631
+ while (nodeToVisit.length > 0) {
3632
+ const node = nodeToVisit.shift();
3633
+ ts.forEachChild(node, appendNodeToVisit);
3634
+ if (ts.isCallExpression(node)) {
3635
+ yield* pipe(
3636
+ typeParser.pipeCall(node),
3637
+ flatMap2(
3638
+ (pipeCall) => map3(typeParser.pipeCall(pipeCall.subject), (innerCall) => ({ pipeCall, innerCall }))
3639
+ ),
3640
+ map3(({ innerCall, pipeCall }) => {
3641
+ report({
3642
+ node,
3643
+ messageText: `Chained pipe calls can be simplified to a single pipe call`,
3644
+ fixes: [{
3645
+ fixName: "unnecessaryPipeChain_fix",
3646
+ description: "Rewrite as single pipe call",
3647
+ apply: gen(function* () {
3648
+ const changeTracker = yield* service(
3649
+ ChangeTracker
3650
+ );
3651
+ switch (innerCall.kind) {
3652
+ case "pipe": {
3653
+ changeTracker.replaceNode(
3654
+ sourceFile,
3655
+ node,
3656
+ ts.factory.createCallExpression(
3657
+ ts.factory.createIdentifier("pipe"),
3658
+ void 0,
3659
+ [innerCall.subject, ...innerCall.args, ...pipeCall.args]
3660
+ )
3661
+ );
3662
+ break;
3663
+ }
3664
+ case "pipeable": {
3665
+ changeTracker.replaceNode(
3666
+ sourceFile,
3667
+ node,
3668
+ ts.factory.createCallExpression(
3669
+ ts.factory.createPropertyAccessExpression(
3670
+ innerCall.subject,
3671
+ "pipe"
3672
+ ),
3673
+ void 0,
3674
+ [...innerCall.args, ...pipeCall.args]
3675
+ )
3676
+ );
3677
+ break;
3678
+ }
3679
+ }
3680
+ })
3681
+ }]
3682
+ });
3683
+ }),
3684
+ ignore
3685
+ );
3686
+ }
3687
+ }
3688
+ })
3689
+ });
3690
+
3576
3691
  // src/diagnostics.ts
3577
3692
  var diagnostics = [
3578
3693
  duplicatePackage,
@@ -3589,7 +3704,8 @@ var diagnostics = [
3589
3704
  tryCatchInEffectGen,
3590
3705
  importFromBarrel,
3591
3706
  scopeInLayerEffect,
3592
- effectInVoidSuccess
3707
+ effectInVoidSuccess,
3708
+ unnecessaryPipeChain
3593
3709
  ];
3594
3710
 
3595
3711
  // src/transform.ts