@effect/language-service 0.15.0 → 0.16.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/README.md +50 -48
- package/index.js +96 -48
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +33 -29
- package/transform.js.map +1 -1
package/README.md
CHANGED
|
@@ -26,12 +26,39 @@ This package implements a TypeScript language service plugin that allows additio
|
|
|
26
26
|
|
|
27
27
|
And you're done! You'll now be able to use a set of refactor and diagnostics that targets Effect!
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## Provided functionalities
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
### Quickinfo
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
- Show the extended type of the current Effect
|
|
34
|
+
- Hovering yield\* of Effect.gen will show the Effect type parameters
|
|
35
|
+
|
|
36
|
+
### Diagnostics
|
|
37
|
+
|
|
38
|
+
- Better error readability when you're missing errors or service types in your Effect definitions
|
|
39
|
+
- Floating Effects that are not yielded or run
|
|
40
|
+
- Wrong usage of yield inside Effect.gen
|
|
41
|
+
- Unnecessary usages of Effect.gen
|
|
42
|
+
- Multiple versions of Effect in your project
|
|
43
|
+
|
|
44
|
+
### Completions
|
|
45
|
+
|
|
46
|
+
- Autocomplete 'Self' in Effect.Service, Context.Tag, Schema.TaggedClass, Schema.TaggedRequest and family
|
|
47
|
+
|
|
48
|
+
### Refactors
|
|
49
|
+
|
|
50
|
+
- Transform an async function definition, into an Effect by using Effect.gen.
|
|
51
|
+
- Transform an async function definition, into an Effect by using Effect.gen, and generating a tagged error for each promise call.
|
|
52
|
+
- Transform a function returning an Effect.gen into a Effect.fn
|
|
53
|
+
- Function calls to pipe: Transform a set of function calls to a pipe() call.
|
|
54
|
+
- Pipe to datafirst: Transform a pipe() call into a series of datafirst function calls (where available).
|
|
55
|
+
- Toggle return type signature: With a single refactor, adds or removes type annotations from the definition.
|
|
56
|
+
- Remove unnecessary `Effect.gen` definitions that contains a single `yield` statement.
|
|
57
|
+
- Wrap an `Effect` expression with `Effect.gen`
|
|
58
|
+
|
|
59
|
+
## Options
|
|
60
|
+
|
|
61
|
+
Few options can be provided alongside the initialization of the Language Service Plugin.
|
|
35
62
|
|
|
36
63
|
```json
|
|
37
64
|
{
|
|
@@ -39,30 +66,22 @@ Your `tsconfig.json` should look like this:
|
|
|
39
66
|
"plugins": [
|
|
40
67
|
{
|
|
41
68
|
"name": "@effect/language-service",
|
|
42
|
-
"
|
|
69
|
+
"diagnostics": true, // controls Effect diagnostics (default: true)
|
|
70
|
+
"quickinfo": true, // controls quickinfo over Effect (default: true)
|
|
71
|
+
"completions": true, // controls Effect completions (default: true)
|
|
72
|
+
"multipleEffectCheck": true // controls if multiple versions of Effect are referenced (default: true)
|
|
43
73
|
}
|
|
44
74
|
]
|
|
45
75
|
}
|
|
46
76
|
}
|
|
47
77
|
```
|
|
48
78
|
|
|
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
|
-
```
|
|
79
|
+
## Why diagnostics does not appear at compile time?
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
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
82
|
|
|
65
|
-
|
|
83
|
+
HOWEVER, if you use `ts-patch` you can enable the transform as well to get the diagnostics also at compile time.
|
|
84
|
+
Your `tsconfig.json` should look like this:
|
|
66
85
|
|
|
67
86
|
```json
|
|
68
87
|
{
|
|
@@ -70,44 +89,27 @@ Few options can be provided alongside the initialization of the Language Service
|
|
|
70
89
|
"plugins": [
|
|
71
90
|
{
|
|
72
91
|
"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
|
|
92
|
+
"transform": "@effect/language-service/transform" // enables diagnostics at compile time when using ts-patch
|
|
77
93
|
}
|
|
78
94
|
]
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
```
|
|
82
98
|
|
|
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
|
|
99
|
+
To get diagnostics you need to install `ts-patch` which will make it possible to run `tspc`.
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
Running `tspc` in your project will now also run the plugin and give you the diagnostics at compile time.
|
|
102
|
+
Effect diagnostics will be shown only after standard TypeScript diagnostics has been satisfied.
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
```ts
|
|
105
|
+
$ npx tspc
|
|
106
|
+
index.ts:3:1 - error TS3: Effect must be yielded or assigned to a variable.
|
|
100
107
|
|
|
101
|
-
|
|
108
|
+
3 Effect.succeed(1)
|
|
109
|
+
~~~~~~~~~~~~~~~~~
|
|
102
110
|
|
|
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`
|
|
111
|
+
Found 1 error in index.ts:3
|
|
112
|
+
```
|
|
111
113
|
|
|
112
114
|
## Configuring diagnostics
|
|
113
115
|
|
package/index.js
CHANGED
|
@@ -1004,23 +1004,27 @@ var contextGet = (context, tag) => {
|
|
|
1004
1004
|
}
|
|
1005
1005
|
return none2();
|
|
1006
1006
|
};
|
|
1007
|
-
var
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
}
|
|
1007
|
+
var Proto = {
|
|
1008
|
+
run: () => {
|
|
1009
|
+
},
|
|
1011
1010
|
[Symbol.iterator]() {
|
|
1012
1011
|
return new SingleShotGen(new YieldWrap(this));
|
|
1013
1012
|
}
|
|
1014
1013
|
};
|
|
1014
|
+
function make3(run2) {
|
|
1015
|
+
const result = Object.create(Proto);
|
|
1016
|
+
result.run = run2;
|
|
1017
|
+
return result;
|
|
1018
|
+
}
|
|
1015
1019
|
var unsafeRun = (fa) => {
|
|
1016
1020
|
const result = fa.run(contextEmpty);
|
|
1017
1021
|
switch (result._tag) {
|
|
1018
1022
|
case "Left":
|
|
1019
|
-
return left2(result.
|
|
1023
|
+
return left2(result.value);
|
|
1020
1024
|
case "Defect":
|
|
1021
|
-
return left2(new NanoDefectException(result.
|
|
1025
|
+
return left2(new NanoDefectException(result.value));
|
|
1022
1026
|
case "Right":
|
|
1023
|
-
return right2(result.
|
|
1027
|
+
return right2(result.value);
|
|
1024
1028
|
}
|
|
1025
1029
|
};
|
|
1026
1030
|
var run = (fa) => {
|
|
@@ -1030,35 +1034,35 @@ var run = (fa) => {
|
|
|
1030
1034
|
return left2(new NanoDefectException(e));
|
|
1031
1035
|
}
|
|
1032
1036
|
};
|
|
1033
|
-
var succeed = (value) =>
|
|
1034
|
-
var fail = (value) =>
|
|
1035
|
-
var sync = (value) =>
|
|
1036
|
-
var flatMap3 = dual(2, (fa, f) =>
|
|
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() }));
|
|
1040
|
+
var flatMap3 = dual(2, (fa, f) => make3((ctx) => {
|
|
1037
1041
|
const result = fa.run(ctx);
|
|
1038
1042
|
if (result._tag !== "Right") return result;
|
|
1039
|
-
return f(result.
|
|
1043
|
+
return f(result.value).run(ctx);
|
|
1040
1044
|
}));
|
|
1041
|
-
var map3 = dual(2, (fa, f) =>
|
|
1045
|
+
var map3 = dual(2, (fa, f) => make3((ctx) => {
|
|
1042
1046
|
const result = fa.run(ctx);
|
|
1043
1047
|
if (result._tag !== "Right") return result;
|
|
1044
|
-
return { _tag: "Right",
|
|
1048
|
+
return { _tag: "Right", value: f(result.value) };
|
|
1045
1049
|
}));
|
|
1046
|
-
var orElse3 = (f) => (fa) =>
|
|
1050
|
+
var orElse3 = (f) => (fa) => make3((ctx) => {
|
|
1047
1051
|
const result = fa.run(ctx);
|
|
1048
|
-
if (result._tag === "Left") return f(result.
|
|
1052
|
+
if (result._tag === "Left") return f(result.value).run(ctx);
|
|
1049
1053
|
return result;
|
|
1050
1054
|
});
|
|
1051
1055
|
var firstSuccessOf = (arr) => reduce(arr.slice(1), arr[0], (arr2, fa) => orElse3(() => fa)(arr2));
|
|
1052
|
-
var service = (tag) =>
|
|
1056
|
+
var service = (tag) => make3(
|
|
1053
1057
|
(ctx) => contextGet(ctx, tag).pipe(match2({
|
|
1054
|
-
onNone: () => ({ _tag: "Defect",
|
|
1055
|
-
onSome: (value) => ({ _tag: "Right",
|
|
1058
|
+
onNone: () => ({ _tag: "Defect", value: `Cannot find service ${tag.key}` }),
|
|
1059
|
+
onSome: (value) => ({ _tag: "Right", value })
|
|
1056
1060
|
}))
|
|
1057
1061
|
);
|
|
1058
|
-
var provideService = (tag, value) => (fa) =>
|
|
1062
|
+
var provideService = (tag, value) => (fa) => make3((ctx) => {
|
|
1059
1063
|
return fa.run(contextAdd(ctx, tag, value));
|
|
1060
1064
|
});
|
|
1061
|
-
var gen2 = (...args) =>
|
|
1065
|
+
var gen2 = (...args) => make3((ctx) => {
|
|
1062
1066
|
const iterator = args[0]();
|
|
1063
1067
|
let state = iterator.next();
|
|
1064
1068
|
while (!state.done) {
|
|
@@ -1067,11 +1071,11 @@ var gen2 = (...args) => new Nano((ctx) => {
|
|
|
1067
1071
|
if (result._tag !== "Right") {
|
|
1068
1072
|
return result;
|
|
1069
1073
|
}
|
|
1070
|
-
state = iterator.next(result.
|
|
1074
|
+
state = iterator.next(result.value);
|
|
1071
1075
|
}
|
|
1072
|
-
return { _tag: "Right",
|
|
1076
|
+
return { _tag: "Right", value: state.value };
|
|
1073
1077
|
});
|
|
1074
|
-
var fn = (_) => (body) => (...args) =>
|
|
1078
|
+
var fn = (_) => (body) => (...args) => make3((ctx) => {
|
|
1075
1079
|
const iterator = body(...args);
|
|
1076
1080
|
let state = iterator.next();
|
|
1077
1081
|
while (!state.done) {
|
|
@@ -1080,17 +1084,17 @@ var fn = (_) => (body) => (...args) => new Nano((ctx) => {
|
|
|
1080
1084
|
if (result._tag !== "Right") {
|
|
1081
1085
|
return result;
|
|
1082
1086
|
}
|
|
1083
|
-
state = iterator.next(result.
|
|
1087
|
+
state = iterator.next(result.value);
|
|
1084
1088
|
}
|
|
1085
|
-
return { _tag: "Right",
|
|
1089
|
+
return { _tag: "Right", value: state.value };
|
|
1086
1090
|
});
|
|
1087
|
-
var option = (fa) =>
|
|
1091
|
+
var option = (fa) => make3((ctx) => {
|
|
1088
1092
|
const result = fa.run(ctx);
|
|
1089
1093
|
switch (result._tag) {
|
|
1090
1094
|
case "Right":
|
|
1091
|
-
return { _tag: "Right",
|
|
1095
|
+
return { _tag: "Right", value: some2(result.value) };
|
|
1092
1096
|
case "Left":
|
|
1093
|
-
return { _tag: "Right",
|
|
1097
|
+
return { _tag: "Right", value: none2() };
|
|
1094
1098
|
case "Defect":
|
|
1095
1099
|
return result;
|
|
1096
1100
|
}
|
|
@@ -2610,6 +2614,7 @@ var JSDocTagInfoEq = make(
|
|
|
2610
2614
|
(fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? array(SymbolDisplayPartEq)(fa.text, fb.text) : true)
|
|
2611
2615
|
);
|
|
2612
2616
|
function dedupeJsDocTags(quickInfo) {
|
|
2617
|
+
if (!quickInfo) return quickInfo;
|
|
2613
2618
|
if (quickInfo.tags) {
|
|
2614
2619
|
return {
|
|
2615
2620
|
...quickInfo,
|
|
@@ -2635,21 +2640,33 @@ function prependEffectTypeArguments(sourceFile, position, quickInfo) {
|
|
|
2635
2640
|
gen2(function* () {
|
|
2636
2641
|
const ts = yield* service(TypeScriptApi);
|
|
2637
2642
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
2638
|
-
const hasTruncationHappened = ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
|
|
2639
|
-
if (!hasTruncationHappened) return quickInfo;
|
|
2640
2643
|
const maybeNode = pipe(
|
|
2641
2644
|
yield* getAncestorNodesInRange(sourceFile, toTextRange(position)),
|
|
2642
2645
|
head
|
|
2643
2646
|
);
|
|
2644
2647
|
if (isNone2(maybeNode)) return quickInfo;
|
|
2648
|
+
const node = maybeNode.value;
|
|
2649
|
+
const hasTruncationHappened = quickInfo && ts.displayPartsToString(quickInfo.displayParts).indexOf("...") > -1;
|
|
2650
|
+
const nodeForType = !quickInfo && ts.isYieldExpression(node) && node.asteriskToken && node.expression ? node.expression : hasTruncationHappened ? node : void 0;
|
|
2651
|
+
if (!nodeForType) return quickInfo;
|
|
2645
2652
|
const effectType2 = yield* effectType(
|
|
2646
|
-
typeChecker.getTypeAtLocation(
|
|
2647
|
-
|
|
2653
|
+
typeChecker.getTypeAtLocation(nodeForType),
|
|
2654
|
+
nodeForType
|
|
2648
2655
|
);
|
|
2649
2656
|
const effectTypeArgsDocumentation = [{
|
|
2650
2657
|
kind: "text",
|
|
2651
2658
|
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"
|
|
2652
2659
|
}];
|
|
2660
|
+
if (!quickInfo) {
|
|
2661
|
+
const start = node.getStart();
|
|
2662
|
+
const end = node.getEnd();
|
|
2663
|
+
return {
|
|
2664
|
+
kind: ts.ScriptElementKind.callSignatureElement,
|
|
2665
|
+
kindModifiers: "",
|
|
2666
|
+
textSpan: { start, length: end - start },
|
|
2667
|
+
documentation: effectTypeArgsDocumentation
|
|
2668
|
+
};
|
|
2669
|
+
}
|
|
2653
2670
|
if (quickInfo.documentation) {
|
|
2654
2671
|
return {
|
|
2655
2672
|
...quickInfo,
|
|
@@ -3595,6 +3612,7 @@ var makeSchemaGenContext = fn("SchemaGen.makeSchemaGenContext")(function* (sourc
|
|
|
3595
3612
|
case "Date":
|
|
3596
3613
|
case "Pick":
|
|
3597
3614
|
case "Omit":
|
|
3615
|
+
case "Record":
|
|
3598
3616
|
return some2(name.text);
|
|
3599
3617
|
case "ReadonlyArray":
|
|
3600
3618
|
case "Array":
|
|
@@ -3631,8 +3649,17 @@ var parseAllLiterals = fn(
|
|
|
3631
3649
|
)(
|
|
3632
3650
|
function* (node) {
|
|
3633
3651
|
const { ts } = yield* service(SchemaGenContext);
|
|
3634
|
-
if (ts.isLiteralTypeNode(node)
|
|
3635
|
-
|
|
3652
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
3653
|
+
switch (node.literal.kind) {
|
|
3654
|
+
case ts.SyntaxKind.StringLiteral:
|
|
3655
|
+
return [ts.factory.createStringLiteral(node.literal.text)];
|
|
3656
|
+
case ts.SyntaxKind.NumericLiteral:
|
|
3657
|
+
return [ts.factory.createNumericLiteral(node.literal.text)];
|
|
3658
|
+
case ts.SyntaxKind.TrueKeyword:
|
|
3659
|
+
return [ts.factory.createTrue()];
|
|
3660
|
+
case ts.SyntaxKind.FalseKeyword:
|
|
3661
|
+
return [ts.factory.createFalse()];
|
|
3662
|
+
}
|
|
3636
3663
|
}
|
|
3637
3664
|
if (ts.isUnionTypeNode(node)) {
|
|
3638
3665
|
return flatten(yield* all2(...node.types.map((_) => parseAllLiterals(_))));
|
|
@@ -3675,23 +3702,30 @@ var processNode = (node) => gen2(function* () {
|
|
|
3675
3702
|
return createApiPropertyAccess("BigInt");
|
|
3676
3703
|
}
|
|
3677
3704
|
if (ts.isLiteralTypeNode(node)) {
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
case ts.SyntaxKind.TrueKeyword:
|
|
3682
|
-
return createApiCall("Literal", [ts.factory.createTrue()]);
|
|
3683
|
-
case ts.SyntaxKind.FalseKeyword:
|
|
3684
|
-
return createApiCall("Literal", [ts.factory.createFalse()]);
|
|
3685
|
-
case ts.SyntaxKind.StringLiteral:
|
|
3686
|
-
return createApiCall("Literal", [ts.factory.createStringLiteral(node.literal.text)]);
|
|
3687
|
-
case ts.SyntaxKind.NumericLiteral:
|
|
3688
|
-
return createApiCall("Literal", [ts.factory.createNumericLiteral(node.literal.text)]);
|
|
3689
|
-
}
|
|
3705
|
+
if (node.literal.kind === ts.SyntaxKind.NullKeyword) return createApiPropertyAccess("Null");
|
|
3706
|
+
const literalMembers = yield* option(parseAllLiterals(node));
|
|
3707
|
+
if (isSome2(literalMembers)) return createApiCall("Literal", literalMembers.value);
|
|
3690
3708
|
}
|
|
3691
3709
|
if (ts.isUnionTypeNode(node)) {
|
|
3710
|
+
const allLiterals = yield* option(parseAllLiterals(node));
|
|
3711
|
+
if (isSome2(allLiterals)) return createApiCall("Literal", allLiterals.value);
|
|
3692
3712
|
const members = yield* all2(...node.types.map((_) => processNode(_)));
|
|
3693
3713
|
return createApiCall("Union", members);
|
|
3694
3714
|
}
|
|
3715
|
+
if (ts.isIntersectionTypeNode(node)) {
|
|
3716
|
+
const [firstSchema, ...otherSchemas] = yield* all2(
|
|
3717
|
+
...node.types.map((_) => processNode(_))
|
|
3718
|
+
);
|
|
3719
|
+
if (otherSchemas.length === 0) return firstSchema;
|
|
3720
|
+
return ts.factory.createCallExpression(
|
|
3721
|
+
ts.factory.createPropertyAccessExpression(
|
|
3722
|
+
firstSchema,
|
|
3723
|
+
"pipe"
|
|
3724
|
+
),
|
|
3725
|
+
[],
|
|
3726
|
+
otherSchemas.map((_) => createApiCall("extend", [_]))
|
|
3727
|
+
);
|
|
3728
|
+
}
|
|
3695
3729
|
if (ts.isArrayTypeNode(node)) {
|
|
3696
3730
|
const typeSchema = yield* processNode(node.elementType);
|
|
3697
3731
|
return createApiCall("Array", [typeSchema]);
|
|
@@ -3718,6 +3752,20 @@ var processNode = (node) => gen2(function* () {
|
|
|
3718
3752
|
);
|
|
3719
3753
|
return createApiCall(parsedName.value, elements);
|
|
3720
3754
|
}
|
|
3755
|
+
case "Record": {
|
|
3756
|
+
const elements = yield* all2(
|
|
3757
|
+
...node.typeArguments ? node.typeArguments.map(processNode) : []
|
|
3758
|
+
);
|
|
3759
|
+
if (elements.length >= 2) {
|
|
3760
|
+
return createApiCall(parsedName.value, [
|
|
3761
|
+
ts.factory.createObjectLiteralExpression([
|
|
3762
|
+
ts.factory.createPropertyAssignment("key", elements[0]),
|
|
3763
|
+
ts.factory.createPropertyAssignment("value", elements[1])
|
|
3764
|
+
])
|
|
3765
|
+
]);
|
|
3766
|
+
}
|
|
3767
|
+
return createUnsupportedNodeComment(ts, sourceFile, node);
|
|
3768
|
+
}
|
|
3721
3769
|
case "Either": {
|
|
3722
3770
|
const elements = yield* all2(
|
|
3723
3771
|
...node.typeArguments ? node.typeArguments.map(processNode) : []
|
|
@@ -4252,7 +4300,7 @@ var init = (modules) => {
|
|
|
4252
4300
|
};
|
|
4253
4301
|
proxy.getQuickInfoAtPosition = (fileName, position, ...args) => {
|
|
4254
4302
|
const quickInfo = languageService.getQuickInfoAtPosition(fileName, position, ...args);
|
|
4255
|
-
if (pluginOptions.quickinfo
|
|
4303
|
+
if (pluginOptions.quickinfo) {
|
|
4256
4304
|
const dedupedTagsQuickInfo = dedupeJsDocTags(quickInfo);
|
|
4257
4305
|
const program = languageService.getProgram();
|
|
4258
4306
|
if (program) {
|