@effect/language-service 0.84.2 → 0.85.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 +11 -0
- package/cli.js +945 -270
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +529 -103
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +539 -113
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/schema.json +132 -0
- package/transform.js +529 -103
- package/transform.js.map +1 -1
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
3
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Pipeable.js
|
|
4
4
|
var pipeArguments = (self, args3) => {
|
|
5
5
|
switch (args3.length) {
|
|
6
6
|
case 0:
|
|
@@ -44,7 +44,7 @@ var Class = /* @__PURE__ */ (function() {
|
|
|
44
44
|
return PipeableBase;
|
|
45
45
|
})();
|
|
46
46
|
|
|
47
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
47
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Function.js
|
|
48
48
|
var dual = function(arity, body) {
|
|
49
49
|
if (typeof arity === "function") {
|
|
50
50
|
return function() {
|
|
@@ -92,9 +92,9 @@ function pipe(a, ...args3) {
|
|
|
92
92
|
return pipeArguments(a, args3);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
95
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Equivalence.js
|
|
96
96
|
var make = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that);
|
|
97
|
-
function
|
|
97
|
+
function Array_(item) {
|
|
98
98
|
return make((self, that) => {
|
|
99
99
|
if (self.length !== that.length) return false;
|
|
100
100
|
for (let i = 0; i < self.length; i++) {
|
|
@@ -104,7 +104,7 @@ function Array2(item) {
|
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
107
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/equal.js
|
|
108
108
|
var getAllObjectKeys = (obj) => {
|
|
109
109
|
const keys2 = new Set(Reflect.ownKeys(obj));
|
|
110
110
|
if (obj.constructor === Object) return keys2;
|
|
@@ -127,7 +127,7 @@ var getAllObjectKeys = (obj) => {
|
|
|
127
127
|
};
|
|
128
128
|
var byReferenceInstances = /* @__PURE__ */ new WeakSet();
|
|
129
129
|
|
|
130
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
130
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Predicate.js
|
|
131
131
|
function isString(input) {
|
|
132
132
|
return typeof input === "string";
|
|
133
133
|
}
|
|
@@ -148,7 +148,7 @@ function isObjectKeyword(input) {
|
|
|
148
148
|
}
|
|
149
149
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObjectKeyword(self) && property in self);
|
|
150
150
|
|
|
151
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
151
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Hash.js
|
|
152
152
|
var symbol = "~effect/interfaces/Hash";
|
|
153
153
|
var hash = (self) => {
|
|
154
154
|
switch (typeof self) {
|
|
@@ -267,7 +267,7 @@ function withVisitedTracking(obj, fn2) {
|
|
|
267
267
|
return result;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
270
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Equal.js
|
|
271
271
|
var symbol2 = "~effect/interfaces/Equal";
|
|
272
272
|
function equals() {
|
|
273
273
|
if (arguments.length === 1) {
|
|
@@ -429,7 +429,7 @@ var compareSets = /* @__PURE__ */ makeCompareSet(compareBoth);
|
|
|
429
429
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
430
430
|
var asEquivalence = () => equals;
|
|
431
431
|
|
|
432
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
432
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Redactable.js
|
|
433
433
|
var symbolRedactable = /* @__PURE__ */ Symbol.for("~effect/Inspectable/redactable");
|
|
434
434
|
var isRedactable = (u) => hasProperty(u, symbolRedactable);
|
|
435
435
|
function redact(u) {
|
|
@@ -448,7 +448,7 @@ var emptyServiceMap = {
|
|
|
448
448
|
}
|
|
449
449
|
};
|
|
450
450
|
|
|
451
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
451
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Formatter.js
|
|
452
452
|
function format(input, options) {
|
|
453
453
|
const space = options?.space ?? 0;
|
|
454
454
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -527,7 +527,7 @@ function safeToString(input) {
|
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
|
|
530
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
530
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Inspectable.js
|
|
531
531
|
var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
532
532
|
var toJson = (input) => {
|
|
533
533
|
try {
|
|
@@ -571,7 +571,7 @@ var Class2 = class {
|
|
|
571
571
|
}
|
|
572
572
|
};
|
|
573
573
|
|
|
574
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
574
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Utils.js
|
|
575
575
|
var SingleShotGen = class _SingleShotGen {
|
|
576
576
|
called = false;
|
|
577
577
|
self;
|
|
@@ -614,7 +614,7 @@ var forced = {
|
|
|
614
614
|
var isNotOptimizedAway = /* @__PURE__ */ standard[InternalTypeId](() => new Error().stack)?.includes(InternalTypeId) === true;
|
|
615
615
|
var internalCall = isNotOptimizedAway ? standard[InternalTypeId] : forced[InternalTypeId];
|
|
616
616
|
|
|
617
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
617
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/core.js
|
|
618
618
|
var EffectTypeId = `~effect/Effect`;
|
|
619
619
|
var ExitTypeId = `~effect/Exit`;
|
|
620
620
|
var effectVariance = {
|
|
@@ -961,7 +961,7 @@ var DoneVoid = {
|
|
|
961
961
|
value: void 0
|
|
962
962
|
};
|
|
963
963
|
|
|
964
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
964
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/option.js
|
|
965
965
|
var TypeId = "~effect/data/Option";
|
|
966
966
|
var CommonProto = {
|
|
967
967
|
[TypeId]: {
|
|
@@ -1032,7 +1032,7 @@ var some = (value) => {
|
|
|
1032
1032
|
return a;
|
|
1033
1033
|
};
|
|
1034
1034
|
|
|
1035
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1035
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/result.js
|
|
1036
1036
|
var TypeId2 = "~effect/data/Result";
|
|
1037
1037
|
var CommonProto2 = {
|
|
1038
1038
|
[TypeId2]: {
|
|
@@ -1103,7 +1103,7 @@ var succeed = (success) => {
|
|
|
1103
1103
|
return a;
|
|
1104
1104
|
};
|
|
1105
1105
|
|
|
1106
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1106
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Result.js
|
|
1107
1107
|
var succeed2 = succeed;
|
|
1108
1108
|
var fail2 = fail;
|
|
1109
1109
|
var isFailure2 = isFailure;
|
|
@@ -1111,10 +1111,10 @@ var isSuccess2 = isSuccess;
|
|
|
1111
1111
|
var map = /* @__PURE__ */ dual(2, (self, f) => isSuccess2(self) ? succeed2(f(self.success)) : fail2(self.failure));
|
|
1112
1112
|
var getOrElse = /* @__PURE__ */ dual(2, (self, onFailure) => isFailure2(self) ? onFailure(self.failure) : self.success);
|
|
1113
1113
|
|
|
1114
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1114
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/array.js
|
|
1115
1115
|
var isArrayNonEmpty = (self) => self.length > 0;
|
|
1116
1116
|
|
|
1117
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1117
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Order.js
|
|
1118
1118
|
function make2(compare) {
|
|
1119
1119
|
return (self, that) => self === that ? 0 : compare(self, that);
|
|
1120
1120
|
}
|
|
@@ -1137,7 +1137,7 @@ var combine2 = /* @__PURE__ */ dual(2, (self, that) => make2((a1, a2) => {
|
|
|
1137
1137
|
}));
|
|
1138
1138
|
var mapInput = /* @__PURE__ */ dual(2, (self, f) => make2((b1, b2) => self(f(b1), f(b2))));
|
|
1139
1139
|
|
|
1140
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1140
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Option.js
|
|
1141
1141
|
var none2 = () => none;
|
|
1142
1142
|
var some2 = some;
|
|
1143
1143
|
var isNone2 = isNone;
|
|
@@ -1148,7 +1148,7 @@ var fromNullishOr = (a) => a == null ? none2() : some2(a);
|
|
|
1148
1148
|
var getOrUndefined = /* @__PURE__ */ getOrElse2(constUndefined);
|
|
1149
1149
|
var map2 = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : some2(f(self.value)));
|
|
1150
1150
|
|
|
1151
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1151
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Record.js
|
|
1152
1152
|
var map3 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
1153
1153
|
const out = {
|
|
1154
1154
|
...self
|
|
@@ -1160,12 +1160,12 @@ var map3 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1160
1160
|
});
|
|
1161
1161
|
var keys = (self) => Object.keys(self);
|
|
1162
1162
|
|
|
1163
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1164
|
-
var
|
|
1165
|
-
var fromIterable = (collection) =>
|
|
1163
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Array.js
|
|
1164
|
+
var Array2 = globalThis.Array;
|
|
1165
|
+
var fromIterable = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
|
|
1166
1166
|
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
1167
1167
|
var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
|
|
1168
|
-
var isArray =
|
|
1168
|
+
var isArray = Array2.isArray;
|
|
1169
1169
|
var isArrayEmpty = (self) => self.length === 0;
|
|
1170
1170
|
var isReadonlyArrayEmpty = isArrayEmpty;
|
|
1171
1171
|
var isReadonlyArrayNonEmpty = isArrayNonEmpty;
|
|
@@ -1187,7 +1187,7 @@ var head = /* @__PURE__ */ get(0);
|
|
|
1187
1187
|
var headNonEmpty = /* @__PURE__ */ getUnsafe(0);
|
|
1188
1188
|
var tailNonEmpty = (self) => self.slice(1);
|
|
1189
1189
|
var sort = /* @__PURE__ */ dual(2, (self, O) => {
|
|
1190
|
-
const out =
|
|
1190
|
+
const out = Array2.from(self);
|
|
1191
1191
|
out.sort(O);
|
|
1192
1192
|
return out;
|
|
1193
1193
|
});
|
|
@@ -1251,7 +1251,7 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
|
|
|
1251
1251
|
var dedupe = (self) => dedupeWith(self, asEquivalence());
|
|
1252
1252
|
var join = /* @__PURE__ */ dual(2, (self, sep) => fromIterable(self).join(sep));
|
|
1253
1253
|
|
|
1254
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1254
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Data.js
|
|
1255
1255
|
var Class3 = class extends Class {
|
|
1256
1256
|
constructor(props) {
|
|
1257
1257
|
super();
|
|
@@ -1262,7 +1262,7 @@ var Class3 = class extends Class {
|
|
|
1262
1262
|
};
|
|
1263
1263
|
var TaggedError2 = TaggedError;
|
|
1264
1264
|
|
|
1265
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1265
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Encoding.js
|
|
1266
1266
|
var EncodingErrorTypeId = "~effect/encoding/EncodingError";
|
|
1267
1267
|
var EncodingError = class extends (/* @__PURE__ */ TaggedError2("EncodingError")) {
|
|
1268
1268
|
/**
|
|
@@ -1298,7 +1298,7 @@ var base64EncodeUint8Array = (bytes) => {
|
|
|
1298
1298
|
var base64abc = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"];
|
|
1299
1299
|
var base64UrlEncodeUint8Array = (data) => base64EncodeUint8Array(data).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
1300
1300
|
|
|
1301
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1301
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Graph.js
|
|
1302
1302
|
var TypeId3 = "~effect/collections/Graph";
|
|
1303
1303
|
var Edge = class extends Class3 {
|
|
1304
1304
|
};
|
|
@@ -4130,6 +4130,14 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4130
4130
|
),
|
|
4131
4131
|
([A, E, R]) => ({ A, E, R })
|
|
4132
4132
|
);
|
|
4133
|
+
const streamVarianceStruct = (type, atLocation) => map5(
|
|
4134
|
+
all(
|
|
4135
|
+
varianceStructCovariantType(type, atLocation, "_A"),
|
|
4136
|
+
varianceStructCovariantType(type, atLocation, "_E"),
|
|
4137
|
+
varianceStructCovariantType(type, atLocation, "_R")
|
|
4138
|
+
),
|
|
4139
|
+
([A, E, R]) => ({ A, E, R })
|
|
4140
|
+
);
|
|
4133
4141
|
const layerVarianceStruct = (type, atLocation) => map5(
|
|
4134
4142
|
all(
|
|
4135
4143
|
varianceStructContravariantType(type, atLocation, "_ROut"),
|
|
@@ -4176,6 +4184,21 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4176
4184
|
"TypeParser.strictEffectType",
|
|
4177
4185
|
(type) => type
|
|
4178
4186
|
);
|
|
4187
|
+
const streamType = cachedBy(
|
|
4188
|
+
fn("TypeParser.streamType")(function* (type, atLocation) {
|
|
4189
|
+
if (supportedEffect() === "v3") {
|
|
4190
|
+
return yield* effectType(type, atLocation);
|
|
4191
|
+
}
|
|
4192
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Stream");
|
|
4193
|
+
if (!typeIdSymbol) {
|
|
4194
|
+
return yield* typeParserIssue("Type is not a stream", type, atLocation);
|
|
4195
|
+
}
|
|
4196
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
4197
|
+
return yield* streamVarianceStruct(typeIdType, atLocation);
|
|
4198
|
+
}),
|
|
4199
|
+
"TypeParser.streamType",
|
|
4200
|
+
(type) => type
|
|
4201
|
+
);
|
|
4179
4202
|
const isEffectTypeSourceFile = cachedBy(
|
|
4180
4203
|
fn("TypeParser.isEffectTypeSourceFile")(function* (sourceFile) {
|
|
4181
4204
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -4747,33 +4770,33 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4747
4770
|
),
|
|
4748
4771
|
([Identifier, Service]) => ({ Identifier, Service })
|
|
4749
4772
|
);
|
|
4750
|
-
const serviceVarianceStruct = (type, atLocation) => map5(
|
|
4751
|
-
all(
|
|
4752
|
-
varianceStructInvariantType(type, atLocation, "_Identifier"),
|
|
4753
|
-
varianceStructInvariantType(type, atLocation, "_Service")
|
|
4754
|
-
),
|
|
4755
|
-
([Identifier, Service]) => ({ Identifier, Service })
|
|
4756
|
-
);
|
|
4757
4773
|
const serviceType = cachedBy(
|
|
4758
4774
|
fn("TypeParser.serviceType")(function* (type, atLocation) {
|
|
4775
|
+
if (supportedEffect() !== "v4") return yield* typeParserIssue("v4 only");
|
|
4759
4776
|
yield* pipeableType(type, atLocation);
|
|
4760
|
-
const
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
if (propertiesSymbols.length === 0) {
|
|
4764
|
-
return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
|
|
4777
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/ServiceMap/Service");
|
|
4778
|
+
if (!typeIdSymbol) {
|
|
4779
|
+
return yield* typeParserIssue("Type has no service key type id", type, atLocation);
|
|
4765
4780
|
}
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4781
|
+
const identifierSymbol = typeChecker.getPropertyOfType(type, "Identifier");
|
|
4782
|
+
if (!identifierSymbol) {
|
|
4783
|
+
return yield* typeParserIssue("Type has no 'Identifier' property", type, atLocation);
|
|
4784
|
+
}
|
|
4785
|
+
const serviceSymbol = typeChecker.getPropertyOfType(type, "Service");
|
|
4786
|
+
if (!serviceSymbol) {
|
|
4787
|
+
return yield* typeParserIssue("Type has no 'Service' property", type, atLocation);
|
|
4788
|
+
}
|
|
4789
|
+
return {
|
|
4790
|
+
Identifier: typeChecker.getTypeOfSymbolAtLocation(identifierSymbol, atLocation),
|
|
4791
|
+
Service: typeChecker.getTypeOfSymbolAtLocation(serviceSymbol, atLocation)
|
|
4792
|
+
};
|
|
4771
4793
|
}),
|
|
4772
4794
|
"TypeParser.serviceType",
|
|
4773
4795
|
(type) => type
|
|
4774
4796
|
);
|
|
4775
4797
|
const contextTag = cachedBy(
|
|
4776
4798
|
fn("TypeParser.contextTag")(function* (type, atLocation) {
|
|
4799
|
+
if (supportedEffect() !== "v3") return yield* typeParserIssue("v3 only");
|
|
4777
4800
|
yield* pipeableType(type, atLocation);
|
|
4778
4801
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
4779
4802
|
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
|
|
@@ -4914,6 +4937,19 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
4914
4937
|
"TypeParser.promiseLike",
|
|
4915
4938
|
(type) => type
|
|
4916
4939
|
);
|
|
4940
|
+
const promiseType = cachedBy(
|
|
4941
|
+
function(type, atLocation) {
|
|
4942
|
+
const promiseSymbol = typeChecker.resolveName("Promise", void 0, ts.SymbolFlags.Type, false);
|
|
4943
|
+
if (!promiseSymbol) return typeParserIssue("global Promise type not found", type, atLocation);
|
|
4944
|
+
const globalPromiseType = typeChecker.getDeclaredTypeOfSymbol(promiseSymbol);
|
|
4945
|
+
if (type === globalPromiseType || "target" in type && type.target === globalPromiseType || typeChecker.isTypeAssignableTo(type, globalPromiseType)) {
|
|
4946
|
+
return succeed3(type);
|
|
4947
|
+
}
|
|
4948
|
+
return typeParserIssue("type is not a Promise", type, atLocation);
|
|
4949
|
+
},
|
|
4950
|
+
"TypeParser.promiseType",
|
|
4951
|
+
(type) => type
|
|
4952
|
+
);
|
|
4917
4953
|
const extendsSchemaClass = cachedBy(
|
|
4918
4954
|
fn("TypeParser.extendsSchemaClass")(function* (atLocation) {
|
|
4919
4955
|
if (!atLocation.name) {
|
|
@@ -5911,6 +5947,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5911
5947
|
isServiceMapTypeSourceFile,
|
|
5912
5948
|
isNodeReferenceToServiceMapModuleApi,
|
|
5913
5949
|
effectType,
|
|
5950
|
+
streamType,
|
|
5914
5951
|
strictEffectType,
|
|
5915
5952
|
layerType,
|
|
5916
5953
|
fiberType,
|
|
@@ -5932,6 +5969,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5932
5969
|
singleArgCall,
|
|
5933
5970
|
scopeType,
|
|
5934
5971
|
promiseLike,
|
|
5972
|
+
promiseType,
|
|
5935
5973
|
extendsEffectTag,
|
|
5936
5974
|
extendsEffectService,
|
|
5937
5975
|
extendsServiceMapService,
|
|
@@ -7291,6 +7329,37 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
7291
7329
|
})
|
|
7292
7330
|
});
|
|
7293
7331
|
|
|
7332
|
+
// src/diagnostics/asyncFunction.ts
|
|
7333
|
+
var asyncFunction = createDiagnostic({
|
|
7334
|
+
name: "asyncFunction",
|
|
7335
|
+
code: 69,
|
|
7336
|
+
description: "Warns when declaring async functions and suggests using Effect values and Effect.gen for async control flow",
|
|
7337
|
+
group: "effectNative",
|
|
7338
|
+
severity: "off",
|
|
7339
|
+
fixable: false,
|
|
7340
|
+
supportedEffect: ["v3", "v4"],
|
|
7341
|
+
apply: fn("asyncFunction.apply")(function* (sourceFile, report) {
|
|
7342
|
+
const ts = yield* service(TypeScriptApi);
|
|
7343
|
+
const hasAsyncModifier = (node) => ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) === true;
|
|
7344
|
+
const visit = (node) => {
|
|
7345
|
+
if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) {
|
|
7346
|
+
ts.forEachChild(node, visit);
|
|
7347
|
+
return void 0;
|
|
7348
|
+
}
|
|
7349
|
+
if (hasAsyncModifier(node)) {
|
|
7350
|
+
report({
|
|
7351
|
+
location: node,
|
|
7352
|
+
messageText: "This code declares an async function, consider representing this async control flow with Effect values and `Effect.gen`.",
|
|
7353
|
+
fixes: []
|
|
7354
|
+
});
|
|
7355
|
+
}
|
|
7356
|
+
ts.forEachChild(node, visit);
|
|
7357
|
+
return void 0;
|
|
7358
|
+
};
|
|
7359
|
+
ts.forEachChild(sourceFile, visit);
|
|
7360
|
+
})
|
|
7361
|
+
});
|
|
7362
|
+
|
|
7294
7363
|
// src/diagnostics/catchAllToMapError.ts
|
|
7295
7364
|
var catchAllToMapError = createDiagnostic({
|
|
7296
7365
|
name: "catchAllToMapError",
|
|
@@ -7369,7 +7438,7 @@ var catchAllToMapError = createDiagnostic({
|
|
|
7369
7438
|
const { failArg, failCall } = failCallInfo;
|
|
7370
7439
|
report({
|
|
7371
7440
|
location: transformation.callee,
|
|
7372
|
-
messageText:
|
|
7441
|
+
messageText: `\`Effect.mapError\` expresses the same error-type transformation more directly than \`Effect.${catchAllName}\` followed by \`Effect.fail\`.`,
|
|
7373
7442
|
fixes: [{
|
|
7374
7443
|
fixName: "catchAllToMapError_fix",
|
|
7375
7444
|
description: "Replace with Effect.mapError",
|
|
@@ -7433,7 +7502,7 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
7433
7502
|
if (E.flags & ts.TypeFlags.Never) {
|
|
7434
7503
|
report({
|
|
7435
7504
|
location: transformation.callee,
|
|
7436
|
-
messageText:
|
|
7505
|
+
messageText: "The previous Effect does not fail, so this error-handling branch will never run.",
|
|
7437
7506
|
fixes: []
|
|
7438
7507
|
});
|
|
7439
7508
|
}
|
|
@@ -7496,7 +7565,7 @@ var classSelfMismatch = createDiagnostic({
|
|
|
7496
7565
|
if (actualName !== expectedName) {
|
|
7497
7566
|
report({
|
|
7498
7567
|
location: selfTypeNode,
|
|
7499
|
-
messageText: `Self type parameter should be
|
|
7568
|
+
messageText: `The \`Self\` type parameter for this class should be \`${expectedName}\`.`,
|
|
7500
7569
|
fixes: [{
|
|
7501
7570
|
fixName: "classSelfMismatch_fix",
|
|
7502
7571
|
description: `Replace '${actualName}' with '${expectedName}'`,
|
|
@@ -7519,6 +7588,59 @@ var classSelfMismatch = createDiagnostic({
|
|
|
7519
7588
|
})
|
|
7520
7589
|
});
|
|
7521
7590
|
|
|
7591
|
+
// src/diagnostics/cryptoRandomUUIDInEffect.ts
|
|
7592
|
+
var makeCryptoRandomUUIDApply = (checkInEffect) => fn(`cryptoRandomUUID${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
7593
|
+
const ts = yield* service(TypeScriptApi);
|
|
7594
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
7595
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7596
|
+
const typeParser = yield* service(TypeParser);
|
|
7597
|
+
const cryptoSymbol = typeChecker.resolveName("crypto", void 0, ts.SymbolFlags.Value, false);
|
|
7598
|
+
if (!cryptoSymbol) return;
|
|
7599
|
+
const nodeToVisit = [];
|
|
7600
|
+
const appendNodeToVisit = (node) => {
|
|
7601
|
+
nodeToVisit.push(node);
|
|
7602
|
+
return void 0;
|
|
7603
|
+
};
|
|
7604
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7605
|
+
while (nodeToVisit.length > 0) {
|
|
7606
|
+
const node = nodeToVisit.shift();
|
|
7607
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7608
|
+
if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || ts.idText(node.expression.name) !== "randomUUID") continue;
|
|
7609
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
|
|
7610
|
+
if (!symbol3) continue;
|
|
7611
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== cryptoSymbol) continue;
|
|
7612
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
7613
|
+
if (inEffect !== checkInEffect) continue;
|
|
7614
|
+
report({
|
|
7615
|
+
location: node,
|
|
7616
|
+
messageText: checkInEffect ? "This Effect code uses `crypto.randomUUID()`, prefer the Effect `Random` module instead because it uses Effect-injected randomness rather than the `crypto` module behind the scenes." : "This code uses `crypto.randomUUID()`, prefer the Effect `Random` module instead because it uses Effect-injected randomness rather than the `crypto` module behind the scenes.",
|
|
7617
|
+
fixes: []
|
|
7618
|
+
});
|
|
7619
|
+
}
|
|
7620
|
+
});
|
|
7621
|
+
var cryptoRandomUUIDInEffect = createDiagnostic({
|
|
7622
|
+
name: "cryptoRandomUUIDInEffect",
|
|
7623
|
+
code: 67,
|
|
7624
|
+
description: "Warns when using crypto.randomUUID() inside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenes",
|
|
7625
|
+
group: "effectNative",
|
|
7626
|
+
severity: "off",
|
|
7627
|
+
fixable: false,
|
|
7628
|
+
supportedEffect: ["v4"],
|
|
7629
|
+
apply: makeCryptoRandomUUIDApply(true)
|
|
7630
|
+
});
|
|
7631
|
+
|
|
7632
|
+
// src/diagnostics/cryptoRandomUUID.ts
|
|
7633
|
+
var cryptoRandomUUID = createDiagnostic({
|
|
7634
|
+
name: "cryptoRandomUUID",
|
|
7635
|
+
code: 66,
|
|
7636
|
+
description: "Warns when using crypto.randomUUID() outside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenes",
|
|
7637
|
+
group: "effectNative",
|
|
7638
|
+
severity: "off",
|
|
7639
|
+
fixable: false,
|
|
7640
|
+
supportedEffect: ["v4"],
|
|
7641
|
+
apply: makeCryptoRandomUUIDApply(false)
|
|
7642
|
+
});
|
|
7643
|
+
|
|
7522
7644
|
// src/diagnostics/deterministicKeys.ts
|
|
7523
7645
|
var deterministicKeys = createDiagnostic({
|
|
7524
7646
|
name: "deterministicKeys",
|
|
@@ -7620,7 +7742,7 @@ var deterministicKeys = createDiagnostic({
|
|
|
7620
7742
|
if (actualIdentifier !== expectedKey) {
|
|
7621
7743
|
report({
|
|
7622
7744
|
location: keyStringLiteral,
|
|
7623
|
-
messageText: `
|
|
7745
|
+
messageText: `This key does not match the deterministic key for this declaration. The expected key is \`${expectedKey}\`.`,
|
|
7624
7746
|
fixes: [{
|
|
7625
7747
|
fixName: "deterministicKeys_fix",
|
|
7626
7748
|
description: `Replace '${actualIdentifier}' with '${expectedKey}'`,
|
|
@@ -7659,9 +7781,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
7659
7781
|
const versions = Object.keys(resolvedPackages[packageName]);
|
|
7660
7782
|
report({
|
|
7661
7783
|
location: sourceFile.statements[0],
|
|
7662
|
-
messageText: `
|
|
7663
|
-
|
|
7664
|
-
If this is intended set the LSP config "allowedDuplicatedPackages" to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
7784
|
+
messageText: `Multiple versions of package \`${packageName}\` were detected: ${versions.join(", ")}. Package duplication can change runtime identity and type equality across Effect modules.
|
|
7785
|
+
If this is intentional, set the LSP config \`allowedDuplicatedPackages\` to ${JSON.stringify(options.allowedDuplicatedPackages.concat([packageName]))}.
|
|
7665
7786
|
|
|
7666
7787
|
${versions.map((version) => `- found ${version} at ${resolvedPackages[packageName][version]}`).join("\n")}`,
|
|
7667
7788
|
fixes: []
|
|
@@ -7671,6 +7792,40 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
|
|
|
7671
7792
|
})
|
|
7672
7793
|
});
|
|
7673
7794
|
|
|
7795
|
+
// src/diagnostics/effectDoNotation.ts
|
|
7796
|
+
var effectDoNotation = createDiagnostic({
|
|
7797
|
+
name: "effectDoNotation",
|
|
7798
|
+
code: 73,
|
|
7799
|
+
description: "Suggests using Effect.gen or Effect.fn instead of the Effect.Do notation helpers",
|
|
7800
|
+
group: "style",
|
|
7801
|
+
severity: "off",
|
|
7802
|
+
fixable: false,
|
|
7803
|
+
supportedEffect: ["v3", "v4"],
|
|
7804
|
+
apply: fn("effectDoNotation.apply")(function* (sourceFile, report) {
|
|
7805
|
+
const ts = yield* service(TypeScriptApi);
|
|
7806
|
+
const typeParser = yield* service(TypeParser);
|
|
7807
|
+
const nodeToVisit = [];
|
|
7808
|
+
const appendNodeToVisit = (node) => {
|
|
7809
|
+
nodeToVisit.push(node);
|
|
7810
|
+
return void 0;
|
|
7811
|
+
};
|
|
7812
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
7813
|
+
while (nodeToVisit.length > 0) {
|
|
7814
|
+
const node = nodeToVisit.shift();
|
|
7815
|
+
const isReference = yield* orUndefined(typeParser.isNodeReferenceToEffectModuleApi("Do")(node));
|
|
7816
|
+
if (isReference) {
|
|
7817
|
+
report({
|
|
7818
|
+
location: node,
|
|
7819
|
+
messageText: "This uses the Effect do emulation. `Effect.gen` or `Effect.fn` achieve the same result with native JS scopes.",
|
|
7820
|
+
fixes: []
|
|
7821
|
+
});
|
|
7822
|
+
continue;
|
|
7823
|
+
}
|
|
7824
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
7825
|
+
}
|
|
7826
|
+
})
|
|
7827
|
+
});
|
|
7828
|
+
|
|
7674
7829
|
// src/diagnostics/effectFnIife.ts
|
|
7675
7830
|
var effectFnIife = createDiagnostic({
|
|
7676
7831
|
name: "effectFnIife",
|
|
@@ -7769,7 +7924,7 @@ var effectFnIife = createDiagnostic({
|
|
|
7769
7924
|
const traceExpressionText = traceExpression ? sourceFile.text.slice(traceExpression.pos, traceExpression.end) : void 0;
|
|
7770
7925
|
report({
|
|
7771
7926
|
location: node,
|
|
7772
|
-
messageText:
|
|
7927
|
+
messageText: `\`${effectModuleName}.${kind}\` returns a reusable function that can take arguments, but it is invoked immediately here. \`Effect.gen\` represents the immediate-use form for this pattern${traceExpressionText ? ` with \`Effect.withSpan(${traceExpressionText})\` piped at the end to maintain tracing spans` : ``}.`,
|
|
7773
7928
|
fixes
|
|
7774
7929
|
});
|
|
7775
7930
|
}
|
|
@@ -7854,7 +8009,7 @@ var effectFnImplicitAny = createDiagnostic({
|
|
|
7854
8009
|
const parameterName = getParameterName(ts, parameter.name);
|
|
7855
8010
|
report({
|
|
7856
8011
|
location: parameter.name,
|
|
7857
|
-
messageText: `Parameter
|
|
8012
|
+
messageText: `Parameter \`${parameterName}\` implicitly has type \`any\` in \`Effect.fn\`, \`Effect.fnUntraced\`, or \`Effect.fnUntracedEager\`. No parameter type is available from an explicit annotation or contextual function type.`,
|
|
7858
8013
|
fixes: []
|
|
7859
8014
|
});
|
|
7860
8015
|
}
|
|
@@ -8450,7 +8605,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
8450
8605
|
const expectedSignature = generateExpectedSignature();
|
|
8451
8606
|
report({
|
|
8452
8607
|
location: nameIdentifier ?? targetNode,
|
|
8453
|
-
messageText: `
|
|
8608
|
+
messageText: `This expression can be rewritten in the reusable function form \`${expectedSignature}\`.`,
|
|
8454
8609
|
fixes
|
|
8455
8610
|
});
|
|
8456
8611
|
}
|
|
@@ -8617,6 +8772,43 @@ var effectInVoidSuccess = createDiagnostic({
|
|
|
8617
8772
|
})
|
|
8618
8773
|
});
|
|
8619
8774
|
|
|
8775
|
+
// src/diagnostics/effectMapFlatten.ts
|
|
8776
|
+
var effectMapFlatten = createDiagnostic({
|
|
8777
|
+
name: "effectMapFlatten",
|
|
8778
|
+
code: 74,
|
|
8779
|
+
description: "Suggests using Effect.flatMap instead of Effect.map followed by Effect.flatten in piping flows",
|
|
8780
|
+
group: "style",
|
|
8781
|
+
severity: "suggestion",
|
|
8782
|
+
fixable: false,
|
|
8783
|
+
supportedEffect: ["v3", "v4"],
|
|
8784
|
+
apply: fn("effectMapFlatten.apply")(function* (sourceFile, report) {
|
|
8785
|
+
const typeParser = yield* service(TypeParser);
|
|
8786
|
+
const flows = yield* typeParser.pipingFlows(false)(sourceFile);
|
|
8787
|
+
for (const flow2 of flows) {
|
|
8788
|
+
for (let index = 0; index < flow2.transformations.length - 1; index++) {
|
|
8789
|
+
const mapTransformation = flow2.transformations[index];
|
|
8790
|
+
const flattenTransformation = flow2.transformations[index + 1];
|
|
8791
|
+
if (!mapTransformation || !flattenTransformation || !mapTransformation?.args || flattenTransformation?.args || mapTransformation.kind !== "pipe" && mapTransformation.kind !== "pipeable" || flattenTransformation.kind !== mapTransformation.kind) {
|
|
8792
|
+
continue;
|
|
8793
|
+
}
|
|
8794
|
+
const isMapCall = yield* orUndefined(
|
|
8795
|
+
typeParser.isNodeReferenceToEffectModuleApi("map")(mapTransformation.callee)
|
|
8796
|
+
);
|
|
8797
|
+
const isFlattenCall = yield* orUndefined(
|
|
8798
|
+
typeParser.isNodeReferenceToEffectModuleApi("flatten")(flattenTransformation.callee)
|
|
8799
|
+
);
|
|
8800
|
+
if (isMapCall && isFlattenCall) {
|
|
8801
|
+
report({
|
|
8802
|
+
location: flattenTransformation.callee,
|
|
8803
|
+
messageText: "`Effect.map` + `Effect.flatten` is the same as `Effect.flatMap` that expresses the same steps more directly.",
|
|
8804
|
+
fixes: []
|
|
8805
|
+
});
|
|
8806
|
+
}
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
})
|
|
8810
|
+
});
|
|
8811
|
+
|
|
8620
8812
|
// src/diagnostics/effectMapVoid.ts
|
|
8621
8813
|
var effectMapVoid = createDiagnostic({
|
|
8622
8814
|
name: "effectMapVoid",
|
|
@@ -8662,7 +8854,7 @@ var effectMapVoid = createDiagnostic({
|
|
|
8662
8854
|
if (isNone2(match2)) continue;
|
|
8663
8855
|
report({
|
|
8664
8856
|
location: node.expression,
|
|
8665
|
-
messageText: "
|
|
8857
|
+
messageText: "This expression discards the success value through mapping. `Effect.asVoid` represents that form directly.",
|
|
8666
8858
|
fixes: [{
|
|
8667
8859
|
fixName: "effectMapVoid_fix",
|
|
8668
8860
|
description: "Replace with Effect.asVoid",
|
|
@@ -8717,7 +8909,7 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
8717
8909
|
if (!tsUtils.isVoidExpression(argument)) continue;
|
|
8718
8910
|
report({
|
|
8719
8911
|
location: node,
|
|
8720
|
-
messageText: "Effect.void
|
|
8912
|
+
messageText: "`Effect.void` represents the same outcome as `Effect.succeed(undefined)` or `Effect.succeed(void 0)`.",
|
|
8721
8913
|
fixes: [{
|
|
8722
8914
|
fixName: "effectSucceedWithVoid_fix",
|
|
8723
8915
|
description: "Replace with Effect.void",
|
|
@@ -8779,7 +8971,7 @@ var extendsNativeError = createDiagnostic({
|
|
|
8779
8971
|
if (isNativeError) {
|
|
8780
8972
|
report({
|
|
8781
8973
|
location: node.name ?? typeExpression,
|
|
8782
|
-
messageText: "
|
|
8974
|
+
messageText: "This class extends the native `Error` type directly. Untagged native errors lose distinction in the Effect failure channel.",
|
|
8783
8975
|
fixes: []
|
|
8784
8976
|
});
|
|
8785
8977
|
}
|
|
@@ -8824,7 +9016,12 @@ var floatingEffect = createDiagnostic({
|
|
|
8824
9016
|
if (!isFloatingExpression(node)) continue;
|
|
8825
9017
|
const type = typeCheckerUtils.getTypeAtLocation(node.expression);
|
|
8826
9018
|
if (!type) continue;
|
|
8827
|
-
const effect = yield* option(
|
|
9019
|
+
const effect = yield* option(
|
|
9020
|
+
pipe(
|
|
9021
|
+
typeParser.effectType(type, node.expression),
|
|
9022
|
+
orElse2(() => typeParser.streamType(type, node.expression))
|
|
9023
|
+
)
|
|
9024
|
+
);
|
|
8828
9025
|
if (isSome2(effect)) {
|
|
8829
9026
|
const allowedFloatingEffects = yield* pipe(
|
|
8830
9027
|
typeParser.fiberType(type, node.expression),
|
|
@@ -8833,10 +9030,9 @@ var floatingEffect = createDiagnostic({
|
|
|
8833
9030
|
);
|
|
8834
9031
|
if (isNone2(allowedFloatingEffects)) {
|
|
8835
9032
|
const isStrictEffect = yield* option(typeParser.strictEffectType(type, node.expression));
|
|
8836
|
-
const name = isSome2(isStrictEffect) ? "Effect" : "Effect-able " + typeChecker.typeToString(type);
|
|
8837
9033
|
report({
|
|
8838
9034
|
location: node,
|
|
8839
|
-
messageText:
|
|
9035
|
+
messageText: isSome2(isStrictEffect) ? "This Effect value is neither yielded nor used in an assignment." : `This Effect-able \`${typeChecker.typeToString(type)}\` value is neither yielded nor assigned to a variable.`,
|
|
8840
9036
|
fixes: []
|
|
8841
9037
|
});
|
|
8842
9038
|
}
|
|
@@ -8880,6 +9076,7 @@ var genericEffectServices = createDiagnostic({
|
|
|
8880
9076
|
for (const [type, reportAt] of typesToCheck) {
|
|
8881
9077
|
yield* pipe(
|
|
8882
9078
|
typeParser.contextTag(type, node),
|
|
9079
|
+
orElse2(() => typeParser.serviceType(type, node)),
|
|
8883
9080
|
map5(() => {
|
|
8884
9081
|
report({
|
|
8885
9082
|
location: reportAt,
|
|
@@ -8931,7 +9128,7 @@ var makeGlobalConsoleApply = (checkInEffect) => fn(`globalConsole${checkInEffect
|
|
|
8931
9128
|
if (inEffect !== checkInEffect) continue;
|
|
8932
9129
|
report({
|
|
8933
9130
|
location: node,
|
|
8934
|
-
messageText: checkInEffect ? `
|
|
9131
|
+
messageText: checkInEffect ? `This Effect code uses \`console.${method}\`, logging in Effect code is represented through \`${alternative}\`.` : `This code uses \`console.${method}\`, the corresponding Effect logging API is \`${alternative}\`.`,
|
|
8935
9132
|
fixes: []
|
|
8936
9133
|
});
|
|
8937
9134
|
}
|
|
@@ -8980,10 +9177,10 @@ var makeGlobalDateApply = (checkInEffect) => fn(`globalDate${checkInEffect ? "In
|
|
|
8980
9177
|
let objectNode;
|
|
8981
9178
|
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.idText(node.expression.name) === "now") {
|
|
8982
9179
|
objectNode = node.expression.expression;
|
|
8983
|
-
messageText = checkInEffect ? "
|
|
9180
|
+
messageText = checkInEffect ? "This Effect code uses `Date.now()`, time access in Effect code is represented through `Clock` from Effect." : "This code uses `Date.now()`, time access is represented through `Clock` from Effect.";
|
|
8984
9181
|
} else if (ts.isNewExpression(node)) {
|
|
8985
9182
|
objectNode = node.expression;
|
|
8986
|
-
messageText = checkInEffect ? "
|
|
9183
|
+
messageText = checkInEffect ? "This Effect code constructs `new Date()`, date values in Effect code are represented through `DateTime` from Effect." : "This code constructs `new Date()`, date values are represented through `DateTime` from Effect.";
|
|
8987
9184
|
}
|
|
8988
9185
|
if (!messageText || !objectNode) continue;
|
|
8989
9186
|
const symbol3 = typeChecker.getSymbolAtLocation(objectNode);
|
|
@@ -9066,7 +9263,7 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
9066
9263
|
);
|
|
9067
9264
|
report({
|
|
9068
9265
|
location: node.expression,
|
|
9069
|
-
messageText: `The
|
|
9266
|
+
messageText: `The \`catch\` callback in \`${nodeText}\` returns the global \`Error\` type. Untagged errors merge together in the Effect error channel and lose type-level distinction; a tagged error preserves that distinction and can wrap the original error in a \`cause\` property.`,
|
|
9070
9267
|
fixes: []
|
|
9071
9268
|
});
|
|
9072
9269
|
}
|
|
@@ -9146,7 +9343,7 @@ var makeGlobalFetchApply = (checkInEffect) => fn(`globalFetch${checkInEffect ? "
|
|
|
9146
9343
|
if (!fetchSymbol) return;
|
|
9147
9344
|
const effectVersion = typeParser.supportedEffect();
|
|
9148
9345
|
const packageName = effectVersion === "v3" ? "@effect/platform" : "effect/unstable/http";
|
|
9149
|
-
const messageText = checkInEffect ? `
|
|
9346
|
+
const messageText = checkInEffect ? `This Effect code calls the global \`fetch\` function, HTTP requests in Effect code are represented through \`HttpClient\` from \`${packageName}\`.` : `This code uses the global \`fetch\` function, HTTP requests are represented through \`HttpClient\` from \`${packageName}\`.`;
|
|
9150
9347
|
const nodeToVisit = [];
|
|
9151
9348
|
const appendNodeToVisit = (node) => {
|
|
9152
9349
|
nodeToVisit.push(node);
|
|
@@ -9219,7 +9416,7 @@ var makeGlobalRandomApply = (checkInEffect) => fn(`globalRandom${checkInEffect ?
|
|
|
9219
9416
|
if (inEffect !== checkInEffect) continue;
|
|
9220
9417
|
report({
|
|
9221
9418
|
location: node,
|
|
9222
|
-
messageText: checkInEffect ? "
|
|
9419
|
+
messageText: checkInEffect ? "This Effect code uses `Math.random()`, randomness is represented through the Effect `Random` service." : "This code uses `Math.random()`, randomness is represented through the Effect `Random` service.",
|
|
9223
9420
|
fixes: []
|
|
9224
9421
|
});
|
|
9225
9422
|
}
|
|
@@ -9250,12 +9447,12 @@ var globalRandom = createDiagnostic({
|
|
|
9250
9447
|
// src/diagnostics/globalTimersInEffect.ts
|
|
9251
9448
|
var timerAlternatives = {
|
|
9252
9449
|
"setTimeout": {
|
|
9253
|
-
inEffect: "
|
|
9254
|
-
outsideEffect: "
|
|
9450
|
+
inEffect: "This Effect code uses `setTimeout`, the corresponding timer API in this context is `Effect.sleep or Schedule` from Effect.",
|
|
9451
|
+
outsideEffect: "This code uses `setTimeout`, the corresponding Effect timer API is `Effect.sleep or Schedule` from Effect."
|
|
9255
9452
|
},
|
|
9256
9453
|
"setInterval": {
|
|
9257
|
-
inEffect: "
|
|
9258
|
-
outsideEffect: "
|
|
9454
|
+
inEffect: "This Effect code uses `setInterval`, the corresponding timer API in this context is `Schedule or Effect.repeat` from Effect.",
|
|
9455
|
+
outsideEffect: "This code uses `setInterval`, the corresponding Effect timer API is `Schedule or Effect.repeat` from Effect."
|
|
9259
9456
|
}
|
|
9260
9457
|
};
|
|
9261
9458
|
var makeGlobalTimersApply = (checkInEffect) => fn(`globalTimers${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
@@ -9497,7 +9694,7 @@ var instanceOfSchema = createDiagnostic({
|
|
|
9497
9694
|
if (isSchemaType._tag === "Some") {
|
|
9498
9695
|
report({
|
|
9499
9696
|
location: node,
|
|
9500
|
-
messageText: "
|
|
9697
|
+
messageText: "This code uses `instanceof` with an Effect Schema type. `Schema.is` is the schema-aware runtime check for this case.",
|
|
9501
9698
|
fixes: [{
|
|
9502
9699
|
fixName: "instanceOfSchema_fix",
|
|
9503
9700
|
description: "Replace with Schema.is",
|
|
@@ -9643,6 +9840,55 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
9643
9840
|
})
|
|
9644
9841
|
});
|
|
9645
9842
|
|
|
9843
|
+
// src/diagnostics/lazyPromiseInEffectSync.ts
|
|
9844
|
+
var lazyPromiseInEffectSync = createDiagnostic({
|
|
9845
|
+
name: "lazyPromiseInEffectSync",
|
|
9846
|
+
code: 70,
|
|
9847
|
+
description: "Warns when Effect.sync lazily returns a Promise instead of using an async Effect constructor",
|
|
9848
|
+
group: "antipattern",
|
|
9849
|
+
severity: "warning",
|
|
9850
|
+
fixable: false,
|
|
9851
|
+
supportedEffect: ["v3", "v4"],
|
|
9852
|
+
apply: fn("lazyPromiseInEffectSync.apply")(function* (sourceFile, report) {
|
|
9853
|
+
const ts = yield* service(TypeScriptApi);
|
|
9854
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
9855
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
9856
|
+
const typeParser = yield* service(TypeParser);
|
|
9857
|
+
const nodeToVisit = [];
|
|
9858
|
+
const appendNodeToVisit = (node) => {
|
|
9859
|
+
nodeToVisit.push(node);
|
|
9860
|
+
return void 0;
|
|
9861
|
+
};
|
|
9862
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
9863
|
+
while (nodeToVisit.length > 0) {
|
|
9864
|
+
const node = nodeToVisit.shift();
|
|
9865
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
9866
|
+
if (!ts.isCallExpression(node)) continue;
|
|
9867
|
+
const isSyncCall = yield* orUndefined(
|
|
9868
|
+
typeParser.isNodeReferenceToEffectModuleApi("sync")(node.expression)
|
|
9869
|
+
);
|
|
9870
|
+
if (!isSyncCall) continue;
|
|
9871
|
+
const lazyArg = node.arguments[0];
|
|
9872
|
+
if (!lazyArg) continue;
|
|
9873
|
+
const lazyArgType = typeCheckerUtils.getTypeAtLocation(lazyArg);
|
|
9874
|
+
if (!lazyArgType) continue;
|
|
9875
|
+
const entries2 = typeCheckerUtils.unrollUnionMembers(lazyArgType).flatMap(
|
|
9876
|
+
(member) => typeChecker.getSignaturesOfType(member, ts.SignatureKind.Call).map(
|
|
9877
|
+
(signature) => typeParser.promiseType(typeChecker.getReturnTypeOfSignature(signature), lazyArg)
|
|
9878
|
+
)
|
|
9879
|
+
);
|
|
9880
|
+
if (entries2.length === 0) continue;
|
|
9881
|
+
const promiseReturn = yield* orUndefined(firstSuccessOf(entries2));
|
|
9882
|
+
if (!promiseReturn) continue;
|
|
9883
|
+
report({
|
|
9884
|
+
location: lazyArg,
|
|
9885
|
+
messageText: "This `Effect.sync` thunk returns a Promise. Use `Effect.promise` or `Effect.tryPromise` to represent async work.",
|
|
9886
|
+
fixes: []
|
|
9887
|
+
});
|
|
9888
|
+
}
|
|
9889
|
+
})
|
|
9890
|
+
});
|
|
9891
|
+
|
|
9646
9892
|
// src/diagnostics/leakingRequirements.ts
|
|
9647
9893
|
var leakingRequirements = createDiagnostic({
|
|
9648
9894
|
name: "leakingRequirements",
|
|
@@ -9767,7 +10013,7 @@ var leakingRequirements = createDiagnostic({
|
|
|
9767
10013
|
location: node,
|
|
9768
10014
|
messageText: `Methods of this Service require \`${requirementsStr}\` from every caller.
|
|
9769
10015
|
|
|
9770
|
-
|
|
10016
|
+
The requirement becomes part of the public service surface instead of remaining internal to Layer implementation.
|
|
9771
10017
|
|
|
9772
10018
|
Resolve these dependencies at Layer creation and provide them to each method, so the service's type reflects its purpose, not its implementation.
|
|
9773
10019
|
|
|
@@ -9964,7 +10210,7 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
9964
10210
|
).trim() : "";
|
|
9965
10211
|
report({
|
|
9966
10212
|
location: flow2.node,
|
|
9967
|
-
messageText: `
|
|
10213
|
+
messageText: `This nested call structure has a pipeable form. \`${subjectText}.pipe(...)\` represents the same call sequence in pipe style and may be easier to read.`,
|
|
9968
10214
|
fixes: [{
|
|
9969
10215
|
fixName: "missedPipeableOpportunity_fix",
|
|
9970
10216
|
description: "Convert to pipe style",
|
|
@@ -10045,7 +10291,7 @@ var missingEffectContext = createDiagnostic({
|
|
|
10045
10291
|
(missingTypes) => missingTypes.length > 0 ? report(
|
|
10046
10292
|
{
|
|
10047
10293
|
location: node,
|
|
10048
|
-
messageText: `
|
|
10294
|
+
messageText: `This Effect requires a service that is missing from the expected Effect context: \`${sortTypes(missingTypes).map((_) => typeChecker.typeToString(_)).join(" | ")}\`.`,
|
|
10049
10295
|
fixes: []
|
|
10050
10296
|
}
|
|
10051
10297
|
) : void 0
|
|
@@ -10396,7 +10642,7 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
10396
10642
|
}];
|
|
10397
10643
|
report({
|
|
10398
10644
|
location: unwrapped,
|
|
10399
|
-
messageText:
|
|
10645
|
+
messageText: "This Effect never succeeds; using `return yield*` preserves a definitive generator exit point for type narrowing and tooling support.",
|
|
10400
10646
|
fixes: fix
|
|
10401
10647
|
});
|
|
10402
10648
|
}
|
|
@@ -10452,7 +10698,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
10452
10698
|
brokenGenerators.forEach(
|
|
10453
10699
|
(pos) => report({
|
|
10454
10700
|
location: { pos, end: pos + "function".length },
|
|
10455
|
-
messageText: `
|
|
10701
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
10456
10702
|
fixes: []
|
|
10457
10703
|
})
|
|
10458
10704
|
);
|
|
@@ -10474,7 +10720,7 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
10474
10720
|
}] : [];
|
|
10475
10721
|
report({
|
|
10476
10722
|
location: node,
|
|
10477
|
-
messageText: `
|
|
10723
|
+
messageText: "This uses `yield` for an `Effect` value. `yield*` is the Effect-aware form in this context.",
|
|
10478
10724
|
fixes: fix
|
|
10479
10725
|
});
|
|
10480
10726
|
});
|
|
@@ -10542,7 +10788,7 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
10542
10788
|
if (chunk.length < 2) continue;
|
|
10543
10789
|
report({
|
|
10544
10790
|
location: chunk[0].node,
|
|
10545
|
-
messageText: "
|
|
10791
|
+
messageText: "This expression chains multiple `Effect.provide` calls. Providing Layers in multiple calls in a chain can break service lifecycle behavior compared with a single combined provide with merged layers.",
|
|
10546
10792
|
fixes: [{
|
|
10547
10793
|
fixName: "multipleEffectProvide_fix",
|
|
10548
10794
|
description: "Combine into a single provide",
|
|
@@ -10576,6 +10822,74 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
10576
10822
|
})
|
|
10577
10823
|
});
|
|
10578
10824
|
|
|
10825
|
+
// src/diagnostics/nestedEffectGenYield.ts
|
|
10826
|
+
var nestedEffectGenYield = createDiagnostic({
|
|
10827
|
+
name: "nestedEffectGenYield",
|
|
10828
|
+
code: 71,
|
|
10829
|
+
description: "Warns when yielding a nested bare Effect.gen inside an existing Effect generator context",
|
|
10830
|
+
group: "style",
|
|
10831
|
+
severity: "off",
|
|
10832
|
+
fixable: false,
|
|
10833
|
+
supportedEffect: ["v3", "v4"],
|
|
10834
|
+
apply: fn("nestedEffectGenYield.apply")(function* (sourceFile, report) {
|
|
10835
|
+
const ts = yield* service(TypeScriptApi);
|
|
10836
|
+
const typeParser = yield* service(TypeParser);
|
|
10837
|
+
const nodeToVisit = [];
|
|
10838
|
+
const appendNodeToVisit = (node) => {
|
|
10839
|
+
nodeToVisit.push(node);
|
|
10840
|
+
return void 0;
|
|
10841
|
+
};
|
|
10842
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
10843
|
+
while (nodeToVisit.length > 0) {
|
|
10844
|
+
const node = nodeToVisit.shift();
|
|
10845
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
10846
|
+
if (!ts.isYieldExpression(node) || !node.asteriskToken || !node.expression) continue;
|
|
10847
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
10848
|
+
if (!inEffect) continue;
|
|
10849
|
+
const bareNestedEffectGen = yield* orUndefined(typeParser.effectGen(node.expression));
|
|
10850
|
+
if (!bareNestedEffectGen) continue;
|
|
10851
|
+
report({
|
|
10852
|
+
location: node.expression,
|
|
10853
|
+
messageText: "This `yield*` is applied to a nested `Effect.gen(...)` that can be inlined in the parent Effect generator context.",
|
|
10854
|
+
fixes: []
|
|
10855
|
+
});
|
|
10856
|
+
}
|
|
10857
|
+
})
|
|
10858
|
+
});
|
|
10859
|
+
|
|
10860
|
+
// src/diagnostics/newPromise.ts
|
|
10861
|
+
var newPromise = createDiagnostic({
|
|
10862
|
+
name: "newPromise",
|
|
10863
|
+
code: 68,
|
|
10864
|
+
description: "Warns when constructing promises with new Promise instead of using Effect APIs",
|
|
10865
|
+
group: "effectNative",
|
|
10866
|
+
severity: "off",
|
|
10867
|
+
fixable: false,
|
|
10868
|
+
supportedEffect: ["v3", "v4"],
|
|
10869
|
+
apply: fn("newPromise.apply")(function* (sourceFile, report) {
|
|
10870
|
+
const ts = yield* service(TypeScriptApi);
|
|
10871
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
10872
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
10873
|
+
const promiseSymbol = typeChecker.resolveName("Promise", void 0, ts.SymbolFlags.Value, false);
|
|
10874
|
+
if (!promiseSymbol) return;
|
|
10875
|
+
const visit = (node) => {
|
|
10876
|
+
if (ts.isNewExpression(node)) {
|
|
10877
|
+
const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
|
|
10878
|
+
if (symbol3 && typeCheckerUtils.resolveToGlobalSymbol(symbol3) === promiseSymbol) {
|
|
10879
|
+
report({
|
|
10880
|
+
location: node,
|
|
10881
|
+
messageText: "This code constructs `new Promise(...)`, prefer Effect APIs such as `Effect.async`, `Effect.promise`, or `Effect.tryPromise` instead of manual Promise construction.",
|
|
10882
|
+
fixes: []
|
|
10883
|
+
});
|
|
10884
|
+
}
|
|
10885
|
+
}
|
|
10886
|
+
ts.forEachChild(node, visit);
|
|
10887
|
+
return void 0;
|
|
10888
|
+
};
|
|
10889
|
+
ts.forEachChild(sourceFile, visit);
|
|
10890
|
+
})
|
|
10891
|
+
});
|
|
10892
|
+
|
|
10579
10893
|
// src/diagnostics/nodeBuiltinImport.ts
|
|
10580
10894
|
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
10581
10895
|
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
@@ -10632,7 +10946,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
10632
10946
|
if (match2) {
|
|
10633
10947
|
report({
|
|
10634
10948
|
location: statement.moduleSpecifier,
|
|
10635
|
-
messageText: `
|
|
10949
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
10636
10950
|
fixes: []
|
|
10637
10951
|
});
|
|
10638
10952
|
}
|
|
@@ -10645,7 +10959,7 @@ var nodeBuiltinImport = createDiagnostic({
|
|
|
10645
10959
|
if (match2) {
|
|
10646
10960
|
report({
|
|
10647
10961
|
location: arg,
|
|
10648
|
-
messageText: `
|
|
10962
|
+
messageText: `This module reference uses the \`${match2.module}\` module, the corresponding Effect API is \`${match2.alternative}\` from \`${match2.package}\`.`,
|
|
10649
10963
|
fixes: []
|
|
10650
10964
|
});
|
|
10651
10965
|
}
|
|
@@ -10699,7 +11013,7 @@ var nonObjectEffectServiceType = createDiagnostic({
|
|
|
10699
11013
|
const propertyValue = property.initializer;
|
|
10700
11014
|
const errorToReport = {
|
|
10701
11015
|
location: property.name,
|
|
10702
|
-
messageText: "Effect.Service
|
|
11016
|
+
messageText: "`Effect.Service` is declared with a primitive service type. `Effect.Service` models object-shaped services; primitive values use `Context.Tag` or `Effect.Tag` directly.",
|
|
10703
11017
|
fixes: []
|
|
10704
11018
|
};
|
|
10705
11019
|
if (propertyName === "succeed") {
|
|
@@ -10919,6 +11233,14 @@ var effectModuleMigrationDb = {
|
|
|
10919
11233
|
"yieldNow": asUnchanged,
|
|
10920
11234
|
"zip": asUnchanged,
|
|
10921
11235
|
"zipWith": asUnchanged,
|
|
11236
|
+
"annotateLogsScoped": asUnchanged,
|
|
11237
|
+
"awaitAllChildren": asUnchanged,
|
|
11238
|
+
"bind": asUnchanged,
|
|
11239
|
+
"bindTo": asUnchanged,
|
|
11240
|
+
"Do": asUnchanged,
|
|
11241
|
+
"let": asUnchanged,
|
|
11242
|
+
"partition": asUnchanged,
|
|
11243
|
+
"validate": asUnchanged,
|
|
10922
11244
|
// Renamed APIs (v3 name → v4 name)
|
|
10923
11245
|
"catchAll": asRenamedSameBehaviour("catch"),
|
|
10924
11246
|
"catchAllCause": asRenamedSameBehaviour("catchCause"),
|
|
@@ -10938,14 +11260,6 @@ var effectModuleMigrationDb = {
|
|
|
10938
11260
|
"serviceOptional": asRenamedSameBehaviour("serviceOption"),
|
|
10939
11261
|
"tapErrorCause": asRenamedSameBehaviour("tapCause"),
|
|
10940
11262
|
// Removed APIs
|
|
10941
|
-
"annotateLogsScoped": asUnchanged,
|
|
10942
|
-
"awaitAllChildren": asUnchanged,
|
|
10943
|
-
"bind": asUnchanged,
|
|
10944
|
-
"bindTo": asUnchanged,
|
|
10945
|
-
"Do": asUnchanged,
|
|
10946
|
-
"let": asUnchanged,
|
|
10947
|
-
"partition": asUnchanged,
|
|
10948
|
-
"validate": asUnchanged,
|
|
10949
11263
|
"catchSomeDefect": asRemoved(
|
|
10950
11264
|
"Use Effect.catchDefect or Effect.matchCause to handle specific defects."
|
|
10951
11265
|
),
|
|
@@ -11461,7 +11775,7 @@ var outdatedApi = createDiagnostic({
|
|
|
11461
11775
|
hasReported = true;
|
|
11462
11776
|
report({
|
|
11463
11777
|
location: propertyAccess.name,
|
|
11464
|
-
messageText:
|
|
11778
|
+
messageText: `This project targets Effect v4, but this code uses the Effect v3 API \`${propertyName}\`. The referenced API belongs to the v3 surface rather than the configured v4 surface.`,
|
|
11465
11779
|
fixes: []
|
|
11466
11780
|
});
|
|
11467
11781
|
}
|
|
@@ -11504,7 +11818,7 @@ var outdatedApi = createDiagnostic({
|
|
|
11504
11818
|
if (hasReported) {
|
|
11505
11819
|
report({
|
|
11506
11820
|
location: { pos: 0, end: 0 },
|
|
11507
|
-
messageText: "This project targets Effect v4, but
|
|
11821
|
+
messageText: "This project targets Effect v4, but this code uses Effect v3 APIs. The referenced API belongs to the v3 surface rather than the configured v4 surface.",
|
|
11508
11822
|
fixes: []
|
|
11509
11823
|
});
|
|
11510
11824
|
}
|
|
@@ -11680,7 +11994,7 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
11680
11994
|
};
|
|
11681
11995
|
report({
|
|
11682
11996
|
location: member,
|
|
11683
|
-
messageText: "
|
|
11997
|
+
messageText: "This Schema subclass defines its own constructor. For Schema classes, constructor overrides break decoding behavior for the class shape. Custom construction can be expressed through a static `new` method instead.",
|
|
11684
11998
|
fixes: (member.body ? [fixAsStaticNew] : []).concat([{
|
|
11685
11999
|
fixName: "overriddenSchemaConstructor_fix",
|
|
11686
12000
|
description: "Remove the constructor override",
|
|
@@ -11802,7 +12116,7 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11802
12116
|
if (isSome2(match2)) {
|
|
11803
12117
|
report({
|
|
11804
12118
|
location: match2.value,
|
|
11805
|
-
messageText: "
|
|
12119
|
+
messageText: "This code uses `JSON.parse` or `JSON.stringify`. Effect Schema provides Effect-aware APIs for JSON parsing and stringifying.",
|
|
11806
12120
|
fixes: []
|
|
11807
12121
|
});
|
|
11808
12122
|
}
|
|
@@ -11810,6 +12124,63 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
11810
12124
|
})
|
|
11811
12125
|
});
|
|
11812
12126
|
|
|
12127
|
+
// src/diagnostics/processEnvInEffect.ts
|
|
12128
|
+
var isEnvPropertyAccess = (tsApi, node) => tsApi.isPropertyAccessExpression(node) && tsApi.idText(node.name) === "env";
|
|
12129
|
+
var isProcessEnvMemberAccess = (tsApi, node) => (tsApi.isPropertyAccessExpression(node) || tsApi.isElementAccessExpression(node)) && isEnvPropertyAccess(tsApi, node.expression);
|
|
12130
|
+
var makeProcessEnvApply = (checkInEffect) => fn(`processEnv${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
|
|
12131
|
+
const ts = yield* service(TypeScriptApi);
|
|
12132
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
12133
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
12134
|
+
const typeParser = yield* service(TypeParser);
|
|
12135
|
+
const processSymbol = typeChecker.resolveName("process", void 0, ts.SymbolFlags.Value, false);
|
|
12136
|
+
if (!processSymbol) return;
|
|
12137
|
+
const nodeToVisit = [];
|
|
12138
|
+
const appendNodeToVisit = (node) => {
|
|
12139
|
+
nodeToVisit.push(node);
|
|
12140
|
+
return void 0;
|
|
12141
|
+
};
|
|
12142
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
12143
|
+
while (nodeToVisit.length > 0) {
|
|
12144
|
+
const node = nodeToVisit.shift();
|
|
12145
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
12146
|
+
if (!isProcessEnvMemberAccess(ts, node)) continue;
|
|
12147
|
+
const processNode2 = node.expression.expression;
|
|
12148
|
+
if (!ts.isIdentifier(processNode2) || ts.idText(processNode2) !== "process") continue;
|
|
12149
|
+
const symbol3 = typeChecker.getSymbolAtLocation(processNode2);
|
|
12150
|
+
if (!symbol3) continue;
|
|
12151
|
+
if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== processSymbol) continue;
|
|
12152
|
+
const { inEffect } = yield* typeParser.findEnclosingScopes(node);
|
|
12153
|
+
if (inEffect !== checkInEffect) continue;
|
|
12154
|
+
report({
|
|
12155
|
+
location: node,
|
|
12156
|
+
messageText: checkInEffect ? "This Effect code reads from `process.env`, environment configuration in Effect code is represented through `Config` from Effect." : "This code reads from `process.env`, environment configuration is represented through `Config` from Effect.",
|
|
12157
|
+
fixes: []
|
|
12158
|
+
});
|
|
12159
|
+
}
|
|
12160
|
+
});
|
|
12161
|
+
var processEnvInEffect = createDiagnostic({
|
|
12162
|
+
name: "processEnvInEffect",
|
|
12163
|
+
code: 65,
|
|
12164
|
+
description: "Warns when reading process.env inside Effect generators instead of using Effect Config",
|
|
12165
|
+
group: "effectNative",
|
|
12166
|
+
severity: "off",
|
|
12167
|
+
fixable: false,
|
|
12168
|
+
supportedEffect: ["v3", "v4"],
|
|
12169
|
+
apply: makeProcessEnvApply(true)
|
|
12170
|
+
});
|
|
12171
|
+
|
|
12172
|
+
// src/diagnostics/processEnv.ts
|
|
12173
|
+
var processEnv = createDiagnostic({
|
|
12174
|
+
name: "processEnv",
|
|
12175
|
+
code: 64,
|
|
12176
|
+
description: "Warns when reading process.env outside Effect generators instead of using Effect Config",
|
|
12177
|
+
group: "effectNative",
|
|
12178
|
+
severity: "off",
|
|
12179
|
+
fixable: false,
|
|
12180
|
+
supportedEffect: ["v3", "v4"],
|
|
12181
|
+
apply: makeProcessEnvApply(false)
|
|
12182
|
+
});
|
|
12183
|
+
|
|
11813
12184
|
// src/diagnostics/redundantSchemaTagIdentifier.ts
|
|
11814
12185
|
var redundantSchemaTagIdentifier = createDiagnostic({
|
|
11815
12186
|
name: "redundantSchemaTagIdentifier",
|
|
@@ -11920,9 +12291,7 @@ var returnEffectInGen = createDiagnostic({
|
|
|
11920
12291
|
}] : [];
|
|
11921
12292
|
report({
|
|
11922
12293
|
location: node,
|
|
11923
|
-
messageText:
|
|
11924
|
-
Maybe you wanted to return yield* instead?
|
|
11925
|
-
Nested Effect-able types may be intended if you plan to later manually flatten or unwrap this Effect, if so you can safely disable this diagnostic for this line through quickfixes.`,
|
|
12294
|
+
messageText: "This generator returns an Effect-able value directly, which produces a nested `Effect<Effect<...>>`. If the intended result is the inner Effect value, `return yield*` represents that form.",
|
|
11926
12295
|
fixes: fix
|
|
11927
12296
|
});
|
|
11928
12297
|
}),
|
|
@@ -12077,9 +12446,7 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
12077
12446
|
);
|
|
12078
12447
|
});
|
|
12079
12448
|
const v4MethodName = `${isEffectRunCall.value.methodName}With`;
|
|
12080
|
-
const messageText = supportedEffect === "v4" ?
|
|
12081
|
-
Consider extracting the current services by using for example Effect.services and then use Effect.${v4MethodName} with the extracted services instead.` : `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
|
|
12082
|
-
Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
|
|
12449
|
+
const messageText = supportedEffect === "v4" ? `\`${nodeText}\` is called inside an Effect with a separate services invocation. In this context, child Effects run with the surrounding services, which can be accessed through \`Effect.services\` and \`Effect.${v4MethodName}\`.` : `\`${nodeText}\` is called inside an Effect with a separate runtime invocation. In this context, run child Effects with the surrounding runtime, which can be accessed through \`Effect.runtime\` and \`Runtime.${isEffectRunCall.value.methodName}\`.`;
|
|
12083
12450
|
report({
|
|
12084
12451
|
location: node.expression,
|
|
12085
12452
|
messageText,
|
|
@@ -12092,7 +12459,7 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
|
|
|
12092
12459
|
} else {
|
|
12093
12460
|
report({
|
|
12094
12461
|
location: node.expression,
|
|
12095
|
-
messageText:
|
|
12462
|
+
messageText: `\`${nodeText}\` is called inside an existing Effect context. Here, the inner Effect can be used directly.`,
|
|
12096
12463
|
fixes: []
|
|
12097
12464
|
});
|
|
12098
12465
|
}
|
|
@@ -12147,7 +12514,7 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
12147
12514
|
const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
|
|
12148
12515
|
report({
|
|
12149
12516
|
location: node,
|
|
12150
|
-
messageText: "Schema.Struct
|
|
12517
|
+
messageText: "This `Schema.Struct` includes a `_tag` field. `Schema.TaggedStruct` is the tagged-struct form for this pattern and makes the tag optional in the constructor.",
|
|
12151
12518
|
fixes: [{
|
|
12152
12519
|
fixName: "schemaStructWithTag_fix",
|
|
12153
12520
|
description: "Replace with Schema.TaggedStruct",
|
|
@@ -12240,7 +12607,7 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
12240
12607
|
const effectMethodName = syncToEffectMethod[isSchemaSyncCall.value.methodName];
|
|
12241
12608
|
report({
|
|
12242
12609
|
location: node.expression,
|
|
12243
|
-
messageText:
|
|
12610
|
+
messageText: `\`${nodeText}\` is used inside an Effect generator. \`Schema.${effectMethodName}\` preserves the typed Effect error channel for this operation without throwing.`,
|
|
12244
12611
|
fixes: []
|
|
12245
12612
|
});
|
|
12246
12613
|
}
|
|
@@ -12300,7 +12667,7 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
12300
12667
|
const schemaLiteralExpression = firstLiteralCall.expression;
|
|
12301
12668
|
report({
|
|
12302
12669
|
location: node,
|
|
12303
|
-
messageText: "
|
|
12670
|
+
messageText: "This `Schema.Union` contains multiple `Schema.Literal` members and can be simplified to a single `Schema.Literal` call.",
|
|
12304
12671
|
fixes: [{
|
|
12305
12672
|
fixName: "schemaUnionOfLiterals_fix",
|
|
12306
12673
|
description: "Replace with a single Schema.Literal call",
|
|
@@ -12363,8 +12730,7 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
12363
12730
|
map5(
|
|
12364
12731
|
() => report({
|
|
12365
12732
|
location: node,
|
|
12366
|
-
messageText: `
|
|
12367
|
-
Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
12733
|
+
messageText: "This layer construction leaves `Scope` in the requirement set. The scoped API removes `Scope` from the resulting requirements.",
|
|
12368
12734
|
fixes: methodIdentifier ? [{
|
|
12369
12735
|
fixName: "scopeInLayerEffect_scoped",
|
|
12370
12736
|
description: "Use scoped for Layer creation",
|
|
@@ -12464,7 +12830,7 @@ var serviceNotAsClass = createDiagnostic({
|
|
|
12464
12830
|
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
12465
12831
|
report({
|
|
12466
12832
|
location: callExpr,
|
|
12467
|
-
messageText:
|
|
12833
|
+
messageText: `\`ServiceMap.Service\` is assigned to a variable here, but this API is intended for a class declaration shape such as \`class ${variableName} extends ServiceMap.Service<${variableName}, ${shapeText}>()("${argsText.replace(/['"]/g, "")}") {}\`.`,
|
|
12468
12834
|
fixes: [{
|
|
12469
12835
|
fixName: "serviceNotAsClass",
|
|
12470
12836
|
description: `Convert to class declaration`,
|
|
@@ -12677,7 +13043,7 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
12677
13043
|
map5(() => {
|
|
12678
13044
|
report({
|
|
12679
13045
|
location: node,
|
|
12680
|
-
messageText: `
|
|
13046
|
+
messageText: `This Effect generator contains \`try/catch\`; in this context, error handling is expressed with Effect APIs such as ${alternatives.join(", ")}).`,
|
|
12681
13047
|
fixes: []
|
|
12682
13048
|
});
|
|
12683
13049
|
}),
|
|
@@ -12738,8 +13104,7 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
12738
13104
|
);
|
|
12739
13105
|
report({
|
|
12740
13106
|
location: node.expression,
|
|
12741
|
-
messageText: `The
|
|
12742
|
-
Consider wrapping unknown errors into Effect's Data.TaggedError for example, or narrow down the type to the specific error raised.`,
|
|
13107
|
+
messageText: `The \`catch\` callback in \`${nodeText}\` returns \`unknown\`, so the Effect error type stays untyped. A specific typed error preserves error-channel information, for example by narrowing the value or wrapping it in \`Data.TaggedError\`.`,
|
|
12743
13108
|
fixes: []
|
|
12744
13109
|
});
|
|
12745
13110
|
}
|
|
@@ -12753,6 +13118,56 @@ Consider wrapping unknown errors into Effect's Data.TaggedError for example, or
|
|
|
12753
13118
|
})
|
|
12754
13119
|
});
|
|
12755
13120
|
|
|
13121
|
+
// src/diagnostics/unnecessaryArrowBlock.ts
|
|
13122
|
+
var unnecessaryArrowBlock = createDiagnostic({
|
|
13123
|
+
name: "unnecessaryArrowBlock",
|
|
13124
|
+
code: 72,
|
|
13125
|
+
description: "Suggests using a concise arrow body when the block only returns an expression",
|
|
13126
|
+
group: "style",
|
|
13127
|
+
severity: "off",
|
|
13128
|
+
fixable: true,
|
|
13129
|
+
supportedEffect: ["v3", "v4"],
|
|
13130
|
+
apply: fn("unnecessaryArrowBlock.apply")(function* (sourceFile, report) {
|
|
13131
|
+
const ts = yield* service(TypeScriptApi);
|
|
13132
|
+
const nodeToVisit = [];
|
|
13133
|
+
const appendNodeToVisit = (node) => {
|
|
13134
|
+
nodeToVisit.push(node);
|
|
13135
|
+
return void 0;
|
|
13136
|
+
};
|
|
13137
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
13138
|
+
while (nodeToVisit.length > 0) {
|
|
13139
|
+
const node = nodeToVisit.shift();
|
|
13140
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
13141
|
+
if (!ts.isArrowFunction(node) || !ts.isBlock(node.body)) continue;
|
|
13142
|
+
if (node.body.statements.length !== 1) continue;
|
|
13143
|
+
const [statement] = node.body.statements;
|
|
13144
|
+
if (!ts.isReturnStatement(statement) || !statement.expression) continue;
|
|
13145
|
+
const returnedExpression = statement.expression;
|
|
13146
|
+
report({
|
|
13147
|
+
location: node.body,
|
|
13148
|
+
messageText: "This arrow function block only returns an expression and can use a concise body.",
|
|
13149
|
+
fixes: [{
|
|
13150
|
+
fixName: "unnecessaryArrowBlock_fix",
|
|
13151
|
+
description: "Use a concise arrow body",
|
|
13152
|
+
apply: gen(function* () {
|
|
13153
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
13154
|
+
const replacementNode = ts.factory.updateArrowFunction(
|
|
13155
|
+
node,
|
|
13156
|
+
node.modifiers,
|
|
13157
|
+
node.typeParameters,
|
|
13158
|
+
node.parameters,
|
|
13159
|
+
node.type,
|
|
13160
|
+
node.equalsGreaterThanToken,
|
|
13161
|
+
ts.factory.createParenthesizedExpression(returnedExpression)
|
|
13162
|
+
);
|
|
13163
|
+
changeTracker.replaceNode(sourceFile, node, replacementNode);
|
|
13164
|
+
})
|
|
13165
|
+
}]
|
|
13166
|
+
});
|
|
13167
|
+
}
|
|
13168
|
+
})
|
|
13169
|
+
});
|
|
13170
|
+
|
|
12756
13171
|
// src/diagnostics/unnecessaryEffectGen.ts
|
|
12757
13172
|
var unnecessaryEffectGen = createDiagnostic({
|
|
12758
13173
|
name: "unnecessaryEffectGen",
|
|
@@ -12836,7 +13251,7 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
12836
13251
|
map5(
|
|
12837
13252
|
() => report({
|
|
12838
13253
|
location: node,
|
|
12839
|
-
messageText:
|
|
13254
|
+
messageText: "This `yield* Effect.fail(...)` passes a yieldable error value. `yield*` represents that value directly without wrapping it in `Effect.fail`.",
|
|
12840
13255
|
fixes: [{
|
|
12841
13256
|
fixName: "unnecessaryFailYieldableError_fix",
|
|
12842
13257
|
description: "Replace yield* Effect.fail with yield*",
|
|
@@ -12941,7 +13356,7 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
12941
13356
|
map5(({ innerCall, pipeCall }) => {
|
|
12942
13357
|
report({
|
|
12943
13358
|
location: node,
|
|
12944
|
-
messageText: `
|
|
13359
|
+
messageText: "This expression contains chained `pipe` calls that can be simplified to a single `pipe` call.",
|
|
12945
13360
|
fixes: [{
|
|
12946
13361
|
fixName: "unnecessaryPipeChain_fix",
|
|
12947
13362
|
description: "Rewrite as single pipe call",
|
|
@@ -13053,12 +13468,17 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
13053
13468
|
var diagnostics = [
|
|
13054
13469
|
outdatedApi,
|
|
13055
13470
|
anyUnknownInErrorContext,
|
|
13471
|
+
asyncFunction,
|
|
13056
13472
|
instanceOfSchema,
|
|
13057
13473
|
catchAllToMapError,
|
|
13058
13474
|
catchUnfailableEffect,
|
|
13059
13475
|
classSelfMismatch,
|
|
13476
|
+
cryptoRandomUUID,
|
|
13477
|
+
cryptoRandomUUIDInEffect,
|
|
13060
13478
|
duplicatePackage,
|
|
13479
|
+
effectDoNotation,
|
|
13061
13480
|
effectFnImplicitAny,
|
|
13481
|
+
effectMapFlatten,
|
|
13062
13482
|
effectGenUsesAdapter,
|
|
13063
13483
|
missingEffectContext,
|
|
13064
13484
|
missingEffectError,
|
|
@@ -13067,6 +13487,8 @@ var diagnostics = [
|
|
|
13067
13487
|
floatingEffect,
|
|
13068
13488
|
effectInFailure,
|
|
13069
13489
|
missingStarInYieldEffectGen,
|
|
13490
|
+
newPromise,
|
|
13491
|
+
lazyPromiseInEffectSync,
|
|
13070
13492
|
unnecessaryEffectGen,
|
|
13071
13493
|
unnecessaryFailYieldableError,
|
|
13072
13494
|
missingReturnYieldStar,
|
|
@@ -13075,6 +13497,8 @@ var diagnostics = [
|
|
|
13075
13497
|
genericEffectServices,
|
|
13076
13498
|
globalFetch,
|
|
13077
13499
|
globalFetchInEffect,
|
|
13500
|
+
processEnv,
|
|
13501
|
+
processEnvInEffect,
|
|
13078
13502
|
returnEffectInGen,
|
|
13079
13503
|
tryCatchInEffectGen,
|
|
13080
13504
|
importFromBarrel,
|
|
@@ -13092,6 +13516,8 @@ var diagnostics = [
|
|
|
13092
13516
|
strictEffectProvide,
|
|
13093
13517
|
unknownInEffectCatch,
|
|
13094
13518
|
runEffectInsideEffect,
|
|
13519
|
+
nestedEffectGenYield,
|
|
13520
|
+
unnecessaryArrowBlock,
|
|
13095
13521
|
schemaUnionOfLiterals,
|
|
13096
13522
|
schemaStructWithTag,
|
|
13097
13523
|
globalErrorInEffectCatch,
|
|
@@ -14409,7 +14835,7 @@ var middlewareGenLike = fn("middlewareGenLike")(function* (sourceFile, _span, pr
|
|
|
14409
14835
|
// src/quickinfo/dedupeJsDocs.ts
|
|
14410
14836
|
var SymbolDisplayPartEq = make((fa, fb) => fa.kind === fb.kind && fa.text === fb.text);
|
|
14411
14837
|
var JSDocTagInfoEq = make(
|
|
14412
|
-
(fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ?
|
|
14838
|
+
(fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? Array_(SymbolDisplayPartEq)(fa.text, fb.text) : true)
|
|
14413
14839
|
);
|
|
14414
14840
|
function dedupeJsDocs(quickInfo2) {
|
|
14415
14841
|
if (!quickInfo2) return succeed3(quickInfo2);
|