@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 +51 -48
- package/index.js +63 -37
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +49 -39
- package/transform.js.map +1 -1
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
|
-
##
|
|
30
|
+
## Provided functionalities
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
### Quickinfo
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
+
```ts
|
|
106
|
+
$ npx tspc
|
|
107
|
+
index.ts:3:1 - error TS3: Effect must be yielded or assigned to a variable.
|
|
100
108
|
|
|
101
|
-
|
|
109
|
+
3 Effect.succeed(1)
|
|
110
|
+
~~~~~~~~~~~~~~~~~
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
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(() => (
|
|
1038
|
-
var fail = (value) => make3(() => (
|
|
1039
|
-
var sync = (value) => make3(() => (
|
|
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
|
|
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) =>
|
|
1065
|
+
var firstSuccessOf = (arr) => arr.slice(1).reduce((arr2, fa) => orElse3(() => fa)(arr2), arr[0]);
|
|
1056
1066
|
var service = (tag) => make3(
|
|
1057
|
-
(ctx) =>
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
1108
|
+
return makeInternalSuccess(some2(result.value));
|
|
1096
1109
|
case "Left":
|
|
1097
|
-
return
|
|
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(
|
|
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
|
-
|
|
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(
|
|
2651
|
-
|
|
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
|
|
4316
|
+
if (pluginOptions.quickinfo) {
|
|
4291
4317
|
const dedupedTagsQuickInfo = dedupeJsDocTags(quickInfo);
|
|
4292
4318
|
const program = languageService.getProgram();
|
|
4293
4319
|
if (program) {
|