@effect/language-service 0.18.0 → 0.19.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/index.js CHANGED
@@ -922,6 +922,7 @@ var map2 = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : some2(
922
922
  // node_modules/.pnpm/effect@3.16.3/node_modules/effect/dist/esm/Array.js
923
923
  var fromIterable = (collection) => Array.isArray(collection) ? collection : Array.from(collection);
924
924
  var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
925
+ var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
925
926
  var isArray = Array.isArray;
926
927
  var isEmptyArray = (self) => self.length === 0;
927
928
  var isEmptyReadonlyArray = isEmptyArray;
@@ -2094,6 +2095,51 @@ var expectedAndRealType = fn("TypeCheckerApi.expectedAndRealType")(function* (so
2094
2095
  cache.expectedAndRealType.set(sourceFile, result);
2095
2096
  return result;
2096
2097
  });
2098
+ var appendToUniqueTypesMap = fn(
2099
+ "TypeCheckerApi.appendToUniqueTypesMap"
2100
+ )(
2101
+ function* (memory, initialType, excludeNever) {
2102
+ const ts = yield* service(TypeScriptApi);
2103
+ const typeChecker = yield* service(TypeCheckerApi);
2104
+ const newIndexes = /* @__PURE__ */ new Set();
2105
+ const knownIndexes = /* @__PURE__ */ new Set();
2106
+ let toTest = [initialType];
2107
+ while (toTest.length > 0) {
2108
+ const type = toTest.pop();
2109
+ if (!type) break;
2110
+ if (excludeNever && type.flags & ts.TypeFlags.Never) {
2111
+ continue;
2112
+ }
2113
+ if (type.isUnion()) {
2114
+ toTest = toTest.concat(type.types);
2115
+ } else {
2116
+ const foundMatch = [];
2117
+ for (const [typeId, knownType] of memory.entries()) {
2118
+ const areSame = typeChecker.isTypeAssignableTo(knownType, type) && typeChecker.isTypeAssignableTo(type, knownType);
2119
+ if (areSame) {
2120
+ foundMatch.push(typeId);
2121
+ break;
2122
+ }
2123
+ }
2124
+ if (foundMatch.length === 0) {
2125
+ const newId = "t" + (memory.size + 1);
2126
+ memory.set(newId, type);
2127
+ newIndexes.add(newId);
2128
+ } else {
2129
+ knownIndexes.add(foundMatch[0]);
2130
+ }
2131
+ }
2132
+ }
2133
+ return {
2134
+ newIndexes,
2135
+ knownIndexes,
2136
+ allIndexes: pipe(
2137
+ fromIterable(newIndexes),
2138
+ appendAll(fromIterable(knownIndexes))
2139
+ )
2140
+ };
2141
+ }
2142
+ );
2097
2143
 
2098
2144
  // src/utils/TypeParser.ts
2099
2145
  var TypeParserIssue = class {
@@ -2114,6 +2160,13 @@ function covariantTypeArgument(type) {
2114
2160
  }
2115
2161
  return succeed(signatures[0].getReturnType());
2116
2162
  }
2163
+ function contravariantTypeArgument(type) {
2164
+ const signatures = type.getCallSignatures();
2165
+ if (signatures.length !== 1) {
2166
+ return typeParserIssue("Contravariant type has no call signature", type);
2167
+ }
2168
+ return succeed(signatures[0].getTypeParameterAtPosition(0));
2169
+ }
2117
2170
  function invariantTypeArgument(type) {
2118
2171
  const signatures = type.getCallSignatures();
2119
2172
  if (signatures.length !== 1) {
@@ -2145,6 +2198,19 @@ var varianceStructCovariantType = fn("TypeParser.varianceStructCovariantType")(
2145
2198
  return yield* covariantTypeArgument(propertyType);
2146
2199
  }
2147
2200
  );
2201
+ var varianceStructContravariantType = fn(
2202
+ "TypeParser.varianceStructContravariantType"
2203
+ )(
2204
+ function* (type, atLocation, propertyName) {
2205
+ const typeChecker = yield* service(TypeCheckerApi);
2206
+ const propertySymbol = typeChecker.getPropertyOfType(type, propertyName);
2207
+ if (!propertySymbol) {
2208
+ return yield* typeParserIssue(`Type has no '${propertyName}' property`, type, atLocation);
2209
+ }
2210
+ const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2211
+ return yield* contravariantTypeArgument(propertyType);
2212
+ }
2213
+ );
2148
2214
  var varianceStructInvariantType = fn("TypeParser.varianceStructInvariantType")(
2149
2215
  function* (type, atLocation, propertyName) {
2150
2216
  const typeChecker = yield* service(TypeCheckerApi);
@@ -2163,6 +2229,13 @@ var effectVarianceStruct = fn("TypeParser.effectVarianceStruct")(function* (type
2163
2229
  R: yield* varianceStructCovariantType(type, atLocation, "_R")
2164
2230
  };
2165
2231
  });
2232
+ var layerVarianceStruct = fn("TypeParser.layerVarianceStruct")(function* (type, atLocation) {
2233
+ return {
2234
+ ROut: yield* varianceStructContravariantType(type, atLocation, "_ROut"),
2235
+ E: yield* varianceStructCovariantType(type, atLocation, "_E"),
2236
+ RIn: yield* varianceStructCovariantType(type, atLocation, "_RIn")
2237
+ };
2238
+ });
2166
2239
  var effectType = fn("TypeParser.effectType")(function* (type, atLocation) {
2167
2240
  const ts = yield* service(TypeScriptApi);
2168
2241
  const typeChecker = yield* service(TypeCheckerApi);
@@ -2183,6 +2256,26 @@ var effectType = fn("TypeParser.effectType")(function* (type, atLocation) {
2183
2256
  }
2184
2257
  return yield* typeParserIssue("Type has no effect variance struct", type, atLocation);
2185
2258
  });
2259
+ var layerType = fn("TypeParser.layerType")(function* (type, atLocation) {
2260
+ const ts = yield* service(TypeScriptApi);
2261
+ const typeChecker = yield* service(TypeCheckerApi);
2262
+ yield* pipeableType(type, atLocation);
2263
+ const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
2264
+ (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional)
2265
+ );
2266
+ propertiesSymbols.sort((a, b) => b.name.indexOf("LayerTypeId") - a.name.indexOf("LayerTypeId"));
2267
+ for (const propertySymbol of propertiesSymbols) {
2268
+ const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
2269
+ const varianceArgs = yield* option(layerVarianceStruct(
2270
+ propertyType,
2271
+ atLocation
2272
+ ));
2273
+ if (isSome2(varianceArgs)) {
2274
+ return varianceArgs.value;
2275
+ }
2276
+ }
2277
+ return yield* typeParserIssue("Type has no layer variance struct", type, atLocation);
2278
+ });
2186
2279
  var fiberType = fn("TypeParser.fiberType")(function* (type, atLocation) {
2187
2280
  const typeChecker = yield* service(TypeCheckerApi);
2188
2281
  const awaitSymbol = typeChecker.getPropertyOfType(type, "await");
@@ -2348,19 +2441,68 @@ var effectFnGen = fn("TypeParser.effectFnGen")(function* (node) {
2348
2441
  functionStar: generatorFunction.getFirstToken()
2349
2442
  };
2350
2443
  });
2351
- var returnYieldEffectBlock = fn("TypeParser.returnYieldEffectBlock")(function* (body) {
2444
+ var unnecessaryEffectGen = fn("TypeParser.unnecessaryEffectGen")(function* (node) {
2352
2445
  const ts = yield* service(TypeScriptApi);
2353
2446
  const typeChecker = yield* service(TypeCheckerApi);
2354
- if (ts.isBlock(body) && body.statements.length === 1 && ts.isReturnStatement(body.statements[0]) && body.statements[0].expression && ts.isYieldExpression(body.statements[0].expression) && body.statements[0].expression.expression) {
2355
- const nodeToCheck = body.statements[0].expression.expression;
2356
- const type = typeChecker.getTypeAtLocation(nodeToCheck);
2357
- yield* effectType(type, nodeToCheck);
2358
- return nodeToCheck;
2447
+ const { body } = yield* effectGen(node);
2448
+ if (body.statements.length !== 1) {
2449
+ return yield* typeParserIssue(
2450
+ "Generator body should have a single statement",
2451
+ void 0,
2452
+ node
2453
+ );
2454
+ }
2455
+ let explicitReturn = false;
2456
+ let nodeToCheck = body.statements[0];
2457
+ while (nodeToCheck) {
2458
+ if (ts.isReturnStatement(nodeToCheck) && nodeToCheck.expression) {
2459
+ nodeToCheck = nodeToCheck.expression;
2460
+ explicitReturn = true;
2461
+ continue;
2462
+ }
2463
+ if (ts.isExpressionStatement(nodeToCheck)) {
2464
+ nodeToCheck = nodeToCheck.expression;
2465
+ continue;
2466
+ }
2467
+ if (ts.isYieldExpression(nodeToCheck) && nodeToCheck.asteriskToken && nodeToCheck.expression) {
2468
+ const yieldedExpression = nodeToCheck.expression;
2469
+ const type = typeChecker.getTypeAtLocation(yieldedExpression);
2470
+ const { A: successType } = yield* effectType(type, yieldedExpression);
2471
+ let replacementNode = succeed(yieldedExpression);
2472
+ if (!explicitReturn && !(successType.flags & ts.TypeFlags.VoidLike)) {
2473
+ replacementNode = pipe(
2474
+ gen2(function* () {
2475
+ const effectIdentifier = pipe(
2476
+ yield* option(
2477
+ findImportedModuleIdentifierByPackageAndNameOrBarrel(node.getSourceFile(), "effect", "Effect")
2478
+ ),
2479
+ match2({
2480
+ onNone: () => "Effect",
2481
+ onSome: (_) => _.text
2482
+ })
2483
+ );
2484
+ return ts.factory.createCallExpression(
2485
+ ts.factory.createPropertyAccessExpression(
2486
+ ts.factory.createIdentifier(effectIdentifier),
2487
+ "asVoid"
2488
+ ),
2489
+ void 0,
2490
+ [
2491
+ yieldedExpression
2492
+ ]
2493
+ );
2494
+ }),
2495
+ provideService(TypeScriptApi, ts)
2496
+ );
2497
+ }
2498
+ return { node, body, yieldedExpression, replacementNode };
2499
+ }
2500
+ break;
2359
2501
  }
2360
2502
  return yield* typeParserIssue(
2361
- "Node is not a return statement with a yield expression",
2503
+ "Not an handled node",
2362
2504
  void 0,
2363
- body
2505
+ node
2364
2506
  );
2365
2507
  });
2366
2508
  var effectSchemaVarianceStruct = fn("TypeParser.effectSchemaVarianceStruct")(
@@ -2792,7 +2934,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
2792
2934
  });
2793
2935
 
2794
2936
  // src/diagnostics/unnecessaryEffectGen.ts
2795
- var unnecessaryEffectGen = createDiagnostic({
2937
+ var unnecessaryEffectGen2 = createDiagnostic({
2796
2938
  name: "unnecessaryEffectGen",
2797
2939
  code: 5,
2798
2940
  apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile) {
@@ -2808,13 +2950,9 @@ var unnecessaryEffectGen = createDiagnostic({
2808
2950
  while (nodeToVisit.length > 0) {
2809
2951
  const node = nodeToVisit.shift();
2810
2952
  ts.forEachChild(node, appendNodeToVisit);
2811
- const maybeNode = yield* pipe(
2812
- effectGen(node),
2813
- flatMap3(({ body }) => returnYieldEffectBlock(body)),
2814
- option
2815
- );
2953
+ const maybeNode = yield* option(unnecessaryEffectGen(node));
2816
2954
  if (isSome2(maybeNode)) {
2817
- unnecessaryGenerators.set(node, maybeNode.value);
2955
+ unnecessaryGenerators.set(node, maybeNode.value.replacementNode);
2818
2956
  }
2819
2957
  }
2820
2958
  unnecessaryGenerators.forEach(
@@ -2829,7 +2967,7 @@ var unnecessaryEffectGen = createDiagnostic({
2829
2967
  const textChanges = yield* service(
2830
2968
  ChangeTracker
2831
2969
  );
2832
- textChanges.replaceNode(sourceFile, effectGenCall, yieldedResult);
2970
+ textChanges.replaceNode(sourceFile, effectGenCall, yield* yieldedResult);
2833
2971
  })
2834
2972
  }]
2835
2973
  })
@@ -2845,24 +2983,26 @@ var diagnostics = [
2845
2983
  missingEffectError,
2846
2984
  floatingEffect,
2847
2985
  missingStarInYieldEffectGen,
2848
- unnecessaryEffectGen
2986
+ unnecessaryEffectGen2
2849
2987
  ];
2850
2988
 
2851
- // src/quickinfo.ts
2989
+ // src/quickinfo/dedupeJsDocs.ts
2852
2990
  var SymbolDisplayPartEq = make((fa, fb) => fa.kind === fb.kind && fa.text === fb.text);
2853
2991
  var JSDocTagInfoEq = make(
2854
2992
  (fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? array(SymbolDisplayPartEq)(fa.text, fb.text) : true)
2855
2993
  );
2856
- function dedupeJsDocTags(quickInfo) {
2857
- if (!quickInfo) return quickInfo;
2858
- if (quickInfo.tags) {
2859
- return {
2860
- ...quickInfo,
2861
- tags: dedupeWith(quickInfo.tags, JSDocTagInfoEq)
2862
- };
2994
+ function dedupeJsDocs(quickInfo2) {
2995
+ if (!quickInfo2) return succeed(quickInfo2);
2996
+ if (quickInfo2.tags) {
2997
+ return succeed({
2998
+ ...quickInfo2,
2999
+ tags: dedupeWith(quickInfo2.tags, JSDocTagInfoEq)
3000
+ });
2863
3001
  }
2864
- return quickInfo;
3002
+ return succeed(quickInfo2);
2865
3003
  }
3004
+
3005
+ // src/quickinfo/effectTypeArgs.ts
2866
3006
  function formatTypeForQuickInfo(channelType, channelName) {
2867
3007
  return gen2(function* () {
2868
3008
  const ts = yield* service(TypeScriptApi);
@@ -2875,7 +3015,7 @@ function formatTypeForQuickInfo(channelType, channelName) {
2875
3015
  return `type ${channelName} = ${stringRepresentation}`;
2876
3016
  });
2877
3017
  }
2878
- function prependEffectTypeArguments(sourceFile, position, quickInfo) {
3018
+ function effectTypeArgs(sourceFile, position, quickInfo2) {
2879
3019
  return pipe(
2880
3020
  gen2(function* () {
2881
3021
  const ts = yield* service(TypeScriptApi);
@@ -2884,11 +3024,11 @@ function prependEffectTypeArguments(sourceFile, position, quickInfo) {
2884
3024
  yield* getAncestorNodesInRange(sourceFile, toTextRange(position)),
2885
3025
  head
2886
3026
  );
2887
- if (isNone2(maybeNode)) return quickInfo;
3027
+ if (isNone2(maybeNode)) return quickInfo2;
2888
3028
  const node = maybeNode.value;
2889
- const hasTruncationHappened = quickInfo && ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
2890
- const nodeForType = !quickInfo && ts.isYieldExpression(node) && node.asteriskToken && node.expression ? node.expression : hasTruncationHappened ? node : void 0;
2891
- if (!nodeForType) return quickInfo;
3029
+ const hasTruncationHappened = quickInfo2 && ts.displayPartsToString(quickInfo2.displayParts).indexOf("...") > -1;
3030
+ const nodeForType = !quickInfo2 && ts.isYieldExpression(node) && node.asteriskToken && node.expression ? node.expression : hasTruncationHappened ? node : void 0;
3031
+ if (!nodeForType) return quickInfo2;
2892
3032
  const effectType2 = yield* effectType(
2893
3033
  typeChecker.getTypeAtLocation(nodeForType),
2894
3034
  nodeForType
@@ -2897,7 +3037,7 @@ function prependEffectTypeArguments(sourceFile, position, quickInfo) {
2897
3037
  kind: "text",
2898
3038
  text: "```ts\n/* Effect Type Parameters */\n" + (yield* formatTypeForQuickInfo(effectType2.A, "Success")) + "\n" + (yield* formatTypeForQuickInfo(effectType2.E, "Failure")) + "\n" + (yield* formatTypeForQuickInfo(effectType2.R, "Requirements")) + "\n```\n"
2899
3039
  }];
2900
- if (!quickInfo) {
3040
+ if (!quickInfo2) {
2901
3041
  const start = node.getStart();
2902
3042
  const end = node.getEnd();
2903
3043
  return {
@@ -2907,21 +3047,398 @@ function prependEffectTypeArguments(sourceFile, position, quickInfo) {
2907
3047
  documentation: effectTypeArgsDocumentation
2908
3048
  };
2909
3049
  }
2910
- if (quickInfo.documentation) {
3050
+ if (quickInfo2.documentation) {
2911
3051
  return {
2912
- ...quickInfo,
2913
- documentation: effectTypeArgsDocumentation.concat(quickInfo.documentation)
3052
+ ...quickInfo2,
3053
+ documentation: effectTypeArgsDocumentation.concat(quickInfo2.documentation)
2914
3054
  };
2915
3055
  }
2916
3056
  return {
2917
- ...quickInfo,
3057
+ ...quickInfo2,
2918
3058
  documentation: effectTypeArgsDocumentation
2919
3059
  };
2920
3060
  }),
2921
- orElse3(() => succeed(quickInfo))
3061
+ orElse3(() => succeed(quickInfo2))
2922
3062
  );
2923
3063
  }
2924
3064
 
3065
+ // src/quickinfo/layerInfo.ts
3066
+ var UnableToProduceLayerGraphError = class {
3067
+ constructor(message, node) {
3068
+ this.message = message;
3069
+ this.node = node;
3070
+ }
3071
+ _tag = "@effect/language-service/UnableToProduceLayerGraphError";
3072
+ };
3073
+ var GraphNodeLeaf = class {
3074
+ constructor(id, node, rout, rin) {
3075
+ this.id = id;
3076
+ this.node = node;
3077
+ this.rout = rout;
3078
+ this.rin = rin;
3079
+ }
3080
+ _tag = "GraphNodeLeaf";
3081
+ };
3082
+ var GraphNodeCompoundTransform = class {
3083
+ constructor(id, node, args, rout, rin) {
3084
+ this.id = id;
3085
+ this.node = node;
3086
+ this.args = args;
3087
+ this.rout = rout;
3088
+ this.rin = rin;
3089
+ }
3090
+ _tag = "GraphNodeCompoundTransform";
3091
+ };
3092
+ function processLayerGraphNode(ctx, node, pipedInGraphNode) {
3093
+ return gen2(function* () {
3094
+ const ts = yield* service(TypeScriptApi);
3095
+ const typeChecker = yield* service(TypeCheckerApi);
3096
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === "pipe") {
3097
+ let graphNode = yield* processLayerGraphNode(ctx, node.expression.expression, void 0);
3098
+ for (const entry of node.arguments) {
3099
+ graphNode = yield* processLayerGraphNode(ctx, entry, graphNode);
3100
+ }
3101
+ return graphNode;
3102
+ }
3103
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "pipe" && node.arguments.length > 0) {
3104
+ let graphNode = yield* processLayerGraphNode(ctx, node.arguments[0], void 0);
3105
+ for (let i = 1; i < node.arguments.length; i++) {
3106
+ graphNode = yield* processLayerGraphNode(ctx, node.arguments[i], graphNode);
3107
+ }
3108
+ return graphNode;
3109
+ }
3110
+ if (ts.isCallExpression(node)) {
3111
+ const type = typeChecker.getTypeAtLocation(node);
3112
+ const maybeLayer = yield* option(layerType(type, node));
3113
+ if (isSome2(maybeLayer)) {
3114
+ const argNodes = yield* option(
3115
+ all2(...node.arguments.map((_) => processLayerGraphNode(ctx, _, void 0)))
3116
+ );
3117
+ if (isSome2(argNodes) && argNodes.value.length === node.arguments.length) {
3118
+ const { allIndexes: outTypes } = yield* appendToUniqueTypesMap(
3119
+ ctx.services,
3120
+ maybeLayer.value.ROut,
3121
+ true
3122
+ );
3123
+ const { allIndexes: inTypes } = yield* appendToUniqueTypesMap(
3124
+ ctx.services,
3125
+ maybeLayer.value.RIn,
3126
+ true
3127
+ );
3128
+ return new GraphNodeCompoundTransform(
3129
+ ctx.nextId(),
3130
+ node,
3131
+ argNodes.value,
3132
+ outTypes,
3133
+ inTypes
3134
+ );
3135
+ }
3136
+ }
3137
+ }
3138
+ if (pipedInGraphNode && ts.isExpression(node)) {
3139
+ const type = typeChecker.getContextualType(node);
3140
+ if (type) {
3141
+ const callSignatures = type.getCallSignatures();
3142
+ if (callSignatures.length === 1) {
3143
+ const [signature] = callSignatures;
3144
+ const returnType = signature.getReturnType();
3145
+ const maybeLayer = yield* option(layerType(returnType, node));
3146
+ if (isSome2(maybeLayer)) {
3147
+ const { allIndexes: outTypes } = yield* appendToUniqueTypesMap(
3148
+ ctx.services,
3149
+ maybeLayer.value.ROut,
3150
+ true
3151
+ );
3152
+ const { allIndexes: inTypes } = yield* appendToUniqueTypesMap(
3153
+ ctx.services,
3154
+ maybeLayer.value.RIn,
3155
+ true
3156
+ );
3157
+ if (ts.isCallExpression(node)) {
3158
+ const argNodes = yield* option(
3159
+ all2(...node.arguments.map((_) => processLayerGraphNode(ctx, _, void 0)))
3160
+ );
3161
+ if (isSome2(argNodes) && argNodes.value.length === node.arguments.length) {
3162
+ return new GraphNodeCompoundTransform(
3163
+ ctx.nextId(),
3164
+ node,
3165
+ [pipedInGraphNode, ...argNodes.value],
3166
+ outTypes,
3167
+ inTypes
3168
+ );
3169
+ }
3170
+ }
3171
+ const argNode = yield* option(processLayerGraphNode(ctx, node, void 0));
3172
+ if (isSome2(argNode)) {
3173
+ return new GraphNodeCompoundTransform(
3174
+ ctx.nextId(),
3175
+ node,
3176
+ [pipedInGraphNode, argNode.value],
3177
+ outTypes,
3178
+ inTypes
3179
+ );
3180
+ } else {
3181
+ return new GraphNodeCompoundTransform(
3182
+ ctx.nextId(),
3183
+ node,
3184
+ [pipedInGraphNode],
3185
+ outTypes,
3186
+ inTypes
3187
+ );
3188
+ }
3189
+ }
3190
+ }
3191
+ }
3192
+ }
3193
+ if (ts.isExpression(node)) {
3194
+ const type = typeChecker.getTypeAtLocation(node);
3195
+ const maybeLayer = yield* option(layerType(type, node));
3196
+ if (isSome2(maybeLayer)) {
3197
+ const { allIndexes: outTypes } = yield* appendToUniqueTypesMap(
3198
+ ctx.services,
3199
+ maybeLayer.value.ROut,
3200
+ true
3201
+ );
3202
+ const { allIndexes: inTypes } = yield* appendToUniqueTypesMap(
3203
+ ctx.services,
3204
+ maybeLayer.value.RIn,
3205
+ true
3206
+ );
3207
+ return new GraphNodeLeaf(ctx.nextId(), node, outTypes, inTypes);
3208
+ }
3209
+ }
3210
+ return yield* fail(new UnableToProduceLayerGraphError(node.getText()));
3211
+ });
3212
+ }
3213
+ function findInnermostGraphEdge(graph, kind, key) {
3214
+ switch (graph._tag) {
3215
+ case "GraphNodeLeaf":
3216
+ return graph[kind].indexOf(key) > -1 ? [graph] : [];
3217
+ case "GraphNodeCompoundTransform": {
3218
+ if (graph[kind].indexOf(key) > -1) {
3219
+ let result = [];
3220
+ for (const child of graph.args) {
3221
+ result = result.concat(findInnermostGraphEdge(child, kind, key));
3222
+ }
3223
+ if (result.length > 0) return result;
3224
+ return [graph];
3225
+ }
3226
+ return [];
3227
+ }
3228
+ }
3229
+ }
3230
+ function escapeMermaid(text) {
3231
+ return text.replace(/"/mg, "#quot;").replace(/\n/mg, " ");
3232
+ }
3233
+ function processNodeMermaid(graph, ctx, ctxL) {
3234
+ return gen2(function* () {
3235
+ const ts = yield* service(TypeScriptApi);
3236
+ const typeChecker = yield* service(TypeCheckerApi);
3237
+ let subgraphDefs = [];
3238
+ if (!ctx.seenIds.has(graph.id)) {
3239
+ const subgraphsIn = [];
3240
+ for (const serviceId of graph.rin) {
3241
+ const type = ctxL.services.get(serviceId);
3242
+ const typeString = typeChecker.typeToString(type, void 0, ts.TypeFormatFlags.NoTruncation);
3243
+ subgraphsIn.push("subgraph " + graph.id + "_rin_" + serviceId + ' ["`' + escapeMermaid(typeString) + '`"]');
3244
+ subgraphsIn.push("end");
3245
+ }
3246
+ const subgraphsOut = [];
3247
+ for (const serviceId of graph.rout) {
3248
+ const type = ctxL.services.get(serviceId);
3249
+ const typeString = typeChecker.typeToString(type, void 0, ts.TypeFormatFlags.NoTruncation);
3250
+ subgraphsOut.push("subgraph " + graph.id + "_rout_" + serviceId + ' ["`' + escapeMermaid(typeString) + '`"]');
3251
+ subgraphsOut.push("end");
3252
+ }
3253
+ const sourceFile = graph.node.getSourceFile();
3254
+ const nodePosition = graph.node.getStart(sourceFile, false);
3255
+ const { character, line } = ts.getLineAndCharacterOfPosition(sourceFile, nodePosition);
3256
+ if (subgraphsIn.length > 0) {
3257
+ subgraphDefs = [
3258
+ ...subgraphDefs,
3259
+ "subgraph " + graph.id + "_rin [Requires]",
3260
+ ...subgraphsIn,
3261
+ "end",
3262
+ "style " + graph.id + "_rin stroke:none"
3263
+ ];
3264
+ }
3265
+ if (subgraphsOut.length > 0) {
3266
+ subgraphDefs = [
3267
+ ...subgraphDefs,
3268
+ "subgraph " + graph.id + "_rout [Provides]",
3269
+ ...subgraphsOut,
3270
+ "end",
3271
+ "style " + graph.id + "_rout stroke:none"
3272
+ ];
3273
+ }
3274
+ subgraphDefs = [
3275
+ "subgraph " + graph.id + ' ["`' + escapeMermaid(graph.node.getText()) + " _at ln " + (line + 1) + " col " + character + '_`"]',
3276
+ ...subgraphDefs,
3277
+ "end",
3278
+ "style " + graph.id + " fill:transparent"
3279
+ ];
3280
+ ctx.seenIds.add(graph.id);
3281
+ }
3282
+ switch (graph._tag) {
3283
+ case "GraphNodeLeaf": {
3284
+ return subgraphDefs;
3285
+ }
3286
+ case "GraphNodeCompoundTransform": {
3287
+ const childs = flatten(yield* all2(...graph.args.map((_) => processNodeMermaid(_, ctx, ctxL))));
3288
+ let currentEdges = [];
3289
+ const connectedNodes = /* @__PURE__ */ new Set();
3290
+ for (const requiredServiceKey of graph.rin) {
3291
+ for (const childNode of graph.args.filter((childNode2) => childNode2.rin.indexOf(requiredServiceKey) > -1)) {
3292
+ currentEdges = [
3293
+ ...currentEdges,
3294
+ graph.id + "_rin_" + requiredServiceKey + " -.-> " + childNode.id + "_rin_" + requiredServiceKey
3295
+ ];
3296
+ connectedNodes.add(childNode.id);
3297
+ }
3298
+ }
3299
+ for (const providedServiceKey of graph.rout) {
3300
+ for (const childNode of graph.args.filter((childNode2) => childNode2.rout.indexOf(providedServiceKey) > -1)) {
3301
+ currentEdges = [
3302
+ ...currentEdges,
3303
+ graph.id + "_rout_" + providedServiceKey + " -.-> " + childNode.id + "_rout_" + providedServiceKey
3304
+ ];
3305
+ connectedNodes.add(childNode.id);
3306
+ }
3307
+ }
3308
+ for (const childNode of graph.args) {
3309
+ if (!connectedNodes.has(childNode.id)) {
3310
+ currentEdges = [...currentEdges, graph.id + " -.-x " + childNode.id];
3311
+ }
3312
+ }
3313
+ return [...subgraphDefs, ...childs, ...currentEdges];
3314
+ }
3315
+ }
3316
+ });
3317
+ }
3318
+ function generateMarmaidUri(graph, ctxL) {
3319
+ return gen2(function* () {
3320
+ const ctx = {
3321
+ seenIds: /* @__PURE__ */ new Set()
3322
+ };
3323
+ const lines = yield* processNodeMermaid(graph, ctx, ctxL);
3324
+ const code = "flowchart TB\n" + lines.join("\n");
3325
+ const state = btoa(JSON.stringify({ code }));
3326
+ return "https://www.mermaidchart.com/play#" + state;
3327
+ });
3328
+ }
3329
+ function layerInfo(sourceFile, position, quickInfo2) {
3330
+ return pipe(
3331
+ gen2(function* () {
3332
+ const ts = yield* service(TypeScriptApi);
3333
+ const typeChecker = yield* service(TypeCheckerApi);
3334
+ const range = toTextRange(position);
3335
+ const maybeNode = pipe(
3336
+ yield* getAncestorNodesInRange(sourceFile, range),
3337
+ filter((_) => ts.isVariableDeclaration(_) || ts.isPropertyDeclaration(_)),
3338
+ filter((_) => isNodeInRange(range)(_.name)),
3339
+ head
3340
+ );
3341
+ if (isNone2(maybeNode)) return quickInfo2;
3342
+ const node = maybeNode.value;
3343
+ const layerNode = node.initializer ? node.initializer : node;
3344
+ const layerType2 = typeChecker.getTypeAtLocation(layerNode);
3345
+ const maybeLayer = yield* option(layerType(layerType2, layerNode));
3346
+ if (isNone2(maybeLayer)) return quickInfo2;
3347
+ let lastId = 0;
3348
+ const graphCtx = {
3349
+ services: /* @__PURE__ */ new Map(),
3350
+ serviceTypeToString: /* @__PURE__ */ new Map(),
3351
+ nextId: () => "id" + lastId++
3352
+ };
3353
+ const layerInfoDisplayParts = yield* pipe(
3354
+ processLayerGraphNode(graphCtx, layerNode, void 0),
3355
+ flatMap3(
3356
+ (rootNode) => gen2(function* () {
3357
+ yield* succeed(void 0);
3358
+ const lines = [];
3359
+ const appendInfo = (providesNode, type, kindText) => {
3360
+ const typeString = typeChecker.typeToString(
3361
+ type,
3362
+ void 0,
3363
+ ts.TypeFormatFlags.NoTruncation
3364
+ );
3365
+ const positions = providesNode.map((_) => {
3366
+ const nodePosition = _.node.getStart(sourceFile, false);
3367
+ const { character, line } = ts.getLineAndCharacterOfPosition(sourceFile, nodePosition);
3368
+ const nodeText = _.node.getText().trim().substr(0, 100);
3369
+ return "ln " + (line + 1) + " col " + character + " by `" + nodeText + "`";
3370
+ });
3371
+ lines.push("- " + typeString + " " + kindText + " at " + positions.join(", "));
3372
+ };
3373
+ for (const providesKey of rootNode.rout) {
3374
+ const providesNode = findInnermostGraphEdge(rootNode, "rout", providesKey);
3375
+ appendInfo(providesNode, graphCtx.services.get(providesKey), "provided");
3376
+ }
3377
+ lines.push("");
3378
+ for (const requiresKey of rootNode.rin) {
3379
+ const requiresNode = findInnermostGraphEdge(rootNode, "rin", requiresKey);
3380
+ appendInfo(requiresNode, graphCtx.services.get(requiresKey), "required");
3381
+ }
3382
+ const mermaidUri = yield* option(generateMarmaidUri(rootNode, graphCtx));
3383
+ const linkParts = [];
3384
+ if (isSome2(mermaidUri)) {
3385
+ linkParts.push({ kind: "space", text: "\n" });
3386
+ linkParts.push({ kind: "link", text: "{@link " });
3387
+ linkParts.push({ kind: "linkText", text: mermaidUri.value + " Show full Layer graph" });
3388
+ linkParts.push({ kind: "link", text: "}" });
3389
+ linkParts.push({ kind: "space", text: "\n" });
3390
+ }
3391
+ return [
3392
+ {
3393
+ kind: "text",
3394
+ text: "```\n/**\n" + lines.map((l) => " * " + l).join("\n") + "\n */\n```\n"
3395
+ },
3396
+ ...linkParts
3397
+ ];
3398
+ })
3399
+ ),
3400
+ orElse3(
3401
+ (e) => succeed([{
3402
+ kind: "text",
3403
+ text: "```\n/** layer graph not created: " + e.message + " */\n```\n"
3404
+ }])
3405
+ )
3406
+ );
3407
+ if (!quickInfo2) {
3408
+ const start = node.getStart();
3409
+ const end = node.getEnd();
3410
+ return {
3411
+ kind: ts.ScriptElementKind.callSignatureElement,
3412
+ kindModifiers: "",
3413
+ textSpan: { start, length: end - start },
3414
+ documentation: layerInfoDisplayParts
3415
+ };
3416
+ }
3417
+ if (quickInfo2.documentation) {
3418
+ return {
3419
+ ...quickInfo2,
3420
+ documentation: quickInfo2.documentation.concat([{ kind: "space", text: "\n" }]).concat(layerInfoDisplayParts)
3421
+ };
3422
+ }
3423
+ return {
3424
+ ...quickInfo2,
3425
+ documentation: layerInfoDisplayParts
3426
+ };
3427
+ }),
3428
+ orElse3(() => succeed(quickInfo2))
3429
+ );
3430
+ }
3431
+
3432
+ // src/quickinfo.ts
3433
+ function quickInfo(sourceFile, position, quickInfo2) {
3434
+ return gen2(function* () {
3435
+ const deduped = yield* dedupeJsDocs(quickInfo2);
3436
+ const withEffectTypeArgs = yield* effectTypeArgs(sourceFile, position, deduped);
3437
+ const withLayerInfo = yield* layerInfo(sourceFile, position, withEffectTypeArgs);
3438
+ return withLayerInfo;
3439
+ });
3440
+ }
3441
+
2925
3442
  // src/refactors/asyncAwaitToGen.ts
2926
3443
  var asyncAwaitToGen = createRefactor({
2927
3444
  name: "asyncAwaitToGen",
@@ -3611,19 +4128,15 @@ var removeUnnecessaryEffectGen = createRefactor({
3611
4128
  description: "Remove unnecessary Effect.gen",
3612
4129
  apply: fn("removeUnnecessaryEffectGen.apply")(function* (sourceFile, textRange) {
3613
4130
  for (const nodeToReplace of yield* getAncestorNodesInRange(sourceFile, textRange)) {
3614
- const maybeNode = yield* pipe(
3615
- effectGen(nodeToReplace),
3616
- flatMap3(({ body }) => returnYieldEffectBlock(body)),
3617
- option
3618
- );
4131
+ const maybeNode = yield* option(unnecessaryEffectGen(nodeToReplace));
3619
4132
  if (isNone2(maybeNode)) continue;
3620
- const returnedYieldedEffect = maybeNode.value;
4133
+ const replacementNode = maybeNode.value.replacementNode;
3621
4134
  return {
3622
4135
  kind: "refactor.rewrite.effect.removeUnnecessaryEffectGen",
3623
4136
  description: "Remove unnecessary Effect.gen",
3624
4137
  apply: gen2(function* () {
3625
4138
  const changeTracker = yield* service(ChangeTracker);
3626
- changeTracker.replaceNode(sourceFile, nodeToReplace, returnedYieldedEffect);
4139
+ changeTracker.replaceNode(sourceFile, nodeToReplace, yield* replacementNode);
3627
4140
  })
3628
4141
  };
3629
4142
  }
@@ -4558,27 +5071,25 @@ var init = (modules) => {
4558
5071
  );
4559
5072
  };
4560
5073
  proxy.getQuickInfoAtPosition = (fileName, position, ...args) => {
4561
- const quickInfo = languageService.getQuickInfoAtPosition(fileName, position, ...args);
5074
+ const applicableQuickInfo = languageService.getQuickInfoAtPosition(fileName, position, ...args);
4562
5075
  if (languageServicePluginOptions.quickinfo) {
4563
- const dedupedTagsQuickInfo = dedupeJsDocTags(quickInfo);
4564
5076
  const program = languageService.getProgram();
4565
5077
  if (program) {
4566
5078
  const sourceFile = program.getSourceFile(fileName);
4567
5079
  if (sourceFile) {
4568
5080
  return pipe(
4569
- prependEffectTypeArguments(
5081
+ quickInfo(
4570
5082
  sourceFile,
4571
5083
  position,
4572
- dedupedTagsQuickInfo
5084
+ applicableQuickInfo
4573
5085
  ),
4574
5086
  runNano(program),
4575
- Either_exports.getOrElse(() => dedupedTagsQuickInfo)
5087
+ Either_exports.getOrElse(() => applicableQuickInfo)
4576
5088
  );
4577
5089
  }
4578
5090
  }
4579
- return dedupedTagsQuickInfo;
4580
5091
  }
4581
- return quickInfo;
5092
+ return applicableQuickInfo;
4582
5093
  };
4583
5094
  proxy.getCompletionsAtPosition = (fileName, position, options, formattingSettings, ...args) => {
4584
5095
  const applicableCompletions = languageService.getCompletionsAtPosition(