@effect/language-service 0.15.1 → 0.16.1

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/README.md CHANGED
@@ -23,15 +23,43 @@ This package implements a TypeScript language service plugin that allows additio
23
23
 
24
24
  - In VSCode you can do this by pressing "F1" and typing "TypeScript: Select TypeScript version". Then select "Use workspace version".
25
25
  - In JetBrains you may have to disable the Vue language service, and chose the workspace version of TypeScript in the settings from the dropdown.
26
+ - In NVim with nvim-vtsls you should refer to [how to enable TypeScript plugins in vstls](https://github.com/yioneko/vtsls?tab=readme-ov-file#typescript-plugin-not-activated)
26
27
 
27
28
  And you're done! You'll now be able to use a set of refactor and diagnostics that targets Effect!
28
29
 
29
- ## Enable diagnostics at compile time
30
+ ## Provided functionalities
30
31
 
31
- TypeScript LSP are loaded only while editing your files. That means that if you run `tsc` in your project, the plugin won't be loaded and you'll miss out on the Effect diagnostics.
32
+ ### Quickinfo
32
33
 
33
- HOWEVER, if you use `ts-patch` you can enable the transform as well to get the diagnostics also at compile time.
34
- Your `tsconfig.json` should look like this:
34
+ - Show the extended type of the current Effect
35
+ - Hovering yield\* of Effect.gen will show the Effect type parameters
36
+
37
+ ### Diagnostics
38
+
39
+ - Better error readability when you're missing errors or service types in your Effect definitions
40
+ - Floating Effects that are not yielded or run
41
+ - Wrong usage of yield inside Effect.gen
42
+ - Unnecessary usages of Effect.gen
43
+ - Multiple versions of Effect in your project
44
+
45
+ ### Completions
46
+
47
+ - Autocomplete 'Self' in Effect.Service, Context.Tag, Schema.TaggedClass, Schema.TaggedRequest and family
48
+
49
+ ### Refactors
50
+
51
+ - Transform an async function definition, into an Effect by using Effect.gen.
52
+ - Transform an async function definition, into an Effect by using Effect.gen, and generating a tagged error for each promise call.
53
+ - Transform a function returning an Effect.gen into a Effect.fn
54
+ - Function calls to pipe: Transform a set of function calls to a pipe() call.
55
+ - Pipe to datafirst: Transform a pipe() call into a series of datafirst function calls (where available).
56
+ - Toggle return type signature: With a single refactor, adds or removes type annotations from the definition.
57
+ - Remove unnecessary `Effect.gen` definitions that contains a single `yield` statement.
58
+ - Wrap an `Effect` expression with `Effect.gen`
59
+
60
+ ## Options
61
+
62
+ Few options can be provided alongside the initialization of the Language Service Plugin.
35
63
 
36
64
  ```json
37
65
  {
@@ -39,30 +67,22 @@ Your `tsconfig.json` should look like this:
39
67
  "plugins": [
40
68
  {
41
69
  "name": "@effect/language-service",
42
- "transform": "@effect/language-service/transform" // enables diagnostics at compile time when using ts-patch
70
+ "diagnostics": true, // controls Effect diagnostics (default: true)
71
+ "quickinfo": true, // controls quickinfo over Effect (default: true)
72
+ "completions": true, // controls Effect completions (default: true)
73
+ "multipleEffectCheck": true // controls if multiple versions of Effect are referenced (default: true)
43
74
  }
44
75
  ]
45
76
  }
46
77
  }
47
78
  ```
48
79
 
49
- To get diagnostics you need to install `ts-patch` which will make it possible to run `tspc`.
50
-
51
- Running `tspc` in your project will now also run the plugin and give you the diagnostics at compile time.
52
-
53
- ```ts
54
- $ npx tspc
55
- index.ts:3:1 - error TS3: Effect must be yielded or assigned to a variable.
56
-
57
- 3 Effect.succeed(1)
58
- ~~~~~~~~~~~~~~~~~
59
-
60
- Found 1 error in index.ts:3 
61
- ```
80
+ ## Why diagnostics does not appear at compile time?
62
81
 
63
- ## Options
82
+ TypeScript LSP are loaded only while editing your files. That means that if you run `tsc` in your project, the plugin won't be loaded and you'll miss out on the Effect diagnostics.
64
83
 
65
- Few options can be provided alongside the initialization of the Language Service Plugin.
84
+ HOWEVER, if you use `ts-patch` you can enable the transform as well to get the diagnostics also at compile time.
85
+ Your `tsconfig.json` should look like this:
66
86
 
67
87
  ```json
68
88
  {
@@ -70,44 +90,27 @@ Few options can be provided alongside the initialization of the Language Service
70
90
  "plugins": [
71
91
  {
72
92
  "name": "@effect/language-service",
73
- "diagnostics": true, // controls Effect diagnostics
74
- "quickinfo": true, // controls quickinfo over Effect
75
- "completions": true, // controls Effect completions
76
- "multipleEffectCheck": true // controls if multiple versions of Effect are referenced
93
+ "transform": "@effect/language-service/transform" // enables diagnostics at compile time when using ts-patch
77
94
  }
78
95
  ]
79
96
  }
80
97
  }
81
98
  ```
82
99
 
83
- ## Provided functionalities
84
-
85
- ### Quickinfo
86
-
87
- - Show the extended type of the current Effect
88
-
89
- ### Diagnostics
90
-
91
- - Better error readability when you're missing errors or service types in your Effect definitions
92
- - Floating Effects that are not yielded or run
93
- - Wrong usage of yield inside Effect.gen
94
- - Unnecessary usages of Effect.gen
95
- - Multiple versions of Effect in your project
100
+ To get diagnostics you need to install `ts-patch` which will make it possible to run `tspc`.
96
101
 
97
- ### Completions
102
+ Running `tspc` in your project will now also run the plugin and give you the diagnostics at compile time.
103
+ Effect diagnostics will be shown only after standard TypeScript diagnostics has been satisfied.
98
104
 
99
- - Autocomplete 'Self' in Effect.Service, Context.Tag, Schema.TaggedClass, Schema.TaggedRequest and family
105
+ ```ts
106
+ $ npx tspc
107
+ index.ts:3:1 - error TS3: Effect must be yielded or assigned to a variable.
100
108
 
101
- ### Refactors
109
+ 3 Effect.succeed(1)
110
+ ~~~~~~~~~~~~~~~~~
102
111
 
103
- - Transform an async function definition, into an Effect by using Effect.gen.
104
- - Transform an async function definition, into an Effect by using Effect.gen, and generating a tagged error for each promise call.
105
- - Transform a function returning an Effect.gen into a Effect.fn
106
- - Function calls to pipe: Transform a set of function calls to a pipe() call.
107
- - Pipe to datafirst: Transform a pipe() call into a series of datafirst function calls (where available).
108
- - Toggle return type signature: With a single refactor, adds or removes type annotations from the definition.
109
- - Remove unnecessary `Effect.gen` definitions that contains a single `yield` statement.
110
- - Wrap an `Effect` expression with `Effect.gen`
112
+ Found 1 error in index.ts:3 
113
+ ```
111
114
 
112
115
  ## Configuring diagnostics
113
116
 
package/index.js CHANGED
@@ -961,7 +961,6 @@ var filter = /* @__PURE__ */ dual(2, (self, predicate) => {
961
961
  }
962
962
  return out;
963
963
  });
964
- var reduce = /* @__PURE__ */ dual(3, (self, b, f) => fromIterable(self).reduce((b2, a, i) => f(b2, a, i), b));
965
964
  var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
966
965
  const input = fromIterable(self);
967
966
  if (isNonEmptyReadonlyArray(input)) {
@@ -978,6 +977,30 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
978
977
  });
979
978
 
980
979
  // src/core/Nano.ts
980
+ var NanoInternalSuccessProto = {
981
+ _tag: "Right"
982
+ };
983
+ function makeInternalSuccess(value) {
984
+ const result = Object.create(NanoInternalSuccessProto);
985
+ result.value = value;
986
+ return result;
987
+ }
988
+ var NanoInternalFailureProto = {
989
+ _tag: "Left"
990
+ };
991
+ function makeInternalFailure(value) {
992
+ const result = Object.create(NanoInternalFailureProto);
993
+ result.value = value;
994
+ return result;
995
+ }
996
+ var NanoInternalDefectProto = {
997
+ _tag: "Defect"
998
+ };
999
+ function makeInternalDefect(value) {
1000
+ const result = Object.create(NanoInternalDefectProto);
1001
+ result.value = value;
1002
+ return result;
1003
+ }
981
1004
  var NanoDefectException = class {
982
1005
  constructor(message) {
983
1006
  this.message = message;
@@ -991,19 +1014,6 @@ var NanoTag = class {
991
1014
  };
992
1015
  var Tag = (identifier) => new NanoTag(identifier);
993
1016
  var contextEmpty = { value: {} };
994
- var contextAdd = (context, tag, value) => ({
995
- ...context,
996
- value: {
997
- ...context.value,
998
- [tag.key]: value
999
- }
1000
- });
1001
- var contextGet = (context, tag) => {
1002
- if (tag.key in context.value) {
1003
- return some2(context.value[tag.key]);
1004
- }
1005
- return none2();
1006
- };
1007
1017
  var Proto = {
1008
1018
  run: () => {
1009
1019
  },
@@ -1034,9 +1044,9 @@ var run = (fa) => {
1034
1044
  return left2(new NanoDefectException(e));
1035
1045
  }
1036
1046
  };
1037
- var succeed = (value) => make3(() => ({ _tag: "Right", value }));
1038
- var fail = (value) => make3(() => ({ _tag: "Left", value }));
1039
- var sync = (value) => make3(() => ({ _tag: "Right", value: value() }));
1047
+ var succeed = (value) => make3(() => makeInternalSuccess(value));
1048
+ var fail = (value) => make3(() => makeInternalFailure(value));
1049
+ var sync = (value) => make3(() => makeInternalSuccess(value()));
1040
1050
  var flatMap3 = dual(2, (fa, f) => make3((ctx) => {
1041
1051
  const result = fa.run(ctx);
1042
1052
  if (result._tag !== "Right") return result;
@@ -1045,22 +1055,25 @@ var flatMap3 = dual(2, (fa, f) => make3((ctx) => {
1045
1055
  var map3 = dual(2, (fa, f) => make3((ctx) => {
1046
1056
  const result = fa.run(ctx);
1047
1057
  if (result._tag !== "Right") return result;
1048
- return { _tag: "Right", value: f(result.value) };
1058
+ return makeInternalSuccess(f(result.value));
1049
1059
  }));
1050
1060
  var orElse3 = (f) => (fa) => make3((ctx) => {
1051
1061
  const result = fa.run(ctx);
1052
1062
  if (result._tag === "Left") return f(result.value).run(ctx);
1053
1063
  return result;
1054
1064
  });
1055
- var firstSuccessOf = (arr) => reduce(arr.slice(1), arr[0], (arr2, fa) => orElse3(() => fa)(arr2));
1065
+ var firstSuccessOf = (arr) => arr.slice(1).reduce((arr2, fa) => orElse3(() => fa)(arr2), arr[0]);
1056
1066
  var service = (tag) => make3(
1057
- (ctx) => contextGet(ctx, tag).pipe(match2({
1058
- onNone: () => ({ _tag: "Defect", value: `Cannot find service ${tag.key}` }),
1059
- onSome: (value) => ({ _tag: "Right", value })
1060
- }))
1067
+ (ctx) => tag.key in ctx.value ? makeInternalSuccess(ctx.value[tag.key]) : makeInternalDefect(`Cannot find service ${tag.key}`)
1061
1068
  );
1062
1069
  var provideService = (tag, value) => (fa) => make3((ctx) => {
1063
- return fa.run(contextAdd(ctx, tag, value));
1070
+ return fa.run({
1071
+ ...ctx,
1072
+ value: {
1073
+ ...ctx.value,
1074
+ [tag.key]: value
1075
+ }
1076
+ });
1064
1077
  });
1065
1078
  var gen2 = (...args) => make3((ctx) => {
1066
1079
  const iterator = args[0]();
@@ -1073,7 +1086,7 @@ var gen2 = (...args) => make3((ctx) => {
1073
1086
  }
1074
1087
  state = iterator.next(result.value);
1075
1088
  }
1076
- return { _tag: "Right", value: state.value };
1089
+ return makeInternalSuccess(state.value);
1077
1090
  });
1078
1091
  var fn = (_) => (body) => (...args) => make3((ctx) => {
1079
1092
  const iterator = body(...args);
@@ -1086,15 +1099,15 @@ var fn = (_) => (body) => (...args) => make3((ctx) => {
1086
1099
  }
1087
1100
  state = iterator.next(result.value);
1088
1101
  }
1089
- return { _tag: "Right", value: state.value };
1102
+ return makeInternalSuccess(state.value);
1090
1103
  });
1091
1104
  var option = (fa) => make3((ctx) => {
1092
1105
  const result = fa.run(ctx);
1093
1106
  switch (result._tag) {
1094
1107
  case "Right":
1095
- return { _tag: "Right", value: some2(result.value) };
1108
+ return makeInternalSuccess(some2(result.value));
1096
1109
  case "Left":
1097
- return { _tag: "Right", value: none2() };
1110
+ return makeInternalSuccess(none2());
1098
1111
  case "Defect":
1099
1112
  return result;
1100
1113
  }
@@ -1468,7 +1481,9 @@ function createCompletion(definition) {
1468
1481
  return definition;
1469
1482
  }
1470
1483
  var PluginOptions = Tag("PluginOptions");
1471
- var getSemanticDiagnosticsWithCodeFixes = fn("LSP.getSemanticDiagnostics")(function* (rules, sourceFile) {
1484
+ var getSemanticDiagnosticsWithCodeFixes = fn(
1485
+ "LSP.getSemanticDiagnosticsWithCodeFixes"
1486
+ )(function* (rules, sourceFile) {
1472
1487
  const effectDiagnostics = [];
1473
1488
  const effectCodeFixes = [];
1474
1489
  const executor = yield* createDiagnosticExecutor(sourceFile);
@@ -2570,9 +2585,7 @@ var unnecessaryEffectGen = createDiagnostic({
2570
2585
  option
2571
2586
  );
2572
2587
  if (isSome2(maybeNode)) {
2573
- if (isSome2(maybeNode)) {
2574
- unnecessaryGenerators.set(node, maybeNode.value);
2575
- }
2588
+ unnecessaryGenerators.set(node, maybeNode.value);
2576
2589
  }
2577
2590
  }
2578
2591
  unnecessaryGenerators.forEach(
@@ -2614,6 +2627,7 @@ var JSDocTagInfoEq = make(
2614
2627
  (fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? array(SymbolDisplayPartEq)(fa.text, fb.text) : true)
2615
2628
  );
2616
2629
  function dedupeJsDocTags(quickInfo) {
2630
+ if (!quickInfo) return quickInfo;
2617
2631
  if (quickInfo.tags) {
2618
2632
  return {
2619
2633
  ...quickInfo,
@@ -2639,21 +2653,33 @@ function prependEffectTypeArguments(sourceFile, position, quickInfo) {
2639
2653
  gen2(function* () {
2640
2654
  const ts = yield* service(TypeScriptApi);
2641
2655
  const typeChecker = yield* service(TypeCheckerApi);
2642
- const hasTruncationHappened = ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
2643
- if (!hasTruncationHappened) return quickInfo;
2644
2656
  const maybeNode = pipe(
2645
2657
  yield* getAncestorNodesInRange(sourceFile, toTextRange(position)),
2646
2658
  head
2647
2659
  );
2648
2660
  if (isNone2(maybeNode)) return quickInfo;
2661
+ const node = maybeNode.value;
2662
+ const hasTruncationHappened = quickInfo && ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
2663
+ const nodeForType = !quickInfo && ts.isYieldExpression(node) && node.asteriskToken && node.expression ? node.expression : hasTruncationHappened ? node : void 0;
2664
+ if (!nodeForType) return quickInfo;
2649
2665
  const effectType2 = yield* effectType(
2650
- typeChecker.getTypeAtLocation(maybeNode.value),
2651
- maybeNode.value
2666
+ typeChecker.getTypeAtLocation(nodeForType),
2667
+ nodeForType
2652
2668
  );
2653
2669
  const effectTypeArgsDocumentation = [{
2654
2670
  kind: "text",
2655
2671
  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"
2656
2672
  }];
2673
+ if (!quickInfo) {
2674
+ const start = node.getStart();
2675
+ const end = node.getEnd();
2676
+ return {
2677
+ kind: ts.ScriptElementKind.callSignatureElement,
2678
+ kindModifiers: "",
2679
+ textSpan: { start, length: end - start },
2680
+ documentation: effectTypeArgsDocumentation
2681
+ };
2682
+ }
2657
2683
  if (quickInfo.documentation) {
2658
2684
  return {
2659
2685
  ...quickInfo,
@@ -4287,7 +4313,7 @@ var init = (modules) => {
4287
4313
  };
4288
4314
  proxy.getQuickInfoAtPosition = (fileName, position, ...args) => {
4289
4315
  const quickInfo = languageService.getQuickInfoAtPosition(fileName, position, ...args);
4290
- if (pluginOptions.quickinfo && quickInfo) {
4316
+ if (pluginOptions.quickinfo) {
4291
4317
  const dedupedTagsQuickInfo = dedupeJsDocTags(quickInfo);
4292
4318
  const program = languageService.getProgram();
4293
4319
  if (program) {