@effect/language-service 0.77.0 → 0.79.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 +65 -42
- package/cli.js +1785 -786
- package/cli.js.map +1 -1
- package/effect-lsp-patch-utils.js +726 -128
- package/effect-lsp-patch-utils.js.map +1 -1
- package/index.js +759 -159
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/transform.js +720 -128
- package/transform.js.map +1 -1
|
@@ -27,7 +27,7 @@ __export(effect_lsp_patch_utils_exports, {
|
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(effect_lsp_patch_utils_exports);
|
|
29
29
|
|
|
30
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
30
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Pipeable.js
|
|
31
31
|
var pipeArguments = (self, args3) => {
|
|
32
32
|
switch (args3.length) {
|
|
33
33
|
case 0:
|
|
@@ -60,7 +60,7 @@ var pipeArguments = (self, args3) => {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
63
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Function.js
|
|
64
64
|
var dual = function(arity, body) {
|
|
65
65
|
if (typeof arity === "function") {
|
|
66
66
|
return function() {
|
|
@@ -108,7 +108,7 @@ function pipe(a, ...args3) {
|
|
|
108
108
|
return pipeArguments(a, args3);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
111
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/equal.js
|
|
112
112
|
var getAllObjectKeys = (obj) => {
|
|
113
113
|
const keys2 = new Set(Reflect.ownKeys(obj));
|
|
114
114
|
if (obj.constructor === Object) return keys2;
|
|
@@ -131,7 +131,7 @@ var getAllObjectKeys = (obj) => {
|
|
|
131
131
|
};
|
|
132
132
|
var byReferenceInstances = /* @__PURE__ */ new WeakSet();
|
|
133
133
|
|
|
134
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
134
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Predicate.js
|
|
135
135
|
function isString(input) {
|
|
136
136
|
return typeof input === "string";
|
|
137
137
|
}
|
|
@@ -152,7 +152,7 @@ function isObjectKeyword(input) {
|
|
|
152
152
|
}
|
|
153
153
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObjectKeyword(self) && property in self);
|
|
154
154
|
|
|
155
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
155
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Hash.js
|
|
156
156
|
var symbol = "~effect/interfaces/Hash";
|
|
157
157
|
var hash = (self) => {
|
|
158
158
|
switch (typeof self) {
|
|
@@ -271,7 +271,7 @@ function withVisitedTracking(obj, fn2) {
|
|
|
271
271
|
return result;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
274
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Equal.js
|
|
275
275
|
var symbol2 = "~effect/interfaces/Equal";
|
|
276
276
|
function equals() {
|
|
277
277
|
if (arguments.length === 1) {
|
|
@@ -433,7 +433,10 @@ var compareSets = /* @__PURE__ */ makeCompareSet(compareBoth);
|
|
|
433
433
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
434
434
|
var asEquivalence = () => equals;
|
|
435
435
|
|
|
436
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
436
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/array.js
|
|
437
|
+
var isArrayNonEmpty = (self) => self.length > 0;
|
|
438
|
+
|
|
439
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Redactable.js
|
|
437
440
|
var symbolRedactable = /* @__PURE__ */ Symbol.for("~effect/Inspectable/redactable");
|
|
438
441
|
var isRedactable = (u) => hasProperty(u, symbolRedactable);
|
|
439
442
|
function redact(u) {
|
|
@@ -452,7 +455,7 @@ var emptyServiceMap = {
|
|
|
452
455
|
}
|
|
453
456
|
};
|
|
454
457
|
|
|
455
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
458
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Formatter.js
|
|
456
459
|
function format(input, options) {
|
|
457
460
|
const space = options?.space ?? 0;
|
|
458
461
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -531,7 +534,7 @@ function safeToString(input) {
|
|
|
531
534
|
}
|
|
532
535
|
}
|
|
533
536
|
|
|
534
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
537
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Inspectable.js
|
|
535
538
|
var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
536
539
|
var toJson = (input) => {
|
|
537
540
|
try {
|
|
@@ -575,7 +578,7 @@ var Class = class {
|
|
|
575
578
|
}
|
|
576
579
|
};
|
|
577
580
|
|
|
578
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
581
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Utils.js
|
|
579
582
|
var GenKindTypeId = "~effect/Utils/GenKind";
|
|
580
583
|
var GenKindImpl = class {
|
|
581
584
|
value;
|
|
@@ -643,7 +646,7 @@ var internalCall = isNotOptimizedAway ? standard[InternalTypeId] : forced[Intern
|
|
|
643
646
|
var genConstructor = function* () {
|
|
644
647
|
}.constructor;
|
|
645
648
|
|
|
646
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
649
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/core.js
|
|
647
650
|
var EffectTypeId = `~effect/Effect`;
|
|
648
651
|
var ExitTypeId = `~effect/Exit`;
|
|
649
652
|
var effectVariance = {
|
|
@@ -990,7 +993,7 @@ var DoneVoid = {
|
|
|
990
993
|
value: void 0
|
|
991
994
|
};
|
|
992
995
|
|
|
993
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
996
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/option.js
|
|
994
997
|
var TypeId = "~effect/data/Option";
|
|
995
998
|
var CommonProto = {
|
|
996
999
|
[TypeId]: {
|
|
@@ -1055,7 +1058,7 @@ var some = (value) => {
|
|
|
1055
1058
|
return a;
|
|
1056
1059
|
};
|
|
1057
1060
|
|
|
1058
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1061
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/result.js
|
|
1059
1062
|
var TypeId2 = "~effect/data/Result";
|
|
1060
1063
|
var CommonProto2 = {
|
|
1061
1064
|
[TypeId2]: {
|
|
@@ -1126,13 +1129,13 @@ var succeed = (success) => {
|
|
|
1126
1129
|
return a;
|
|
1127
1130
|
};
|
|
1128
1131
|
|
|
1129
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1132
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Order.js
|
|
1130
1133
|
function make(compare) {
|
|
1131
1134
|
return (self, that) => self === that ? 0 : compare(self, that);
|
|
1132
1135
|
}
|
|
1133
1136
|
var String2 = /* @__PURE__ */ make((self, that) => self < that ? -1 : 1);
|
|
1134
1137
|
|
|
1135
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1138
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Option.js
|
|
1136
1139
|
var none2 = () => none;
|
|
1137
1140
|
var some2 = some;
|
|
1138
1141
|
var isNone2 = isNone;
|
|
@@ -1142,7 +1145,7 @@ var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : se
|
|
|
1142
1145
|
var fromNullishOr = (a) => a == null ? none2() : some2(a);
|
|
1143
1146
|
var getOrUndefined = /* @__PURE__ */ getOrElse(constUndefined);
|
|
1144
1147
|
|
|
1145
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1148
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Result.js
|
|
1146
1149
|
var succeed2 = succeed;
|
|
1147
1150
|
var fail2 = fail;
|
|
1148
1151
|
var isFailure2 = isFailure;
|
|
@@ -1150,18 +1153,7 @@ var isSuccess2 = isSuccess;
|
|
|
1150
1153
|
var map = /* @__PURE__ */ dual(2, (self, f) => isSuccess2(self) ? succeed2(f(self.success)) : fail2(self.failure));
|
|
1151
1154
|
var getOrElse2 = /* @__PURE__ */ dual(2, (self, onFailure) => isFailure2(self) ? onFailure(self.failure) : self.success);
|
|
1152
1155
|
|
|
1153
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1154
|
-
var apply = (filter2, input, ...args3) => {
|
|
1155
|
-
const result = filter2(input, ...args3);
|
|
1156
|
-
if (result === true) return succeed2(input);
|
|
1157
|
-
if (result === false) return fail2(input);
|
|
1158
|
-
return result;
|
|
1159
|
-
};
|
|
1160
|
-
|
|
1161
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.14/node_modules/effect/dist/internal/array.js
|
|
1162
|
-
var isArrayNonEmpty = (self) => self.length > 0;
|
|
1163
|
-
|
|
1164
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.14/node_modules/effect/dist/Record.js
|
|
1156
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Record.js
|
|
1165
1157
|
var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
1166
1158
|
const out = {
|
|
1167
1159
|
...self
|
|
@@ -1173,7 +1165,7 @@ var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1173
1165
|
});
|
|
1174
1166
|
var keys = (self) => Object.keys(self);
|
|
1175
1167
|
|
|
1176
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1168
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Array.js
|
|
1177
1169
|
var Array2 = globalThis.Array;
|
|
1178
1170
|
var fromIterable = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
|
|
1179
1171
|
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
@@ -1236,13 +1228,12 @@ var flatMap = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1236
1228
|
return out;
|
|
1237
1229
|
});
|
|
1238
1230
|
var flatten = /* @__PURE__ */ flatMap(identity);
|
|
1239
|
-
var filter = /* @__PURE__ */ dual(2, (self,
|
|
1231
|
+
var filter = /* @__PURE__ */ dual(2, (self, predicate) => {
|
|
1240
1232
|
const as = fromIterable(self);
|
|
1241
1233
|
const out = [];
|
|
1242
1234
|
for (let i = 0; i < as.length; i++) {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
out.push(result.success);
|
|
1235
|
+
if (predicate(as[i], i)) {
|
|
1236
|
+
out.push(as[i]);
|
|
1246
1237
|
}
|
|
1247
1238
|
}
|
|
1248
1239
|
return out;
|
|
@@ -1646,10 +1637,12 @@ var defaults = {
|
|
|
1646
1637
|
extendedKeyDetection: false,
|
|
1647
1638
|
ignoreEffectWarningsInTscExitCode: false,
|
|
1648
1639
|
ignoreEffectSuggestionsInTscExitCode: true,
|
|
1640
|
+
ignoreEffectErrorsInTscExitCode: false,
|
|
1649
1641
|
pipeableMinArgCount: 2,
|
|
1650
1642
|
effectFn: ["span"],
|
|
1651
1643
|
layerGraphFollowDepth: 0,
|
|
1652
|
-
mermaidProvider: "mermaid.live"
|
|
1644
|
+
mermaidProvider: "mermaid.live",
|
|
1645
|
+
skipDisabledOptimization: false
|
|
1653
1646
|
};
|
|
1654
1647
|
function parseKeyPatterns(patterns) {
|
|
1655
1648
|
const result = [];
|
|
@@ -1673,6 +1666,7 @@ function parse(config) {
|
|
|
1673
1666
|
includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
|
|
1674
1667
|
ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
|
|
1675
1668
|
ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
|
|
1669
|
+
ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
|
|
1676
1670
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
|
|
1677
1671
|
quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
|
|
1678
1672
|
quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
|
|
@@ -1689,9 +1683,12 @@ function parse(config) {
|
|
|
1689
1683
|
keyPatterns: isObject(config) && hasProperty(config, "keyPatterns") && isArray(config.keyPatterns) ? parseKeyPatterns(config.keyPatterns) : defaults.keyPatterns,
|
|
1690
1684
|
extendedKeyDetection: isObject(config) && hasProperty(config, "extendedKeyDetection") && isBoolean(config.extendedKeyDetection) ? config.extendedKeyDetection : defaults.extendedKeyDetection,
|
|
1691
1685
|
pipeableMinArgCount: isObject(config) && hasProperty(config, "pipeableMinArgCount") && isNumber(config.pipeableMinArgCount) ? config.pipeableMinArgCount : defaults.pipeableMinArgCount,
|
|
1692
|
-
effectFn: isObject(config) && hasProperty(config, "effectFn") && isArray(config.effectFn) && config.effectFn.every(isString) ? config.effectFn.map(
|
|
1686
|
+
effectFn: isObject(config) && hasProperty(config, "effectFn") && isArray(config.effectFn) && config.effectFn.every(isString) ? config.effectFn.map(
|
|
1687
|
+
(_) => _.toLowerCase()
|
|
1688
|
+
) : defaults.effectFn,
|
|
1693
1689
|
layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
1694
|
-
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
|
|
1690
|
+
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
|
|
1691
|
+
skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
|
|
1695
1692
|
};
|
|
1696
1693
|
}
|
|
1697
1694
|
|
|
@@ -2461,7 +2458,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
2461
2458
|
if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
|
|
2462
2459
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2463
2460
|
}
|
|
2464
|
-
if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2461
|
+
if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2465
2462
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2466
2463
|
}
|
|
2467
2464
|
const fixByDisableNextLine = (node) => ({
|
|
@@ -3381,6 +3378,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3381
3378
|
const layerType = cachedBy(
|
|
3382
3379
|
fn("TypeParser.layerType")(function* (type, atLocation) {
|
|
3383
3380
|
yield* pipeableType(type, atLocation);
|
|
3381
|
+
if (supportedEffect() === "v4") {
|
|
3382
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Layer");
|
|
3383
|
+
if (typeIdSymbol) {
|
|
3384
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
3385
|
+
return yield* layerVarianceStruct(typeIdType, atLocation);
|
|
3386
|
+
}
|
|
3387
|
+
return yield* typeParserIssue("Type is not a layer", type, atLocation);
|
|
3388
|
+
}
|
|
3384
3389
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
3385
3390
|
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
|
|
3386
3391
|
);
|
|
@@ -3430,6 +3435,34 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3430
3435
|
"TypeParser.effectSubtype",
|
|
3431
3436
|
(type) => type
|
|
3432
3437
|
);
|
|
3438
|
+
const effectYieldableType = cachedBy(
|
|
3439
|
+
fn("TypeParser.effectYieldableType")(function* (type, atLocation) {
|
|
3440
|
+
if (supportedEffect() === "v3") {
|
|
3441
|
+
return yield* effectType(type, atLocation);
|
|
3442
|
+
}
|
|
3443
|
+
return yield* firstSuccessOf([
|
|
3444
|
+
effectType(type, atLocation),
|
|
3445
|
+
gen(function* () {
|
|
3446
|
+
const asEffectSymbol = typeChecker.getPropertyOfType(type, "asEffect");
|
|
3447
|
+
if (!asEffectSymbol) {
|
|
3448
|
+
return yield* typeParserIssue("Type has no 'asEffect' property", type, atLocation);
|
|
3449
|
+
}
|
|
3450
|
+
const asEffectType = typeChecker.getTypeOfSymbolAtLocation(asEffectSymbol, atLocation);
|
|
3451
|
+
const asEffectSignatures = typeChecker.getSignaturesOfType(asEffectType, ts.SignatureKind.Call);
|
|
3452
|
+
if (asEffectSignatures.length === 0) {
|
|
3453
|
+
return yield* typeParserIssue("'asEffect' property is not callable", type, atLocation);
|
|
3454
|
+
}
|
|
3455
|
+
return yield* firstSuccessOf(
|
|
3456
|
+
asEffectSignatures.map(
|
|
3457
|
+
(signature) => effectType(typeChecker.getReturnTypeOfSignature(signature), atLocation)
|
|
3458
|
+
)
|
|
3459
|
+
);
|
|
3460
|
+
})
|
|
3461
|
+
]);
|
|
3462
|
+
}),
|
|
3463
|
+
"TypeParser.effectYieldableType",
|
|
3464
|
+
(type) => type
|
|
3465
|
+
);
|
|
3433
3466
|
const isEffectContextSourceFile = cachedBy(
|
|
3434
3467
|
fn("TypeParser.isEffectContextSourceFile")(function* (sourceFile) {
|
|
3435
3468
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5057,6 +5090,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5057
5090
|
layerType,
|
|
5058
5091
|
fiberType,
|
|
5059
5092
|
effectSubtype,
|
|
5093
|
+
effectYieldableType,
|
|
5060
5094
|
importedEffectModule,
|
|
5061
5095
|
effectGen,
|
|
5062
5096
|
effectFnUntracedGen,
|
|
@@ -5101,6 +5135,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
5101
5135
|
code: 28,
|
|
5102
5136
|
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
5103
5137
|
severity: "off",
|
|
5138
|
+
fixable: false,
|
|
5139
|
+
supportedEffect: ["v3", "v4"],
|
|
5104
5140
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
5105
5141
|
const ts = yield* service(TypeScriptApi);
|
|
5106
5142
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5204,6 +5240,8 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5204
5240
|
code: 39,
|
|
5205
5241
|
description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
|
|
5206
5242
|
severity: "suggestion",
|
|
5243
|
+
fixable: true,
|
|
5244
|
+
supportedEffect: ["v3", "v4"],
|
|
5207
5245
|
apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
|
|
5208
5246
|
const ts = yield* service(TypeScriptApi);
|
|
5209
5247
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5301,6 +5339,8 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5301
5339
|
code: 2,
|
|
5302
5340
|
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
5303
5341
|
severity: "suggestion",
|
|
5342
|
+
fixable: false,
|
|
5343
|
+
supportedEffect: ["v3", "v4"],
|
|
5304
5344
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
5305
5345
|
const ts = yield* service(TypeScriptApi);
|
|
5306
5346
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5350,6 +5390,8 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5350
5390
|
code: 20,
|
|
5351
5391
|
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
5352
5392
|
severity: "error",
|
|
5393
|
+
fixable: true,
|
|
5394
|
+
supportedEffect: ["v3", "v4"],
|
|
5353
5395
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
5354
5396
|
const ts = yield* service(TypeScriptApi);
|
|
5355
5397
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5488,6 +5530,8 @@ var deterministicKeys = createDiagnostic({
|
|
|
5488
5530
|
code: 25,
|
|
5489
5531
|
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
5490
5532
|
severity: "off",
|
|
5533
|
+
fixable: true,
|
|
5534
|
+
supportedEffect: ["v3", "v4"],
|
|
5491
5535
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
5492
5536
|
const ts = yield* service(TypeScriptApi);
|
|
5493
5537
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5605,6 +5649,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5605
5649
|
code: 6,
|
|
5606
5650
|
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
5607
5651
|
severity: "warning",
|
|
5652
|
+
fixable: false,
|
|
5653
|
+
supportedEffect: ["v3", "v4"],
|
|
5608
5654
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
5609
5655
|
const typeParser = yield* service(TypeParser);
|
|
5610
5656
|
const options = yield* service(LanguageServicePluginOptions);
|
|
@@ -5634,6 +5680,8 @@ var effectFnIife = createDiagnostic({
|
|
|
5634
5680
|
code: 46,
|
|
5635
5681
|
description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
|
|
5636
5682
|
severity: "warning",
|
|
5683
|
+
fixable: true,
|
|
5684
|
+
supportedEffect: ["v3", "v4"],
|
|
5637
5685
|
apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
|
|
5638
5686
|
const ts = yield* service(TypeScriptApi);
|
|
5639
5687
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5736,6 +5784,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5736
5784
|
code: 41,
|
|
5737
5785
|
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
5738
5786
|
severity: "suggestion",
|
|
5787
|
+
fixable: true,
|
|
5788
|
+
supportedEffect: ["v3", "v4"],
|
|
5739
5789
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
5740
5790
|
const ts = yield* service(TypeScriptApi);
|
|
5741
5791
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5769,16 +5819,16 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5769
5819
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
5770
5820
|
return node.name;
|
|
5771
5821
|
}
|
|
5772
|
-
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
5822
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name) && node.parent.initializer === node) {
|
|
5773
5823
|
return node.parent.name;
|
|
5774
5824
|
}
|
|
5775
|
-
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
5825
|
+
if (node.parent && ts.isPropertyAssignment(node.parent) && node.parent.initializer === node) {
|
|
5776
5826
|
const name = node.parent.name;
|
|
5777
5827
|
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
5778
5828
|
return name;
|
|
5779
5829
|
}
|
|
5780
5830
|
}
|
|
5781
|
-
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
5831
|
+
if (node.parent && ts.isPropertyDeclaration(node.parent) && node.parent.initializer === node) {
|
|
5782
5832
|
const name = node.parent.name;
|
|
5783
5833
|
if (ts.isIdentifier(name)) {
|
|
5784
5834
|
return name;
|
|
@@ -5786,6 +5836,190 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5786
5836
|
}
|
|
5787
5837
|
return void 0;
|
|
5788
5838
|
};
|
|
5839
|
+
const hasExportModifier = (node) => {
|
|
5840
|
+
if (!ts.canHaveModifiers(node)) return false;
|
|
5841
|
+
const modifiers = ts.getModifiers(node);
|
|
5842
|
+
return modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
5843
|
+
};
|
|
5844
|
+
const layerServiceNameFromExpression = (expression) => {
|
|
5845
|
+
if (expression.kind === ts.SyntaxKind.ThisKeyword) {
|
|
5846
|
+
const enclosingClass = ts.findAncestor(
|
|
5847
|
+
expression,
|
|
5848
|
+
(node) => ts.isClassDeclaration(node)
|
|
5849
|
+
);
|
|
5850
|
+
if (enclosingClass?.name) {
|
|
5851
|
+
return ts.idText(enclosingClass.name);
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
if (ts.isIdentifier(expression)) return ts.idText(expression);
|
|
5855
|
+
return sourceFile.text.slice(expression.pos, expression.end).trim();
|
|
5856
|
+
};
|
|
5857
|
+
const tryGetLayerApiMethod = (node) => pipe(
|
|
5858
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("effect")(node),
|
|
5859
|
+
map4(() => "effect"),
|
|
5860
|
+
orElse2(
|
|
5861
|
+
() => pipe(
|
|
5862
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("succeed")(node),
|
|
5863
|
+
map4(() => "succeed"),
|
|
5864
|
+
orElse2(
|
|
5865
|
+
() => pipe(
|
|
5866
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("sync")(node),
|
|
5867
|
+
map4(() => "sync"),
|
|
5868
|
+
orElse2(() => succeed3(void 0))
|
|
5869
|
+
)
|
|
5870
|
+
)
|
|
5871
|
+
)
|
|
5872
|
+
)
|
|
5873
|
+
);
|
|
5874
|
+
const verifyLayerMethodAtCall = fn("effectFnOpportunity.verifyLayerMethodAtCall")(
|
|
5875
|
+
function* (callExpression, method, implementationExpression) {
|
|
5876
|
+
const directMethod = yield* tryGetLayerApiMethod(callExpression.expression);
|
|
5877
|
+
if (directMethod === method && callExpression.arguments.length >= 2 && callExpression.arguments[1] === implementationExpression) {
|
|
5878
|
+
return layerServiceNameFromExpression(callExpression.arguments[0]);
|
|
5879
|
+
}
|
|
5880
|
+
if (ts.isCallExpression(callExpression.expression)) {
|
|
5881
|
+
const innerCall = callExpression.expression;
|
|
5882
|
+
const innerMethod = yield* tryGetLayerApiMethod(innerCall.expression);
|
|
5883
|
+
if (innerMethod === method && innerCall.arguments.length >= 1 && callExpression.arguments.length >= 1 && callExpression.arguments[0] === implementationExpression) {
|
|
5884
|
+
return layerServiceNameFromExpression(innerCall.arguments[0]);
|
|
5885
|
+
}
|
|
5886
|
+
}
|
|
5887
|
+
return void 0;
|
|
5888
|
+
}
|
|
5889
|
+
);
|
|
5890
|
+
const tryMatchLayerSucceedInference = fn("effectFnOpportunity.tryMatchLayerSucceedInference")(
|
|
5891
|
+
function* (objectLiteral) {
|
|
5892
|
+
const callExpression = objectLiteral.parent;
|
|
5893
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5894
|
+
return yield* verifyLayerMethodAtCall(callExpression, "succeed", objectLiteral);
|
|
5895
|
+
}
|
|
5896
|
+
);
|
|
5897
|
+
const tryMatchLayerSyncInference = fn("effectFnOpportunity.tryMatchLayerSyncInference")(
|
|
5898
|
+
function* (objectLiteral) {
|
|
5899
|
+
const returnStatement = objectLiteral.parent;
|
|
5900
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5901
|
+
const functionBody = returnStatement.parent;
|
|
5902
|
+
if (!functionBody || !ts.isBlock(functionBody)) return void 0;
|
|
5903
|
+
const lazyFunction = functionBody.parent;
|
|
5904
|
+
if (!lazyFunction || !ts.isArrowFunction(lazyFunction) && !ts.isFunctionExpression(lazyFunction)) {
|
|
5905
|
+
return void 0;
|
|
5906
|
+
}
|
|
5907
|
+
const callExpression = lazyFunction.parent;
|
|
5908
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5909
|
+
return yield* verifyLayerMethodAtCall(callExpression, "sync", lazyFunction);
|
|
5910
|
+
}
|
|
5911
|
+
);
|
|
5912
|
+
const tryMatchLayerEffectInference = fn("effectFnOpportunity.tryMatchLayerEffectInference")(
|
|
5913
|
+
function* (objectLiteral) {
|
|
5914
|
+
const returnStatement = objectLiteral.parent;
|
|
5915
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5916
|
+
const generatorBody = returnStatement.parent;
|
|
5917
|
+
if (!generatorBody || !ts.isBlock(generatorBody)) return void 0;
|
|
5918
|
+
const generatorFunction = generatorBody.parent;
|
|
5919
|
+
if (!generatorFunction || !ts.isFunctionExpression(generatorFunction) || !generatorFunction.asteriskToken) {
|
|
5920
|
+
return void 0;
|
|
5921
|
+
}
|
|
5922
|
+
const genCall = generatorFunction.parent;
|
|
5923
|
+
if (!genCall || !ts.isCallExpression(genCall)) return void 0;
|
|
5924
|
+
const parsedEffectGen = yield* option(typeParser.effectGen(genCall));
|
|
5925
|
+
if (parsedEffectGen._tag === "None" || parsedEffectGen.value.generatorFunction !== generatorFunction) {
|
|
5926
|
+
return void 0;
|
|
5927
|
+
}
|
|
5928
|
+
const layerCall = genCall.parent;
|
|
5929
|
+
if (!layerCall || !ts.isCallExpression(layerCall)) return void 0;
|
|
5930
|
+
return yield* verifyLayerMethodAtCall(layerCall, "effect", genCall);
|
|
5931
|
+
}
|
|
5932
|
+
);
|
|
5933
|
+
const tryMatchOfInference = fn("effectFnOpportunity.tryMatchOfInference")(
|
|
5934
|
+
function* (objectLiteral) {
|
|
5935
|
+
const callExpression = objectLiteral.parent;
|
|
5936
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5937
|
+
if (callExpression.arguments.length < 1 || callExpression.arguments[0] !== objectLiteral) return void 0;
|
|
5938
|
+
if (!ts.isPropertyAccessExpression(callExpression.expression)) return void 0;
|
|
5939
|
+
if (ts.idText(callExpression.expression.name) !== "of") return void 0;
|
|
5940
|
+
const serviceTagExpression = callExpression.expression.expression;
|
|
5941
|
+
const serviceTagType = typeCheckerUtils.getTypeAtLocation(serviceTagExpression);
|
|
5942
|
+
if (!serviceTagType) return void 0;
|
|
5943
|
+
const isTagLike = yield* pipe(
|
|
5944
|
+
typeParser.contextTag(serviceTagType, serviceTagExpression),
|
|
5945
|
+
orElse2(() => typeParser.serviceType(serviceTagType, serviceTagExpression)),
|
|
5946
|
+
option
|
|
5947
|
+
);
|
|
5948
|
+
if (isTagLike._tag === "None") return void 0;
|
|
5949
|
+
return layerServiceNameFromExpression(serviceTagExpression);
|
|
5950
|
+
}
|
|
5951
|
+
);
|
|
5952
|
+
const tryMatchServiceMapMakeInference = fn("effectFnOpportunity.tryMatchServiceMapMakeInference")(
|
|
5953
|
+
function* (objectLiteral) {
|
|
5954
|
+
const returnStatement = objectLiteral.parent;
|
|
5955
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5956
|
+
const generatorBody = returnStatement.parent;
|
|
5957
|
+
if (!generatorBody || !ts.isBlock(generatorBody)) return void 0;
|
|
5958
|
+
const generatorFunction = generatorBody.parent;
|
|
5959
|
+
if (!generatorFunction || !ts.isFunctionExpression(generatorFunction) || !generatorFunction.asteriskToken) {
|
|
5960
|
+
return void 0;
|
|
5961
|
+
}
|
|
5962
|
+
const genCall = generatorFunction.parent;
|
|
5963
|
+
if (!genCall || !ts.isCallExpression(genCall)) return void 0;
|
|
5964
|
+
const parsedEffectGen = yield* option(typeParser.effectGen(genCall));
|
|
5965
|
+
if (parsedEffectGen._tag === "None" || parsedEffectGen.value.generatorFunction !== generatorFunction) {
|
|
5966
|
+
return void 0;
|
|
5967
|
+
}
|
|
5968
|
+
const makeProperty = genCall.parent;
|
|
5969
|
+
if (!makeProperty || !ts.isPropertyAssignment(makeProperty)) return void 0;
|
|
5970
|
+
if (makeProperty.initializer !== genCall) return void 0;
|
|
5971
|
+
if (!ts.isIdentifier(makeProperty.name) || ts.idText(makeProperty.name) !== "make") return void 0;
|
|
5972
|
+
let currentNode = makeProperty.parent;
|
|
5973
|
+
let classDeclaration = void 0;
|
|
5974
|
+
while (currentNode) {
|
|
5975
|
+
if (ts.isClassDeclaration(currentNode)) {
|
|
5976
|
+
classDeclaration = currentNode;
|
|
5977
|
+
break;
|
|
5978
|
+
}
|
|
5979
|
+
currentNode = currentNode.parent;
|
|
5980
|
+
}
|
|
5981
|
+
if (!classDeclaration || !classDeclaration.name) return void 0;
|
|
5982
|
+
const parsedServiceMapService = yield* option(typeParser.extendsServiceMapService(classDeclaration));
|
|
5983
|
+
if (parsedServiceMapService._tag === "None") return void 0;
|
|
5984
|
+
return ts.idText(classDeclaration.name);
|
|
5985
|
+
}
|
|
5986
|
+
);
|
|
5987
|
+
const tryGetLayerInferredTraceName = fn("effectFnOpportunity.tryGetLayerInferredTraceName")(
|
|
5988
|
+
function* (node, suggestedTraceName) {
|
|
5989
|
+
if (!suggestedTraceName) return void 0;
|
|
5990
|
+
if (!(node.parent && ts.isPropertyAssignment(node.parent) && node.parent.initializer === node && node.parent.parent && ts.isObjectLiteralExpression(node.parent.parent))) {
|
|
5991
|
+
return void 0;
|
|
5992
|
+
}
|
|
5993
|
+
const objectLiteral = node.parent.parent;
|
|
5994
|
+
const succeedServiceName = yield* tryMatchLayerSucceedInference(objectLiteral);
|
|
5995
|
+
if (succeedServiceName) return `${succeedServiceName}.${suggestedTraceName}`;
|
|
5996
|
+
const syncServiceName = yield* tryMatchLayerSyncInference(objectLiteral);
|
|
5997
|
+
if (syncServiceName) return `${syncServiceName}.${suggestedTraceName}`;
|
|
5998
|
+
const effectServiceName = yield* tryMatchLayerEffectInference(objectLiteral);
|
|
5999
|
+
if (effectServiceName) return `${effectServiceName}.${suggestedTraceName}`;
|
|
6000
|
+
const ofServiceName = yield* tryMatchOfInference(objectLiteral);
|
|
6001
|
+
if (ofServiceName) return `${ofServiceName}.${suggestedTraceName}`;
|
|
6002
|
+
const serviceMapMakeServiceName = yield* tryMatchServiceMapMakeInference(objectLiteral);
|
|
6003
|
+
return serviceMapMakeServiceName ? `${serviceMapMakeServiceName}.${suggestedTraceName}` : void 0;
|
|
6004
|
+
}
|
|
6005
|
+
);
|
|
6006
|
+
const getInferredTraceName = fn("effectFnOpportunity.getInferredTraceName")(
|
|
6007
|
+
function* (node, suggestedTraceName) {
|
|
6008
|
+
const inferredFromLayer = yield* tryGetLayerInferredTraceName(node, suggestedTraceName);
|
|
6009
|
+
if (inferredFromLayer) return inferredFromLayer;
|
|
6010
|
+
if (ts.isFunctionDeclaration(node) && node.name && hasExportModifier(node)) {
|
|
6011
|
+
return ts.idText(node.name);
|
|
6012
|
+
}
|
|
6013
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name) && node.parent.initializer === node) {
|
|
6014
|
+
const variableDeclarationList = node.parent.parent;
|
|
6015
|
+
const variableStatement = variableDeclarationList?.parent;
|
|
6016
|
+
if (variableDeclarationList && ts.isVariableDeclarationList(variableDeclarationList) && variableStatement && ts.isVariableStatement(variableStatement) && hasExportModifier(variableStatement) && (variableDeclarationList.flags & ts.NodeFlags.Const) !== 0) {
|
|
6017
|
+
return ts.idText(node.parent.name);
|
|
6018
|
+
}
|
|
6019
|
+
}
|
|
6020
|
+
return void 0;
|
|
6021
|
+
}
|
|
6022
|
+
);
|
|
5789
6023
|
const areParametersReferencedIn = (fnNode, nodes) => {
|
|
5790
6024
|
if (fnNode.parameters.length === 0 || nodes.length === 0) return false;
|
|
5791
6025
|
const firstParam = fnNode.parameters[0];
|
|
@@ -5870,7 +6104,10 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5870
6104
|
);
|
|
5871
6105
|
};
|
|
5872
6106
|
const parseEffectFnOpportunityTargetGen = fn("effectFnOpportunity.parseEffectFnOpportunityTarget")(
|
|
5873
|
-
function* (node, returnType,
|
|
6107
|
+
function* (node, returnType, nameIdentifier) {
|
|
6108
|
+
const suggestedTraceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
6109
|
+
const inferredTraceName = yield* getInferredTraceName(node, suggestedTraceName);
|
|
6110
|
+
const hasStrictLayerInferredName = inferredTraceName !== void 0 && inferredTraceName !== suggestedTraceName;
|
|
5874
6111
|
if (yield* isInsideEffectFn(node)) {
|
|
5875
6112
|
return yield* TypeParserIssue.issue;
|
|
5876
6113
|
}
|
|
@@ -5879,11 +6116,11 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5879
6116
|
const opportunity = yield* pipe(
|
|
5880
6117
|
tryParseGenOpportunity(node),
|
|
5881
6118
|
orElse2(() => {
|
|
5882
|
-
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
6119
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body) && !hasStrictLayerInferredName) {
|
|
5883
6120
|
return TypeParserIssue.issue;
|
|
5884
6121
|
}
|
|
5885
6122
|
const body = ts.isArrowFunction(node) ? node.body : node.body;
|
|
5886
|
-
if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
|
|
6123
|
+
if ((!body || !ts.isBlock(body) || body.statements.length <= 5) && !hasStrictLayerInferredName) {
|
|
5887
6124
|
return TypeParserIssue.issue;
|
|
5888
6125
|
}
|
|
5889
6126
|
return succeed3({
|
|
@@ -5898,7 +6135,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5898
6135
|
node,
|
|
5899
6136
|
nameIdentifier,
|
|
5900
6137
|
effectModuleName: opportunity.effectModuleName,
|
|
5901
|
-
inferredTraceName
|
|
6138
|
+
inferredTraceName,
|
|
6139
|
+
suggestedTraceName,
|
|
5902
6140
|
explicitTraceExpression: opportunity.explicitTraceExpression,
|
|
5903
6141
|
pipeArguments: opportunity.pipeArguments,
|
|
5904
6142
|
generatorFunction: opportunity.generatorFunction,
|
|
@@ -5908,27 +6146,26 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5908
6146
|
);
|
|
5909
6147
|
const parseEffectFnOpportunityTarget = (node) => {
|
|
5910
6148
|
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
5911
|
-
return
|
|
6149
|
+
return;
|
|
5912
6150
|
}
|
|
5913
6151
|
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
5914
|
-
return
|
|
6152
|
+
return;
|
|
5915
6153
|
}
|
|
5916
6154
|
if (ts.isFunctionExpression(node) && node.name) {
|
|
5917
|
-
return
|
|
6155
|
+
return;
|
|
5918
6156
|
}
|
|
5919
6157
|
if (node.type) {
|
|
5920
|
-
return
|
|
6158
|
+
return;
|
|
5921
6159
|
}
|
|
5922
6160
|
const functionType = typeChecker.getTypeAtLocation(node);
|
|
5923
|
-
if (!functionType) return
|
|
6161
|
+
if (!functionType) return;
|
|
5924
6162
|
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
5925
|
-
if (callSignatures.length !== 1) return
|
|
6163
|
+
if (callSignatures.length !== 1) return;
|
|
5926
6164
|
const signature = callSignatures[0];
|
|
5927
6165
|
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
5928
6166
|
const nameIdentifier = getNameIdentifier(node);
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
return parseEffectFnOpportunityTargetGen(node, returnType, traceName, nameIdentifier);
|
|
6167
|
+
if (!nameIdentifier) return;
|
|
6168
|
+
return parseEffectFnOpportunityTargetGen(node, returnType, nameIdentifier);
|
|
5932
6169
|
};
|
|
5933
6170
|
const getFunctionBodyBlock = (node) => {
|
|
5934
6171
|
if (ts.isArrowFunction(node)) {
|
|
@@ -6002,18 +6239,21 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6002
6239
|
while (nodeToVisit.length > 0) {
|
|
6003
6240
|
const node = nodeToVisit.shift();
|
|
6004
6241
|
ts.forEachChild(node, appendNodeToVisit);
|
|
6005
|
-
const
|
|
6006
|
-
if (
|
|
6007
|
-
|
|
6242
|
+
const test = parseEffectFnOpportunityTarget(node);
|
|
6243
|
+
if (!test) continue;
|
|
6244
|
+
const target = yield* orUndefined(test);
|
|
6245
|
+
if (!target) continue;
|
|
6246
|
+
if (target.hasParamsInPipeArgs) continue;
|
|
6008
6247
|
const {
|
|
6009
6248
|
effectModuleName,
|
|
6010
6249
|
explicitTraceExpression,
|
|
6011
6250
|
inferredTraceName,
|
|
6012
6251
|
nameIdentifier,
|
|
6013
6252
|
node: targetNode,
|
|
6014
|
-
pipeArguments: pipeArguments2
|
|
6015
|
-
|
|
6016
|
-
|
|
6253
|
+
pipeArguments: pipeArguments2,
|
|
6254
|
+
suggestedTraceName
|
|
6255
|
+
} = target;
|
|
6256
|
+
const innerFunction = target.generatorFunction ?? targetNode;
|
|
6017
6257
|
const fixes = [];
|
|
6018
6258
|
if (pluginOptions.effectFn.includes("span") && explicitTraceExpression) {
|
|
6019
6259
|
fixes.push({
|
|
@@ -6033,7 +6273,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6033
6273
|
})
|
|
6034
6274
|
});
|
|
6035
6275
|
}
|
|
6036
|
-
if (pluginOptions.effectFn.includes("untraced") && target.
|
|
6276
|
+
if (pluginOptions.effectFn.includes("untraced") && target.generatorFunction) {
|
|
6037
6277
|
fixes.push({
|
|
6038
6278
|
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
6039
6279
|
description: "Convert to Effect.fnUntraced",
|
|
@@ -6055,22 +6295,41 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6055
6295
|
})
|
|
6056
6296
|
});
|
|
6057
6297
|
}
|
|
6058
|
-
if (
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6298
|
+
if (!explicitTraceExpression) {
|
|
6299
|
+
if (pluginOptions.effectFn.includes("inferred-span") && inferredTraceName) {
|
|
6300
|
+
fixes.push({
|
|
6301
|
+
fixName: "effectFnOpportunity_toEffectFnSpanInferred",
|
|
6302
|
+
description: `Convert to Effect.fn("${inferredTraceName}")`,
|
|
6303
|
+
apply: gen(function* () {
|
|
6304
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6305
|
+
const newNode = createEffectFnNode(
|
|
6306
|
+
targetNode,
|
|
6307
|
+
innerFunction,
|
|
6308
|
+
effectModuleName,
|
|
6309
|
+
inferredTraceName,
|
|
6310
|
+
pipeArguments2
|
|
6311
|
+
);
|
|
6312
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
6313
|
+
})
|
|
6314
|
+
});
|
|
6315
|
+
}
|
|
6316
|
+
if (pluginOptions.effectFn.includes("suggested-span") && suggestedTraceName && (!pluginOptions.effectFn.includes("inferred-span") || suggestedTraceName !== inferredTraceName)) {
|
|
6317
|
+
fixes.push({
|
|
6318
|
+
fixName: "effectFnOpportunity_toEffectFnSpanSuggested",
|
|
6319
|
+
description: `Convert to Effect.fn("${suggestedTraceName}")`,
|
|
6320
|
+
apply: gen(function* () {
|
|
6321
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6322
|
+
const newNode = createEffectFnNode(
|
|
6323
|
+
targetNode,
|
|
6324
|
+
innerFunction,
|
|
6325
|
+
effectModuleName,
|
|
6326
|
+
suggestedTraceName,
|
|
6327
|
+
pipeArguments2
|
|
6328
|
+
);
|
|
6329
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
6330
|
+
})
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6074
6333
|
}
|
|
6075
6334
|
if (fixes.length === 0) continue;
|
|
6076
6335
|
const generateExpectedSignature = () => {
|
|
@@ -6083,7 +6342,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6083
6342
|
}
|
|
6084
6343
|
return "_";
|
|
6085
6344
|
}).join(", ");
|
|
6086
|
-
const fnSignature = `function*${typeParamNames}(${paramNames}) { ... }`;
|
|
6345
|
+
const fnSignature = ts.isArrowFunction(innerFunction) ? `${typeParamNames}(${paramNames}) => { ... }` : isGeneratorFunction(innerFunction) ? `function*${typeParamNames}(${paramNames}) { ... }` : `function${typeParamNames}(${paramNames}) { ... }`;
|
|
6087
6346
|
const pipeArgsForWithSpan = pipeArguments2.slice(0, -1);
|
|
6088
6347
|
const pipeArgsSuffix = (args3) => args3.length > 0 ? ", ...pipeTransformations" : "";
|
|
6089
6348
|
switch (firstFix.fixName) {
|
|
@@ -6097,6 +6356,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6097
6356
|
return `${effectModuleName}.fn(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6098
6357
|
case "effectFnOpportunity_toEffectFnSpanInferred":
|
|
6099
6358
|
return `${effectModuleName}.fn("${inferredTraceName}")(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6359
|
+
case "effectFnOpportunity_toEffectFnSpanSuggested":
|
|
6360
|
+
return `${effectModuleName}.fn("${suggestedTraceName}")(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6100
6361
|
default:
|
|
6101
6362
|
return `${effectModuleName}.fn(${fnSignature})`;
|
|
6102
6363
|
}
|
|
@@ -6117,6 +6378,8 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6117
6378
|
code: 23,
|
|
6118
6379
|
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
6119
6380
|
severity: "warning",
|
|
6381
|
+
fixable: false,
|
|
6382
|
+
supportedEffect: ["v3", "v4"],
|
|
6120
6383
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
6121
6384
|
const ts = yield* service(TypeScriptApi);
|
|
6122
6385
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6149,12 +6412,80 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6149
6412
|
})
|
|
6150
6413
|
});
|
|
6151
6414
|
|
|
6415
|
+
// src/diagnostics/effectInFailure.ts
|
|
6416
|
+
var effectInFailure = createDiagnostic({
|
|
6417
|
+
name: "effectInFailure",
|
|
6418
|
+
code: 49,
|
|
6419
|
+
description: "Warns when an Effect is used inside an Effect failure channel",
|
|
6420
|
+
severity: "warning",
|
|
6421
|
+
fixable: false,
|
|
6422
|
+
supportedEffect: ["v3", "v4"],
|
|
6423
|
+
apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
|
|
6424
|
+
const ts = yield* service(TypeScriptApi);
|
|
6425
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6426
|
+
const typeParser = yield* service(TypeParser);
|
|
6427
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6428
|
+
const isStrictEffectType = cachedBy(
|
|
6429
|
+
fn("effectInFailure.isStrictEffectType")(function* (type, atLocation) {
|
|
6430
|
+
yield* typeParser.strictEffectType(type, atLocation);
|
|
6431
|
+
return true;
|
|
6432
|
+
}),
|
|
6433
|
+
"effectInFailure.isStrictEffectType",
|
|
6434
|
+
(type) => type
|
|
6435
|
+
);
|
|
6436
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
6437
|
+
const stack = [sourceFile];
|
|
6438
|
+
const shouldSkipBecauseChildMatched = /* @__PURE__ */ new WeakSet();
|
|
6439
|
+
while (stack.length > 0) {
|
|
6440
|
+
const node = stack.pop();
|
|
6441
|
+
if (!visited.has(node)) {
|
|
6442
|
+
visited.add(node);
|
|
6443
|
+
stack.push(node);
|
|
6444
|
+
ts.forEachChild(node, (child) => {
|
|
6445
|
+
stack.push(child);
|
|
6446
|
+
return void 0;
|
|
6447
|
+
});
|
|
6448
|
+
continue;
|
|
6449
|
+
}
|
|
6450
|
+
if (shouldSkipBecauseChildMatched.has(node)) {
|
|
6451
|
+
if (node.parent) shouldSkipBecauseChildMatched.add(node.parent);
|
|
6452
|
+
continue;
|
|
6453
|
+
}
|
|
6454
|
+
const type = typeCheckerUtils.getTypeAtLocation(node);
|
|
6455
|
+
if (!type) continue;
|
|
6456
|
+
const effect = yield* orUndefined(typeParser.strictEffectType(type, node));
|
|
6457
|
+
if (!effect) continue;
|
|
6458
|
+
const failureMembers = typeCheckerUtils.unrollUnionMembers(effect.E);
|
|
6459
|
+
let memberWithEffect = void 0;
|
|
6460
|
+
for (const member of failureMembers) {
|
|
6461
|
+
const isMemberEffect = yield* orUndefined(isStrictEffectType(member, node));
|
|
6462
|
+
if (isMemberEffect) {
|
|
6463
|
+
memberWithEffect = member;
|
|
6464
|
+
break;
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
if (!memberWithEffect) continue;
|
|
6468
|
+
const messageText = `The error channel contains an Effect (${typeChecker.typeToString(memberWithEffect)}). Putting Effect computations in the failure channel is not intended; keep only failure types there.`;
|
|
6469
|
+
report({
|
|
6470
|
+
location: node,
|
|
6471
|
+
messageText,
|
|
6472
|
+
fixes: []
|
|
6473
|
+
});
|
|
6474
|
+
if (node.parent) {
|
|
6475
|
+
shouldSkipBecauseChildMatched.add(node.parent);
|
|
6476
|
+
}
|
|
6477
|
+
}
|
|
6478
|
+
})
|
|
6479
|
+
});
|
|
6480
|
+
|
|
6152
6481
|
// src/diagnostics/effectInVoidSuccess.ts
|
|
6153
6482
|
var effectInVoidSuccess = createDiagnostic({
|
|
6154
6483
|
name: "effectInVoidSuccess",
|
|
6155
6484
|
code: 14,
|
|
6156
6485
|
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
6157
6486
|
severity: "warning",
|
|
6487
|
+
fixable: false,
|
|
6488
|
+
supportedEffect: ["v3", "v4"],
|
|
6158
6489
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
6159
6490
|
const ts = yield* service(TypeScriptApi);
|
|
6160
6491
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6204,6 +6535,8 @@ var effectMapVoid = createDiagnostic({
|
|
|
6204
6535
|
code: 40,
|
|
6205
6536
|
description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
6206
6537
|
severity: "suggestion",
|
|
6538
|
+
fixable: true,
|
|
6539
|
+
supportedEffect: ["v3", "v4"],
|
|
6207
6540
|
apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
|
|
6208
6541
|
const ts = yield* service(TypeScriptApi);
|
|
6209
6542
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6268,6 +6601,8 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6268
6601
|
code: 47,
|
|
6269
6602
|
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
6270
6603
|
severity: "suggestion",
|
|
6604
|
+
fixable: true,
|
|
6605
|
+
supportedEffect: ["v3", "v4"],
|
|
6271
6606
|
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
6272
6607
|
const ts = yield* service(TypeScriptApi);
|
|
6273
6608
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6313,12 +6648,66 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6313
6648
|
})
|
|
6314
6649
|
});
|
|
6315
6650
|
|
|
6651
|
+
// src/diagnostics/extendsNativeError.ts
|
|
6652
|
+
var extendsNativeError = createDiagnostic({
|
|
6653
|
+
name: "extendsNativeError",
|
|
6654
|
+
code: 50,
|
|
6655
|
+
description: "Warns when a class directly extends the native Error class",
|
|
6656
|
+
severity: "off",
|
|
6657
|
+
fixable: false,
|
|
6658
|
+
supportedEffect: ["v3", "v4"],
|
|
6659
|
+
apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
|
|
6660
|
+
const ts = yield* service(TypeScriptApi);
|
|
6661
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6662
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
6663
|
+
if (!errorSymbol) return;
|
|
6664
|
+
const nodeToVisit = [];
|
|
6665
|
+
const appendNodeToVisit = (node) => {
|
|
6666
|
+
nodeToVisit.push(node);
|
|
6667
|
+
return void 0;
|
|
6668
|
+
};
|
|
6669
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
6670
|
+
while (nodeToVisit.length > 0) {
|
|
6671
|
+
const node = nodeToVisit.shift();
|
|
6672
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
6673
|
+
for (const clause of node.heritageClauses) {
|
|
6674
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
6675
|
+
const typeExpression = clause.types[0].expression;
|
|
6676
|
+
const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
|
|
6677
|
+
const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
|
|
6678
|
+
const isNativeError = resolvedSymbol === errorSymbol || (() => {
|
|
6679
|
+
if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
|
|
6680
|
+
const exprType = typeChecker.getTypeAtLocation(typeExpression);
|
|
6681
|
+
const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
|
|
6682
|
+
if (constructSignatures.length > 0) {
|
|
6683
|
+
const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
|
|
6684
|
+
return instanceType.symbol === errorSymbol;
|
|
6685
|
+
}
|
|
6686
|
+
return false;
|
|
6687
|
+
})();
|
|
6688
|
+
if (isNativeError) {
|
|
6689
|
+
report({
|
|
6690
|
+
location: node.name ?? typeExpression,
|
|
6691
|
+
messageText: "Avoid extending the native 'Error' class directly. Consider using a tagged error (e.g. Data.TaggedError) to maintain type safety in the Effect failure channel.",
|
|
6692
|
+
fixes: []
|
|
6693
|
+
});
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
6699
|
+
}
|
|
6700
|
+
})
|
|
6701
|
+
});
|
|
6702
|
+
|
|
6316
6703
|
// src/diagnostics/floatingEffect.ts
|
|
6317
6704
|
var floatingEffect = createDiagnostic({
|
|
6318
6705
|
name: "floatingEffect",
|
|
6319
6706
|
code: 3,
|
|
6320
6707
|
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
6321
6708
|
severity: "error",
|
|
6709
|
+
fixable: false,
|
|
6710
|
+
supportedEffect: ["v3", "v4"],
|
|
6322
6711
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
6323
6712
|
const ts = yield* service(TypeScriptApi);
|
|
6324
6713
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6370,6 +6759,8 @@ var genericEffectServices = createDiagnostic({
|
|
|
6370
6759
|
code: 10,
|
|
6371
6760
|
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
6372
6761
|
severity: "warning",
|
|
6762
|
+
fixable: false,
|
|
6763
|
+
supportedEffect: ["v3", "v4"],
|
|
6373
6764
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
6374
6765
|
const ts = yield* service(TypeScriptApi);
|
|
6375
6766
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6417,6 +6808,8 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
6417
6808
|
code: 36,
|
|
6418
6809
|
description: "Warns when catch callbacks return global Error type instead of typed errors",
|
|
6419
6810
|
severity: "warning",
|
|
6811
|
+
fixable: false,
|
|
6812
|
+
supportedEffect: ["v3", "v4"],
|
|
6420
6813
|
apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
|
|
6421
6814
|
const ts = yield* service(TypeScriptApi);
|
|
6422
6815
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6477,6 +6870,8 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
6477
6870
|
code: 35,
|
|
6478
6871
|
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
6479
6872
|
severity: "warning",
|
|
6873
|
+
fixable: false,
|
|
6874
|
+
supportedEffect: ["v3", "v4"],
|
|
6480
6875
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
6481
6876
|
const ts = yield* service(TypeScriptApi);
|
|
6482
6877
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6530,6 +6925,8 @@ var importFromBarrel = createDiagnostic({
|
|
|
6530
6925
|
code: 12,
|
|
6531
6926
|
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
6532
6927
|
severity: "off",
|
|
6928
|
+
fixable: true,
|
|
6929
|
+
supportedEffect: ["v3", "v4"],
|
|
6533
6930
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
6534
6931
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
6535
6932
|
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
@@ -6670,6 +7067,8 @@ var instanceOfSchema = createDiagnostic({
|
|
|
6670
7067
|
code: 45,
|
|
6671
7068
|
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
6672
7069
|
severity: "off",
|
|
7070
|
+
fixable: true,
|
|
7071
|
+
supportedEffect: ["v3", "v4"],
|
|
6673
7072
|
apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
6674
7073
|
const ts = yield* service(TypeScriptApi);
|
|
6675
7074
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6733,6 +7132,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
6733
7132
|
code: 37,
|
|
6734
7133
|
description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
6735
7134
|
severity: "warning",
|
|
7135
|
+
fixable: true,
|
|
7136
|
+
supportedEffect: ["v3", "v4"],
|
|
6736
7137
|
apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
|
|
6737
7138
|
const ts = yield* service(TypeScriptApi);
|
|
6738
7139
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6846,6 +7247,8 @@ var leakingRequirements = createDiagnostic({
|
|
|
6846
7247
|
code: 8,
|
|
6847
7248
|
description: "Detects implementation services leaked in service methods",
|
|
6848
7249
|
severity: "suggestion",
|
|
7250
|
+
fixable: false,
|
|
7251
|
+
supportedEffect: ["v3", "v4"],
|
|
6849
7252
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
6850
7253
|
const ts = yield* service(TypeScriptApi);
|
|
6851
7254
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7000,6 +7403,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
7000
7403
|
code: 26,
|
|
7001
7404
|
description: "Enforces the use of pipeable style for nested function calls",
|
|
7002
7405
|
severity: "off",
|
|
7406
|
+
fixable: true,
|
|
7407
|
+
supportedEffect: ["v3", "v4"],
|
|
7003
7408
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
7004
7409
|
const ts = yield* service(TypeScriptApi);
|
|
7005
7410
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7180,6 +7585,8 @@ var missingEffectContext = createDiagnostic({
|
|
|
7180
7585
|
code: 1,
|
|
7181
7586
|
description: "Reports missing service requirements in Effect context channel",
|
|
7182
7587
|
severity: "error",
|
|
7588
|
+
fixable: false,
|
|
7589
|
+
supportedEffect: ["v3", "v4"],
|
|
7183
7590
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
7184
7591
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7185
7592
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7229,6 +7636,8 @@ var missingEffectError = createDiagnostic({
|
|
|
7229
7636
|
code: 1,
|
|
7230
7637
|
description: "Reports missing error types in Effect error channel",
|
|
7231
7638
|
severity: "error",
|
|
7639
|
+
fixable: true,
|
|
7640
|
+
supportedEffect: ["v3", "v4"],
|
|
7232
7641
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
7233
7642
|
const ts = yield* service(TypeScriptApi);
|
|
7234
7643
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7370,6 +7779,8 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
7370
7779
|
code: 22,
|
|
7371
7780
|
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
7372
7781
|
severity: "off",
|
|
7782
|
+
fixable: false,
|
|
7783
|
+
supportedEffect: ["v3"],
|
|
7373
7784
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
7374
7785
|
const ts = yield* service(TypeScriptApi);
|
|
7375
7786
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7464,6 +7875,8 @@ var missingLayerContext = createDiagnostic({
|
|
|
7464
7875
|
code: 38,
|
|
7465
7876
|
description: "Reports missing service requirements in Layer context channel",
|
|
7466
7877
|
severity: "error",
|
|
7878
|
+
fixable: false,
|
|
7879
|
+
supportedEffect: ["v3", "v4"],
|
|
7467
7880
|
apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
|
|
7468
7881
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7469
7882
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7513,10 +7926,13 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7513
7926
|
code: 7,
|
|
7514
7927
|
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
7515
7928
|
severity: "error",
|
|
7929
|
+
fixable: true,
|
|
7930
|
+
supportedEffect: ["v3", "v4"],
|
|
7516
7931
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
7517
7932
|
const ts = yield* service(TypeScriptApi);
|
|
7518
7933
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7519
7934
|
const typeParser = yield* service(TypeParser);
|
|
7935
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
7520
7936
|
const nodeToVisit = [];
|
|
7521
7937
|
const appendNodeToVisit = (node) => {
|
|
7522
7938
|
nodeToVisit.push(node);
|
|
@@ -7526,50 +7942,32 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7526
7942
|
while (nodeToVisit.length > 0) {
|
|
7527
7943
|
const node = nodeToVisit.shift();
|
|
7528
7944
|
ts.forEachChild(node, appendNodeToVisit);
|
|
7529
|
-
if (ts.
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
node,
|
|
7556
|
-
ts.factory.createReturnStatement(
|
|
7557
|
-
node
|
|
7558
|
-
)
|
|
7559
|
-
);
|
|
7560
|
-
})
|
|
7561
|
-
}] : [];
|
|
7562
|
-
report({
|
|
7563
|
-
location: node,
|
|
7564
|
-
messageText: `It is recommended to use return yield* for Effects that never succeed to signal a definitive exit point for type narrowing and tooling support.`,
|
|
7565
|
-
fixes: fix
|
|
7566
|
-
});
|
|
7567
|
-
}
|
|
7568
|
-
}
|
|
7569
|
-
}
|
|
7570
|
-
}
|
|
7571
|
-
}
|
|
7572
|
-
}
|
|
7945
|
+
if (!ts.isExpressionStatement(node)) continue;
|
|
7946
|
+
const unwrapped = tsUtils.skipOuterExpressions(node.expression);
|
|
7947
|
+
if (!ts.isYieldExpression(unwrapped) || !unwrapped.expression || !unwrapped.asteriskToken) continue;
|
|
7948
|
+
const type = typeCheckerUtils.getTypeAtLocation(unwrapped.expression);
|
|
7949
|
+
if (!type) continue;
|
|
7950
|
+
const maybeEffect = yield* option(typeParser.effectYieldableType(type, unwrapped.expression));
|
|
7951
|
+
if (!(isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never)) continue;
|
|
7952
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
7953
|
+
if (!effectGen || scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
7954
|
+
const fix = [{
|
|
7955
|
+
fixName: "missingReturnYieldStar_fix",
|
|
7956
|
+
description: "Add return statement",
|
|
7957
|
+
apply: gen(function* () {
|
|
7958
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
7959
|
+
changeTracker.replaceNode(
|
|
7960
|
+
sourceFile,
|
|
7961
|
+
node,
|
|
7962
|
+
ts.factory.createReturnStatement(node.expression)
|
|
7963
|
+
);
|
|
7964
|
+
})
|
|
7965
|
+
}];
|
|
7966
|
+
report({
|
|
7967
|
+
location: unwrapped,
|
|
7968
|
+
messageText: `It is recommended to use return yield* for Effects that never succeed to signal a definitive exit point for type narrowing and tooling support.`,
|
|
7969
|
+
fixes: fix
|
|
7970
|
+
});
|
|
7573
7971
|
}
|
|
7574
7972
|
})
|
|
7575
7973
|
});
|
|
@@ -7580,6 +7978,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
7580
7978
|
code: 4,
|
|
7581
7979
|
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
7582
7980
|
severity: "error",
|
|
7981
|
+
fixable: true,
|
|
7982
|
+
supportedEffect: ["v3", "v4"],
|
|
7583
7983
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
7584
7984
|
const ts = yield* service(TypeScriptApi);
|
|
7585
7985
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7655,6 +8055,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7655
8055
|
code: 18,
|
|
7656
8056
|
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
7657
8057
|
severity: "warning",
|
|
8058
|
+
fixable: true,
|
|
8059
|
+
supportedEffect: ["v3", "v4"],
|
|
7658
8060
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
7659
8061
|
const ts = yield* service(TypeScriptApi);
|
|
7660
8062
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7741,12 +8143,85 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7741
8143
|
})
|
|
7742
8144
|
});
|
|
7743
8145
|
|
|
8146
|
+
// src/diagnostics/nodeBuiltinImport.ts
|
|
8147
|
+
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
8148
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8149
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8150
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8151
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8152
|
+
["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8153
|
+
["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8154
|
+
["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8155
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8156
|
+
["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8157
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8158
|
+
["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
|
|
8159
|
+
["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
|
|
8160
|
+
]);
|
|
8161
|
+
var moduleAlternativesV4 = /* @__PURE__ */ new Map([
|
|
8162
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8163
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8164
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8165
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8166
|
+
["path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8167
|
+
["node:path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8168
|
+
["path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8169
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8170
|
+
["path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8171
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8172
|
+
["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
|
|
8173
|
+
["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
|
|
8174
|
+
]);
|
|
8175
|
+
var nodeBuiltinImport = createDiagnostic({
|
|
8176
|
+
name: "nodeBuiltinImport",
|
|
8177
|
+
code: 52,
|
|
8178
|
+
description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
8179
|
+
severity: "off",
|
|
8180
|
+
fixable: false,
|
|
8181
|
+
supportedEffect: ["v3", "v4"],
|
|
8182
|
+
apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
|
|
8183
|
+
const ts = yield* service(TypeScriptApi);
|
|
8184
|
+
const typeParser = yield* service(TypeParser);
|
|
8185
|
+
const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
|
|
8186
|
+
for (const statement of sourceFile.statements) {
|
|
8187
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
8188
|
+
const specifier = statement.moduleSpecifier.text;
|
|
8189
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8190
|
+
if (match2) {
|
|
8191
|
+
report({
|
|
8192
|
+
location: statement.moduleSpecifier,
|
|
8193
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8194
|
+
fixes: []
|
|
8195
|
+
});
|
|
8196
|
+
}
|
|
8197
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
8198
|
+
for (const decl of statement.declarationList.declarations) {
|
|
8199
|
+
if (decl.initializer && ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression) && ts.idText(decl.initializer.expression) === "require" && decl.initializer.arguments.length === 1 && ts.isStringLiteral(decl.initializer.arguments[0])) {
|
|
8200
|
+
const arg = decl.initializer.arguments[0];
|
|
8201
|
+
const specifier = arg.text;
|
|
8202
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8203
|
+
if (match2) {
|
|
8204
|
+
report({
|
|
8205
|
+
location: arg,
|
|
8206
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8207
|
+
fixes: []
|
|
8208
|
+
});
|
|
8209
|
+
}
|
|
8210
|
+
}
|
|
8211
|
+
}
|
|
8212
|
+
}
|
|
8213
|
+
}
|
|
8214
|
+
})
|
|
8215
|
+
});
|
|
8216
|
+
|
|
7744
8217
|
// src/diagnostics/nonObjectEffectServiceType.ts
|
|
7745
8218
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
7746
8219
|
name: "nonObjectEffectServiceType",
|
|
7747
8220
|
code: 24,
|
|
7748
8221
|
description: "Ensures Effect.Service types are objects, not primitives",
|
|
7749
8222
|
severity: "error",
|
|
8223
|
+
fixable: false,
|
|
8224
|
+
supportedEffect: ["v3"],
|
|
7750
8225
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
7751
8226
|
const ts = yield* service(TypeScriptApi);
|
|
7752
8227
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7886,9 +8361,7 @@ var effectModuleMigrationDb = {
|
|
|
7886
8361
|
"failSync": asUnchanged,
|
|
7887
8362
|
"fiberId": asUnchanged,
|
|
7888
8363
|
"filter": asUnchanged,
|
|
7889
|
-
"filterMap":
|
|
7890
|
-
"Use Effect.filter or Effect.map with Option instead."
|
|
7891
|
-
),
|
|
8364
|
+
"filterMap": asUnchanged,
|
|
7892
8365
|
"filterOrElse": asUnchanged,
|
|
7893
8366
|
"filterOrFail": asUnchanged,
|
|
7894
8367
|
"flatMap": asUnchanged,
|
|
@@ -8176,9 +8649,7 @@ var effectModuleMigrationDb = {
|
|
|
8176
8649
|
"finalizersMask": asRemoved(
|
|
8177
8650
|
"Finalizer masking has been removed in Effect v4."
|
|
8178
8651
|
),
|
|
8179
|
-
"findFirst":
|
|
8180
|
-
"Use Effect.forEach with early return instead."
|
|
8181
|
-
),
|
|
8652
|
+
"findFirst": asUnchanged,
|
|
8182
8653
|
"firstSuccessOf": asRemoved(
|
|
8183
8654
|
"Use Effect.raceAll instead."
|
|
8184
8655
|
),
|
|
@@ -8533,6 +9004,8 @@ var outdatedApi = createDiagnostic({
|
|
|
8533
9004
|
code: 48,
|
|
8534
9005
|
description: "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
8535
9006
|
severity: "warning",
|
|
9007
|
+
fixable: false,
|
|
9008
|
+
supportedEffect: ["v4"],
|
|
8536
9009
|
apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
|
|
8537
9010
|
const typeParser = yield* service(TypeParser);
|
|
8538
9011
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -9669,6 +10142,8 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
9669
10142
|
code: 19,
|
|
9670
10143
|
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
9671
10144
|
severity: "warning",
|
|
10145
|
+
fixable: true,
|
|
10146
|
+
supportedEffect: ["v3", "v4"],
|
|
9672
10147
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
9673
10148
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
9674
10149
|
for (const { codegen, hash: hash2, range } of codegensWithRanges) {
|
|
@@ -9715,6 +10190,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
9715
10190
|
code: 30,
|
|
9716
10191
|
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
9717
10192
|
severity: "error",
|
|
10193
|
+
fixable: true,
|
|
10194
|
+
supportedEffect: ["v3", "v4"],
|
|
9718
10195
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
9719
10196
|
const ts = yield* service(TypeScriptApi);
|
|
9720
10197
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9852,6 +10329,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
9852
10329
|
code: 44,
|
|
9853
10330
|
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
9854
10331
|
severity: "suggestion",
|
|
10332
|
+
fixable: false,
|
|
10333
|
+
supportedEffect: ["v3", "v4"],
|
|
9855
10334
|
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
9856
10335
|
const ts = yield* service(TypeScriptApi);
|
|
9857
10336
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9962,6 +10441,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
|
|
|
9962
10441
|
code: 42,
|
|
9963
10442
|
description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
9964
10443
|
severity: "suggestion",
|
|
10444
|
+
fixable: true,
|
|
10445
|
+
supportedEffect: ["v3", "v4"],
|
|
9965
10446
|
apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
|
|
9966
10447
|
const ts = yield* service(TypeScriptApi);
|
|
9967
10448
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10012,6 +10493,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
10012
10493
|
code: 11,
|
|
10013
10494
|
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
10014
10495
|
severity: "suggestion",
|
|
10496
|
+
fixable: true,
|
|
10497
|
+
supportedEffect: ["v3", "v4"],
|
|
10015
10498
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
10016
10499
|
const ts = yield* service(TypeScriptApi);
|
|
10017
10500
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10081,6 +10564,8 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10081
10564
|
code: 32,
|
|
10082
10565
|
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
10083
10566
|
severity: "suggestion",
|
|
10567
|
+
fixable: true,
|
|
10568
|
+
supportedEffect: ["v3"],
|
|
10084
10569
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10085
10570
|
const ts = yield* service(TypeScriptApi);
|
|
10086
10571
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10205,6 +10690,8 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
10205
10690
|
code: 34,
|
|
10206
10691
|
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
10207
10692
|
severity: "suggestion",
|
|
10693
|
+
fixable: true,
|
|
10694
|
+
supportedEffect: ["v3", "v4"],
|
|
10208
10695
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
10209
10696
|
const ts = yield* service(TypeScriptApi);
|
|
10210
10697
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10297,6 +10784,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
10297
10784
|
code: 43,
|
|
10298
10785
|
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
10299
10786
|
severity: "suggestion",
|
|
10787
|
+
fixable: false,
|
|
10788
|
+
supportedEffect: ["v3", "v4"],
|
|
10300
10789
|
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
10301
10790
|
const ts = yield* service(TypeScriptApi);
|
|
10302
10791
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10346,6 +10835,8 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
10346
10835
|
code: 33,
|
|
10347
10836
|
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
10348
10837
|
severity: "off",
|
|
10838
|
+
fixable: true,
|
|
10839
|
+
supportedEffect: ["v3"],
|
|
10349
10840
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
10350
10841
|
const ts = yield* service(TypeScriptApi);
|
|
10351
10842
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10421,6 +10912,8 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
10421
10912
|
code: 13,
|
|
10422
10913
|
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
10423
10914
|
severity: "warning",
|
|
10915
|
+
fixable: true,
|
|
10916
|
+
supportedEffect: ["v3"],
|
|
10424
10917
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
10425
10918
|
const ts = yield* service(TypeScriptApi);
|
|
10426
10919
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -10510,12 +11003,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
10510
11003
|
})
|
|
10511
11004
|
});
|
|
10512
11005
|
|
|
11006
|
+
// src/diagnostics/serviceNotAsClass.ts
|
|
11007
|
+
var serviceNotAsClass = createDiagnostic({
|
|
11008
|
+
name: "serviceNotAsClass",
|
|
11009
|
+
code: 51,
|
|
11010
|
+
description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
11011
|
+
severity: "off",
|
|
11012
|
+
fixable: true,
|
|
11013
|
+
supportedEffect: ["v4"],
|
|
11014
|
+
apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
|
|
11015
|
+
const ts = yield* service(TypeScriptApi);
|
|
11016
|
+
const typeParser = yield* service(TypeParser);
|
|
11017
|
+
if (typeParser.supportedEffect() === "v3") return;
|
|
11018
|
+
const nodeToVisit = [];
|
|
11019
|
+
const appendNodeToVisit = (node) => {
|
|
11020
|
+
nodeToVisit.push(node);
|
|
11021
|
+
return void 0;
|
|
11022
|
+
};
|
|
11023
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
11024
|
+
while (nodeToVisit.length > 0) {
|
|
11025
|
+
const node = nodeToVisit.shift();
|
|
11026
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
11027
|
+
if (!ts.isVariableDeclaration(node)) continue;
|
|
11028
|
+
if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
|
|
11029
|
+
const callExpr = node.initializer;
|
|
11030
|
+
if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
|
|
11031
|
+
const typeArgs = callExpr.typeArguments;
|
|
11032
|
+
const declList = node.parent;
|
|
11033
|
+
if (!ts.isVariableDeclarationList(declList)) continue;
|
|
11034
|
+
if (!(declList.flags & ts.NodeFlags.Const)) continue;
|
|
11035
|
+
const isServiceMapService = yield* pipe(
|
|
11036
|
+
typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
|
|
11037
|
+
orUndefined
|
|
11038
|
+
);
|
|
11039
|
+
if (!isServiceMapService) continue;
|
|
11040
|
+
const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
|
|
11041
|
+
const variableStatement = declList.parent;
|
|
11042
|
+
const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
|
|
11043
|
+
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11044
|
+
report({
|
|
11045
|
+
location: callExpr,
|
|
11046
|
+
messageText: `ServiceMap.Service should be used in a class declaration instead of as a variable. Use: class ${variableName} extends ServiceMap.Service<${variableName}, ${shapeText}>()("${argsText.replace(/['"]/g, "")}") {}`,
|
|
11047
|
+
fixes: [{
|
|
11048
|
+
fixName: "serviceNotAsClass",
|
|
11049
|
+
description: `Convert to class declaration`,
|
|
11050
|
+
apply: gen(function* () {
|
|
11051
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
11052
|
+
const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
|
|
11053
|
+
const innerCall = ts.factory.createCallExpression(
|
|
11054
|
+
callExpr.expression,
|
|
11055
|
+
[ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
|
|
11056
|
+
[]
|
|
11057
|
+
);
|
|
11058
|
+
const outerCall = ts.factory.createCallExpression(
|
|
11059
|
+
innerCall,
|
|
11060
|
+
void 0,
|
|
11061
|
+
[...callExpr.arguments]
|
|
11062
|
+
);
|
|
11063
|
+
const heritageClause = ts.factory.createHeritageClause(
|
|
11064
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
11065
|
+
[ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
|
|
11066
|
+
);
|
|
11067
|
+
const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
|
|
11068
|
+
const classDeclaration = ts.factory.createClassDeclaration(
|
|
11069
|
+
modifiers,
|
|
11070
|
+
ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
|
|
11071
|
+
void 0,
|
|
11072
|
+
[heritageClause],
|
|
11073
|
+
[]
|
|
11074
|
+
);
|
|
11075
|
+
changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
|
|
11076
|
+
})
|
|
11077
|
+
}]
|
|
11078
|
+
});
|
|
11079
|
+
}
|
|
11080
|
+
})
|
|
11081
|
+
});
|
|
11082
|
+
|
|
10513
11083
|
// src/diagnostics/strictBooleanExpressions.ts
|
|
10514
11084
|
var strictBooleanExpressions = createDiagnostic({
|
|
10515
11085
|
name: "strictBooleanExpressions",
|
|
10516
11086
|
code: 17,
|
|
10517
11087
|
description: "Enforces boolean types in conditional expressions for type safety",
|
|
10518
11088
|
severity: "off",
|
|
11089
|
+
fixable: false,
|
|
11090
|
+
supportedEffect: ["v3", "v4"],
|
|
10519
11091
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
10520
11092
|
const ts = yield* service(TypeScriptApi);
|
|
10521
11093
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -10587,6 +11159,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
10587
11159
|
code: 27,
|
|
10588
11160
|
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
10589
11161
|
severity: "off",
|
|
11162
|
+
fixable: false,
|
|
11163
|
+
supportedEffect: ["v3", "v4"],
|
|
10590
11164
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
10591
11165
|
const ts = yield* service(TypeScriptApi);
|
|
10592
11166
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10638,6 +11212,8 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
10638
11212
|
code: 15,
|
|
10639
11213
|
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
10640
11214
|
severity: "suggestion",
|
|
11215
|
+
fixable: false,
|
|
11216
|
+
supportedEffect: ["v3", "v4"],
|
|
10641
11217
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
10642
11218
|
const ts = yield* service(TypeScriptApi);
|
|
10643
11219
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10695,6 +11271,8 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
10695
11271
|
code: 31,
|
|
10696
11272
|
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
10697
11273
|
severity: "warning",
|
|
11274
|
+
fixable: false,
|
|
11275
|
+
supportedEffect: ["v3", "v4"],
|
|
10698
11276
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
10699
11277
|
const ts = yield* service(TypeScriptApi);
|
|
10700
11278
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10756,6 +11334,8 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
10756
11334
|
code: 5,
|
|
10757
11335
|
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
10758
11336
|
severity: "suggestion",
|
|
11337
|
+
fixable: true,
|
|
11338
|
+
supportedEffect: ["v3", "v4"],
|
|
10759
11339
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
10760
11340
|
const ts = yield* service(TypeScriptApi);
|
|
10761
11341
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10800,6 +11380,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
10800
11380
|
code: 29,
|
|
10801
11381
|
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
10802
11382
|
severity: "suggestion",
|
|
11383
|
+
fixable: true,
|
|
11384
|
+
supportedEffect: ["v3", "v4"],
|
|
10803
11385
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
10804
11386
|
const ts = yield* service(TypeScriptApi);
|
|
10805
11387
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10859,6 +11441,8 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
10859
11441
|
code: 9,
|
|
10860
11442
|
description: "Removes pipe calls with no arguments",
|
|
10861
11443
|
severity: "suggestion",
|
|
11444
|
+
fixable: true,
|
|
11445
|
+
supportedEffect: ["v3", "v4"],
|
|
10862
11446
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
10863
11447
|
const ts = yield* service(TypeScriptApi);
|
|
10864
11448
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10905,6 +11489,8 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
10905
11489
|
code: 16,
|
|
10906
11490
|
description: "Simplifies chained pipe calls into a single pipe call",
|
|
10907
11491
|
severity: "suggestion",
|
|
11492
|
+
fixable: true,
|
|
11493
|
+
supportedEffect: ["v3", "v4"],
|
|
10908
11494
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
10909
11495
|
const ts = yield* service(TypeScriptApi);
|
|
10910
11496
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10980,6 +11566,8 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
10980
11566
|
code: 21,
|
|
10981
11567
|
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
10982
11568
|
severity: "warning",
|
|
11569
|
+
fixable: true,
|
|
11570
|
+
supportedEffect: ["v3", "v4"],
|
|
10983
11571
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
10984
11572
|
const ts = yield* service(TypeScriptApi);
|
|
10985
11573
|
const nodeToVisit = [];
|
|
@@ -11046,6 +11634,7 @@ var diagnostics = [
|
|
|
11046
11634
|
missingEffectServiceDependency,
|
|
11047
11635
|
missingLayerContext,
|
|
11048
11636
|
floatingEffect,
|
|
11637
|
+
effectInFailure,
|
|
11049
11638
|
missingStarInYieldEffectGen,
|
|
11050
11639
|
unnecessaryEffectGen,
|
|
11051
11640
|
unnecessaryFailYieldableError,
|
|
@@ -11081,7 +11670,10 @@ var diagnostics = [
|
|
|
11081
11670
|
effectFnOpportunity,
|
|
11082
11671
|
redundantSchemaTagIdentifier,
|
|
11083
11672
|
schemaSyncInEffect,
|
|
11084
|
-
preferSchemaOverJson
|
|
11673
|
+
preferSchemaOverJson,
|
|
11674
|
+
extendsNativeError,
|
|
11675
|
+
serviceNotAsClass,
|
|
11676
|
+
nodeBuiltinImport
|
|
11085
11677
|
];
|
|
11086
11678
|
|
|
11087
11679
|
// src/effect-lsp-patch-utils.ts
|
|
@@ -11162,6 +11754,12 @@ function extractDiagnosticsForExitStatus(tsInstance, program, diagnostics2, _mod
|
|
|
11162
11754
|
(_) => !(_.source === "effect" && _.category === tsInstance.DiagnosticCategory.Warning)
|
|
11163
11755
|
);
|
|
11164
11756
|
}
|
|
11757
|
+
if (parsedOptions.ignoreEffectErrorsInTscExitCode) {
|
|
11758
|
+
newDiagnostics = filter(
|
|
11759
|
+
newDiagnostics,
|
|
11760
|
+
(_) => !(_.source === "effect" && _.category === tsInstance.DiagnosticCategory.Error)
|
|
11761
|
+
);
|
|
11762
|
+
}
|
|
11165
11763
|
return newDiagnostics;
|
|
11166
11764
|
}
|
|
11167
11765
|
// Annotate the CommonJS export names for ESM import in node:
|