@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
package/transform.js
CHANGED
|
@@ -24,7 +24,7 @@ __export(transform_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(transform_exports);
|
|
26
26
|
|
|
27
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
27
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Pipeable.js
|
|
28
28
|
var pipeArguments = (self, args3) => {
|
|
29
29
|
switch (args3.length) {
|
|
30
30
|
case 0:
|
|
@@ -57,7 +57,7 @@ var pipeArguments = (self, args3) => {
|
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
60
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Function.js
|
|
61
61
|
var dual = function(arity, body) {
|
|
62
62
|
if (typeof arity === "function") {
|
|
63
63
|
return function() {
|
|
@@ -105,7 +105,7 @@ function pipe(a, ...args3) {
|
|
|
105
105
|
return pipeArguments(a, args3);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
108
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/equal.js
|
|
109
109
|
var getAllObjectKeys = (obj) => {
|
|
110
110
|
const keys2 = new Set(Reflect.ownKeys(obj));
|
|
111
111
|
if (obj.constructor === Object) return keys2;
|
|
@@ -128,7 +128,7 @@ var getAllObjectKeys = (obj) => {
|
|
|
128
128
|
};
|
|
129
129
|
var byReferenceInstances = /* @__PURE__ */ new WeakSet();
|
|
130
130
|
|
|
131
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
131
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Predicate.js
|
|
132
132
|
function isString(input) {
|
|
133
133
|
return typeof input === "string";
|
|
134
134
|
}
|
|
@@ -149,7 +149,7 @@ function isObjectKeyword(input) {
|
|
|
149
149
|
}
|
|
150
150
|
var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObjectKeyword(self) && property in self);
|
|
151
151
|
|
|
152
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
152
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Hash.js
|
|
153
153
|
var symbol = "~effect/interfaces/Hash";
|
|
154
154
|
var hash = (self) => {
|
|
155
155
|
switch (typeof self) {
|
|
@@ -268,7 +268,7 @@ function withVisitedTracking(obj, fn2) {
|
|
|
268
268
|
return result;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
271
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Equal.js
|
|
272
272
|
var symbol2 = "~effect/interfaces/Equal";
|
|
273
273
|
function equals() {
|
|
274
274
|
if (arguments.length === 1) {
|
|
@@ -430,7 +430,10 @@ var compareSets = /* @__PURE__ */ makeCompareSet(compareBoth);
|
|
|
430
430
|
var isEqual = (u) => hasProperty(u, symbol2);
|
|
431
431
|
var asEquivalence = () => equals;
|
|
432
432
|
|
|
433
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
433
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/array.js
|
|
434
|
+
var isArrayNonEmpty = (self) => self.length > 0;
|
|
435
|
+
|
|
436
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Redactable.js
|
|
434
437
|
var symbolRedactable = /* @__PURE__ */ Symbol.for("~effect/Inspectable/redactable");
|
|
435
438
|
var isRedactable = (u) => hasProperty(u, symbolRedactable);
|
|
436
439
|
function redact(u) {
|
|
@@ -449,7 +452,7 @@ var emptyServiceMap = {
|
|
|
449
452
|
}
|
|
450
453
|
};
|
|
451
454
|
|
|
452
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
455
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Formatter.js
|
|
453
456
|
function format(input, options) {
|
|
454
457
|
const space = options?.space ?? 0;
|
|
455
458
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -528,7 +531,7 @@ function safeToString(input) {
|
|
|
528
531
|
}
|
|
529
532
|
}
|
|
530
533
|
|
|
531
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
534
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Inspectable.js
|
|
532
535
|
var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
533
536
|
var toJson = (input) => {
|
|
534
537
|
try {
|
|
@@ -572,7 +575,7 @@ var Class = class {
|
|
|
572
575
|
}
|
|
573
576
|
};
|
|
574
577
|
|
|
575
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
578
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Utils.js
|
|
576
579
|
var GenKindTypeId = "~effect/Utils/GenKind";
|
|
577
580
|
var GenKindImpl = class {
|
|
578
581
|
value;
|
|
@@ -640,7 +643,7 @@ var internalCall = isNotOptimizedAway ? standard[InternalTypeId] : forced[Intern
|
|
|
640
643
|
var genConstructor = function* () {
|
|
641
644
|
}.constructor;
|
|
642
645
|
|
|
643
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
646
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/core.js
|
|
644
647
|
var EffectTypeId = `~effect/Effect`;
|
|
645
648
|
var ExitTypeId = `~effect/Exit`;
|
|
646
649
|
var effectVariance = {
|
|
@@ -987,7 +990,7 @@ var DoneVoid = {
|
|
|
987
990
|
value: void 0
|
|
988
991
|
};
|
|
989
992
|
|
|
990
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
993
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/option.js
|
|
991
994
|
var TypeId = "~effect/data/Option";
|
|
992
995
|
var CommonProto = {
|
|
993
996
|
[TypeId]: {
|
|
@@ -1052,7 +1055,7 @@ var some = (value) => {
|
|
|
1052
1055
|
return a;
|
|
1053
1056
|
};
|
|
1054
1057
|
|
|
1055
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1058
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/internal/result.js
|
|
1056
1059
|
var TypeId2 = "~effect/data/Result";
|
|
1057
1060
|
var CommonProto2 = {
|
|
1058
1061
|
[TypeId2]: {
|
|
@@ -1123,13 +1126,13 @@ var succeed = (success) => {
|
|
|
1123
1126
|
return a;
|
|
1124
1127
|
};
|
|
1125
1128
|
|
|
1126
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1129
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Order.js
|
|
1127
1130
|
function make(compare) {
|
|
1128
1131
|
return (self, that) => self === that ? 0 : compare(self, that);
|
|
1129
1132
|
}
|
|
1130
1133
|
var String2 = /* @__PURE__ */ make((self, that) => self < that ? -1 : 1);
|
|
1131
1134
|
|
|
1132
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1135
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Option.js
|
|
1133
1136
|
var none2 = () => none;
|
|
1134
1137
|
var some2 = some;
|
|
1135
1138
|
var isNone2 = isNone;
|
|
@@ -1139,7 +1142,7 @@ var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : se
|
|
|
1139
1142
|
var fromNullishOr = (a) => a == null ? none2() : some2(a);
|
|
1140
1143
|
var getOrUndefined = /* @__PURE__ */ getOrElse(constUndefined);
|
|
1141
1144
|
|
|
1142
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1145
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Result.js
|
|
1143
1146
|
var succeed2 = succeed;
|
|
1144
1147
|
var fail2 = fail;
|
|
1145
1148
|
var isFailure2 = isFailure;
|
|
@@ -1147,18 +1150,7 @@ var isSuccess2 = isSuccess;
|
|
|
1147
1150
|
var map = /* @__PURE__ */ dual(2, (self, f) => isSuccess2(self) ? succeed2(f(self.success)) : fail2(self.failure));
|
|
1148
1151
|
var getOrElse2 = /* @__PURE__ */ dual(2, (self, onFailure) => isFailure2(self) ? onFailure(self.failure) : self.success);
|
|
1149
1152
|
|
|
1150
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1151
|
-
var apply = (filter2, input, ...args3) => {
|
|
1152
|
-
const result = filter2(input, ...args3);
|
|
1153
|
-
if (result === true) return succeed2(input);
|
|
1154
|
-
if (result === false) return fail2(input);
|
|
1155
|
-
return result;
|
|
1156
|
-
};
|
|
1157
|
-
|
|
1158
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.14/node_modules/effect/dist/internal/array.js
|
|
1159
|
-
var isArrayNonEmpty = (self) => self.length > 0;
|
|
1160
|
-
|
|
1161
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.14/node_modules/effect/dist/Record.js
|
|
1153
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Record.js
|
|
1162
1154
|
var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
1163
1155
|
const out = {
|
|
1164
1156
|
...self
|
|
@@ -1170,7 +1162,7 @@ var map2 = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1170
1162
|
});
|
|
1171
1163
|
var keys = (self) => Object.keys(self);
|
|
1172
1164
|
|
|
1173
|
-
// ../../node_modules/.pnpm/effect@4.0.0-beta.
|
|
1165
|
+
// ../../node_modules/.pnpm/effect@4.0.0-beta.27/node_modules/effect/dist/Array.js
|
|
1174
1166
|
var Array2 = globalThis.Array;
|
|
1175
1167
|
var fromIterable = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
|
|
1176
1168
|
var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
|
|
@@ -1233,13 +1225,12 @@ var flatMap = /* @__PURE__ */ dual(2, (self, f) => {
|
|
|
1233
1225
|
return out;
|
|
1234
1226
|
});
|
|
1235
1227
|
var flatten = /* @__PURE__ */ flatMap(identity);
|
|
1236
|
-
var filter = /* @__PURE__ */ dual(2, (self,
|
|
1228
|
+
var filter = /* @__PURE__ */ dual(2, (self, predicate) => {
|
|
1237
1229
|
const as = fromIterable(self);
|
|
1238
1230
|
const out = [];
|
|
1239
1231
|
for (let i = 0; i < as.length; i++) {
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
out.push(result.success);
|
|
1232
|
+
if (predicate(as[i], i)) {
|
|
1233
|
+
out.push(as[i]);
|
|
1243
1234
|
}
|
|
1244
1235
|
}
|
|
1245
1236
|
return out;
|
|
@@ -1647,10 +1638,12 @@ var defaults = {
|
|
|
1647
1638
|
extendedKeyDetection: false,
|
|
1648
1639
|
ignoreEffectWarningsInTscExitCode: false,
|
|
1649
1640
|
ignoreEffectSuggestionsInTscExitCode: true,
|
|
1641
|
+
ignoreEffectErrorsInTscExitCode: false,
|
|
1650
1642
|
pipeableMinArgCount: 2,
|
|
1651
1643
|
effectFn: ["span"],
|
|
1652
1644
|
layerGraphFollowDepth: 0,
|
|
1653
|
-
mermaidProvider: "mermaid.live"
|
|
1645
|
+
mermaidProvider: "mermaid.live",
|
|
1646
|
+
skipDisabledOptimization: false
|
|
1654
1647
|
};
|
|
1655
1648
|
function parseKeyPatterns(patterns) {
|
|
1656
1649
|
const result = [];
|
|
@@ -1674,6 +1667,7 @@ function parse(config) {
|
|
|
1674
1667
|
includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
|
|
1675
1668
|
ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
|
|
1676
1669
|
ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
|
|
1670
|
+
ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
|
|
1677
1671
|
quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
|
|
1678
1672
|
quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
|
|
1679
1673
|
quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
|
|
@@ -1690,9 +1684,12 @@ function parse(config) {
|
|
|
1690
1684
|
keyPatterns: isObject(config) && hasProperty(config, "keyPatterns") && isArray(config.keyPatterns) ? parseKeyPatterns(config.keyPatterns) : defaults.keyPatterns,
|
|
1691
1685
|
extendedKeyDetection: isObject(config) && hasProperty(config, "extendedKeyDetection") && isBoolean(config.extendedKeyDetection) ? config.extendedKeyDetection : defaults.extendedKeyDetection,
|
|
1692
1686
|
pipeableMinArgCount: isObject(config) && hasProperty(config, "pipeableMinArgCount") && isNumber(config.pipeableMinArgCount) ? config.pipeableMinArgCount : defaults.pipeableMinArgCount,
|
|
1693
|
-
effectFn: isObject(config) && hasProperty(config, "effectFn") && isArray(config.effectFn) && config.effectFn.every(isString) ? config.effectFn.map(
|
|
1687
|
+
effectFn: isObject(config) && hasProperty(config, "effectFn") && isArray(config.effectFn) && config.effectFn.every(isString) ? config.effectFn.map(
|
|
1688
|
+
(_) => _.toLowerCase()
|
|
1689
|
+
) : defaults.effectFn,
|
|
1694
1690
|
layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
|
|
1695
|
-
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
|
|
1691
|
+
mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
|
|
1692
|
+
skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
|
|
1696
1693
|
};
|
|
1697
1694
|
}
|
|
1698
1695
|
|
|
@@ -2462,7 +2459,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
|
|
|
2462
2459
|
if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
|
|
2463
2460
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2464
2461
|
}
|
|
2465
|
-
if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2462
|
+
if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
|
|
2466
2463
|
return { diagnostics: diagnostics2, codeFixes };
|
|
2467
2464
|
}
|
|
2468
2465
|
const fixByDisableNextLine = (node) => ({
|
|
@@ -3377,6 +3374,14 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3377
3374
|
const layerType = cachedBy(
|
|
3378
3375
|
fn("TypeParser.layerType")(function* (type, atLocation) {
|
|
3379
3376
|
yield* pipeableType(type, atLocation);
|
|
3377
|
+
if (supportedEffect() === "v4") {
|
|
3378
|
+
const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/Layer");
|
|
3379
|
+
if (typeIdSymbol) {
|
|
3380
|
+
const typeIdType = typeChecker.getTypeOfSymbolAtLocation(typeIdSymbol, atLocation);
|
|
3381
|
+
return yield* layerVarianceStruct(typeIdType, atLocation);
|
|
3382
|
+
}
|
|
3383
|
+
return yield* typeParserIssue("Type is not a layer", type, atLocation);
|
|
3384
|
+
}
|
|
3380
3385
|
const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
|
|
3381
3386
|
(_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
|
|
3382
3387
|
);
|
|
@@ -3426,6 +3431,34 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
3426
3431
|
"TypeParser.effectSubtype",
|
|
3427
3432
|
(type) => type
|
|
3428
3433
|
);
|
|
3434
|
+
const effectYieldableType = cachedBy(
|
|
3435
|
+
fn("TypeParser.effectYieldableType")(function* (type, atLocation) {
|
|
3436
|
+
if (supportedEffect() === "v3") {
|
|
3437
|
+
return yield* effectType(type, atLocation);
|
|
3438
|
+
}
|
|
3439
|
+
return yield* firstSuccessOf([
|
|
3440
|
+
effectType(type, atLocation),
|
|
3441
|
+
gen(function* () {
|
|
3442
|
+
const asEffectSymbol = typeChecker.getPropertyOfType(type, "asEffect");
|
|
3443
|
+
if (!asEffectSymbol) {
|
|
3444
|
+
return yield* typeParserIssue("Type has no 'asEffect' property", type, atLocation);
|
|
3445
|
+
}
|
|
3446
|
+
const asEffectType = typeChecker.getTypeOfSymbolAtLocation(asEffectSymbol, atLocation);
|
|
3447
|
+
const asEffectSignatures = typeChecker.getSignaturesOfType(asEffectType, ts.SignatureKind.Call);
|
|
3448
|
+
if (asEffectSignatures.length === 0) {
|
|
3449
|
+
return yield* typeParserIssue("'asEffect' property is not callable", type, atLocation);
|
|
3450
|
+
}
|
|
3451
|
+
return yield* firstSuccessOf(
|
|
3452
|
+
asEffectSignatures.map(
|
|
3453
|
+
(signature) => effectType(typeChecker.getReturnTypeOfSignature(signature), atLocation)
|
|
3454
|
+
)
|
|
3455
|
+
);
|
|
3456
|
+
})
|
|
3457
|
+
]);
|
|
3458
|
+
}),
|
|
3459
|
+
"TypeParser.effectYieldableType",
|
|
3460
|
+
(type) => type
|
|
3461
|
+
);
|
|
3429
3462
|
const isEffectContextSourceFile = cachedBy(
|
|
3430
3463
|
fn("TypeParser.isEffectContextSourceFile")(function* (sourceFile) {
|
|
3431
3464
|
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
|
@@ -5053,6 +5086,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
|
|
|
5053
5086
|
layerType,
|
|
5054
5087
|
fiberType,
|
|
5055
5088
|
effectSubtype,
|
|
5089
|
+
effectYieldableType,
|
|
5056
5090
|
importedEffectModule,
|
|
5057
5091
|
effectGen,
|
|
5058
5092
|
effectFnUntracedGen,
|
|
@@ -5097,6 +5131,8 @@ var anyUnknownInErrorContext = createDiagnostic({
|
|
|
5097
5131
|
code: 28,
|
|
5098
5132
|
description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
|
|
5099
5133
|
severity: "off",
|
|
5134
|
+
fixable: false,
|
|
5135
|
+
supportedEffect: ["v3", "v4"],
|
|
5100
5136
|
apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
|
|
5101
5137
|
const ts = yield* service(TypeScriptApi);
|
|
5102
5138
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5200,6 +5236,8 @@ var catchAllToMapError = createDiagnostic({
|
|
|
5200
5236
|
code: 39,
|
|
5201
5237
|
description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
|
|
5202
5238
|
severity: "suggestion",
|
|
5239
|
+
fixable: true,
|
|
5240
|
+
supportedEffect: ["v3", "v4"],
|
|
5203
5241
|
apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
|
|
5204
5242
|
const ts = yield* service(TypeScriptApi);
|
|
5205
5243
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5297,6 +5335,8 @@ var catchUnfailableEffect = createDiagnostic({
|
|
|
5297
5335
|
code: 2,
|
|
5298
5336
|
description: "Warns when using error handling on Effects that never fail (error type is 'never')",
|
|
5299
5337
|
severity: "suggestion",
|
|
5338
|
+
fixable: false,
|
|
5339
|
+
supportedEffect: ["v3", "v4"],
|
|
5300
5340
|
apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
|
|
5301
5341
|
const ts = yield* service(TypeScriptApi);
|
|
5302
5342
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5346,6 +5386,8 @@ var classSelfMismatch = createDiagnostic({
|
|
|
5346
5386
|
code: 20,
|
|
5347
5387
|
description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
|
|
5348
5388
|
severity: "error",
|
|
5389
|
+
fixable: true,
|
|
5390
|
+
supportedEffect: ["v3", "v4"],
|
|
5349
5391
|
apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
|
|
5350
5392
|
const ts = yield* service(TypeScriptApi);
|
|
5351
5393
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5484,6 +5526,8 @@ var deterministicKeys = createDiagnostic({
|
|
|
5484
5526
|
code: 25,
|
|
5485
5527
|
description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
|
|
5486
5528
|
severity: "off",
|
|
5529
|
+
fixable: true,
|
|
5530
|
+
supportedEffect: ["v3", "v4"],
|
|
5487
5531
|
apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
|
|
5488
5532
|
const ts = yield* service(TypeScriptApi);
|
|
5489
5533
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5601,6 +5645,8 @@ var duplicatePackage = createDiagnostic({
|
|
|
5601
5645
|
code: 6,
|
|
5602
5646
|
description: "Detects when multiple versions of the same Effect package are loaded",
|
|
5603
5647
|
severity: "warning",
|
|
5648
|
+
fixable: false,
|
|
5649
|
+
supportedEffect: ["v3", "v4"],
|
|
5604
5650
|
apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
|
|
5605
5651
|
const typeParser = yield* service(TypeParser);
|
|
5606
5652
|
const options = yield* service(LanguageServicePluginOptions);
|
|
@@ -5630,6 +5676,8 @@ var effectFnIife = createDiagnostic({
|
|
|
5630
5676
|
code: 46,
|
|
5631
5677
|
description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
|
|
5632
5678
|
severity: "warning",
|
|
5679
|
+
fixable: true,
|
|
5680
|
+
supportedEffect: ["v3", "v4"],
|
|
5633
5681
|
apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
|
|
5634
5682
|
const ts = yield* service(TypeScriptApi);
|
|
5635
5683
|
const typeParser = yield* service(TypeParser);
|
|
@@ -5732,6 +5780,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5732
5780
|
code: 41,
|
|
5733
5781
|
description: "Suggests using Effect.fn for functions that returns an Effect",
|
|
5734
5782
|
severity: "suggestion",
|
|
5783
|
+
fixable: true,
|
|
5784
|
+
supportedEffect: ["v3", "v4"],
|
|
5735
5785
|
apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
|
|
5736
5786
|
const ts = yield* service(TypeScriptApi);
|
|
5737
5787
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -5765,16 +5815,16 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5765
5815
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
5766
5816
|
return node.name;
|
|
5767
5817
|
}
|
|
5768
|
-
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
5818
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name) && node.parent.initializer === node) {
|
|
5769
5819
|
return node.parent.name;
|
|
5770
5820
|
}
|
|
5771
|
-
if (node.parent && ts.isPropertyAssignment(node.parent)) {
|
|
5821
|
+
if (node.parent && ts.isPropertyAssignment(node.parent) && node.parent.initializer === node) {
|
|
5772
5822
|
const name = node.parent.name;
|
|
5773
5823
|
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
5774
5824
|
return name;
|
|
5775
5825
|
}
|
|
5776
5826
|
}
|
|
5777
|
-
if (node.parent && ts.isPropertyDeclaration(node.parent)) {
|
|
5827
|
+
if (node.parent && ts.isPropertyDeclaration(node.parent) && node.parent.initializer === node) {
|
|
5778
5828
|
const name = node.parent.name;
|
|
5779
5829
|
if (ts.isIdentifier(name)) {
|
|
5780
5830
|
return name;
|
|
@@ -5782,6 +5832,190 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5782
5832
|
}
|
|
5783
5833
|
return void 0;
|
|
5784
5834
|
};
|
|
5835
|
+
const hasExportModifier = (node) => {
|
|
5836
|
+
if (!ts.canHaveModifiers(node)) return false;
|
|
5837
|
+
const modifiers = ts.getModifiers(node);
|
|
5838
|
+
return modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
5839
|
+
};
|
|
5840
|
+
const layerServiceNameFromExpression = (expression) => {
|
|
5841
|
+
if (expression.kind === ts.SyntaxKind.ThisKeyword) {
|
|
5842
|
+
const enclosingClass = ts.findAncestor(
|
|
5843
|
+
expression,
|
|
5844
|
+
(node) => ts.isClassDeclaration(node)
|
|
5845
|
+
);
|
|
5846
|
+
if (enclosingClass?.name) {
|
|
5847
|
+
return ts.idText(enclosingClass.name);
|
|
5848
|
+
}
|
|
5849
|
+
}
|
|
5850
|
+
if (ts.isIdentifier(expression)) return ts.idText(expression);
|
|
5851
|
+
return sourceFile.text.slice(expression.pos, expression.end).trim();
|
|
5852
|
+
};
|
|
5853
|
+
const tryGetLayerApiMethod = (node) => pipe(
|
|
5854
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("effect")(node),
|
|
5855
|
+
map4(() => "effect"),
|
|
5856
|
+
orElse2(
|
|
5857
|
+
() => pipe(
|
|
5858
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("succeed")(node),
|
|
5859
|
+
map4(() => "succeed"),
|
|
5860
|
+
orElse2(
|
|
5861
|
+
() => pipe(
|
|
5862
|
+
typeParser.isNodeReferenceToEffectLayerModuleApi("sync")(node),
|
|
5863
|
+
map4(() => "sync"),
|
|
5864
|
+
orElse2(() => succeed3(void 0))
|
|
5865
|
+
)
|
|
5866
|
+
)
|
|
5867
|
+
)
|
|
5868
|
+
)
|
|
5869
|
+
);
|
|
5870
|
+
const verifyLayerMethodAtCall = fn("effectFnOpportunity.verifyLayerMethodAtCall")(
|
|
5871
|
+
function* (callExpression, method, implementationExpression) {
|
|
5872
|
+
const directMethod = yield* tryGetLayerApiMethod(callExpression.expression);
|
|
5873
|
+
if (directMethod === method && callExpression.arguments.length >= 2 && callExpression.arguments[1] === implementationExpression) {
|
|
5874
|
+
return layerServiceNameFromExpression(callExpression.arguments[0]);
|
|
5875
|
+
}
|
|
5876
|
+
if (ts.isCallExpression(callExpression.expression)) {
|
|
5877
|
+
const innerCall = callExpression.expression;
|
|
5878
|
+
const innerMethod = yield* tryGetLayerApiMethod(innerCall.expression);
|
|
5879
|
+
if (innerMethod === method && innerCall.arguments.length >= 1 && callExpression.arguments.length >= 1 && callExpression.arguments[0] === implementationExpression) {
|
|
5880
|
+
return layerServiceNameFromExpression(innerCall.arguments[0]);
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5883
|
+
return void 0;
|
|
5884
|
+
}
|
|
5885
|
+
);
|
|
5886
|
+
const tryMatchLayerSucceedInference = fn("effectFnOpportunity.tryMatchLayerSucceedInference")(
|
|
5887
|
+
function* (objectLiteral) {
|
|
5888
|
+
const callExpression = objectLiteral.parent;
|
|
5889
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5890
|
+
return yield* verifyLayerMethodAtCall(callExpression, "succeed", objectLiteral);
|
|
5891
|
+
}
|
|
5892
|
+
);
|
|
5893
|
+
const tryMatchLayerSyncInference = fn("effectFnOpportunity.tryMatchLayerSyncInference")(
|
|
5894
|
+
function* (objectLiteral) {
|
|
5895
|
+
const returnStatement = objectLiteral.parent;
|
|
5896
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5897
|
+
const functionBody = returnStatement.parent;
|
|
5898
|
+
if (!functionBody || !ts.isBlock(functionBody)) return void 0;
|
|
5899
|
+
const lazyFunction = functionBody.parent;
|
|
5900
|
+
if (!lazyFunction || !ts.isArrowFunction(lazyFunction) && !ts.isFunctionExpression(lazyFunction)) {
|
|
5901
|
+
return void 0;
|
|
5902
|
+
}
|
|
5903
|
+
const callExpression = lazyFunction.parent;
|
|
5904
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5905
|
+
return yield* verifyLayerMethodAtCall(callExpression, "sync", lazyFunction);
|
|
5906
|
+
}
|
|
5907
|
+
);
|
|
5908
|
+
const tryMatchLayerEffectInference = fn("effectFnOpportunity.tryMatchLayerEffectInference")(
|
|
5909
|
+
function* (objectLiteral) {
|
|
5910
|
+
const returnStatement = objectLiteral.parent;
|
|
5911
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5912
|
+
const generatorBody = returnStatement.parent;
|
|
5913
|
+
if (!generatorBody || !ts.isBlock(generatorBody)) return void 0;
|
|
5914
|
+
const generatorFunction = generatorBody.parent;
|
|
5915
|
+
if (!generatorFunction || !ts.isFunctionExpression(generatorFunction) || !generatorFunction.asteriskToken) {
|
|
5916
|
+
return void 0;
|
|
5917
|
+
}
|
|
5918
|
+
const genCall = generatorFunction.parent;
|
|
5919
|
+
if (!genCall || !ts.isCallExpression(genCall)) return void 0;
|
|
5920
|
+
const parsedEffectGen = yield* option(typeParser.effectGen(genCall));
|
|
5921
|
+
if (parsedEffectGen._tag === "None" || parsedEffectGen.value.generatorFunction !== generatorFunction) {
|
|
5922
|
+
return void 0;
|
|
5923
|
+
}
|
|
5924
|
+
const layerCall = genCall.parent;
|
|
5925
|
+
if (!layerCall || !ts.isCallExpression(layerCall)) return void 0;
|
|
5926
|
+
return yield* verifyLayerMethodAtCall(layerCall, "effect", genCall);
|
|
5927
|
+
}
|
|
5928
|
+
);
|
|
5929
|
+
const tryMatchOfInference = fn("effectFnOpportunity.tryMatchOfInference")(
|
|
5930
|
+
function* (objectLiteral) {
|
|
5931
|
+
const callExpression = objectLiteral.parent;
|
|
5932
|
+
if (!callExpression || !ts.isCallExpression(callExpression)) return void 0;
|
|
5933
|
+
if (callExpression.arguments.length < 1 || callExpression.arguments[0] !== objectLiteral) return void 0;
|
|
5934
|
+
if (!ts.isPropertyAccessExpression(callExpression.expression)) return void 0;
|
|
5935
|
+
if (ts.idText(callExpression.expression.name) !== "of") return void 0;
|
|
5936
|
+
const serviceTagExpression = callExpression.expression.expression;
|
|
5937
|
+
const serviceTagType = typeCheckerUtils.getTypeAtLocation(serviceTagExpression);
|
|
5938
|
+
if (!serviceTagType) return void 0;
|
|
5939
|
+
const isTagLike = yield* pipe(
|
|
5940
|
+
typeParser.contextTag(serviceTagType, serviceTagExpression),
|
|
5941
|
+
orElse2(() => typeParser.serviceType(serviceTagType, serviceTagExpression)),
|
|
5942
|
+
option
|
|
5943
|
+
);
|
|
5944
|
+
if (isTagLike._tag === "None") return void 0;
|
|
5945
|
+
return layerServiceNameFromExpression(serviceTagExpression);
|
|
5946
|
+
}
|
|
5947
|
+
);
|
|
5948
|
+
const tryMatchServiceMapMakeInference = fn("effectFnOpportunity.tryMatchServiceMapMakeInference")(
|
|
5949
|
+
function* (objectLiteral) {
|
|
5950
|
+
const returnStatement = objectLiteral.parent;
|
|
5951
|
+
if (!returnStatement || !ts.isReturnStatement(returnStatement)) return void 0;
|
|
5952
|
+
const generatorBody = returnStatement.parent;
|
|
5953
|
+
if (!generatorBody || !ts.isBlock(generatorBody)) return void 0;
|
|
5954
|
+
const generatorFunction = generatorBody.parent;
|
|
5955
|
+
if (!generatorFunction || !ts.isFunctionExpression(generatorFunction) || !generatorFunction.asteriskToken) {
|
|
5956
|
+
return void 0;
|
|
5957
|
+
}
|
|
5958
|
+
const genCall = generatorFunction.parent;
|
|
5959
|
+
if (!genCall || !ts.isCallExpression(genCall)) return void 0;
|
|
5960
|
+
const parsedEffectGen = yield* option(typeParser.effectGen(genCall));
|
|
5961
|
+
if (parsedEffectGen._tag === "None" || parsedEffectGen.value.generatorFunction !== generatorFunction) {
|
|
5962
|
+
return void 0;
|
|
5963
|
+
}
|
|
5964
|
+
const makeProperty = genCall.parent;
|
|
5965
|
+
if (!makeProperty || !ts.isPropertyAssignment(makeProperty)) return void 0;
|
|
5966
|
+
if (makeProperty.initializer !== genCall) return void 0;
|
|
5967
|
+
if (!ts.isIdentifier(makeProperty.name) || ts.idText(makeProperty.name) !== "make") return void 0;
|
|
5968
|
+
let currentNode = makeProperty.parent;
|
|
5969
|
+
let classDeclaration = void 0;
|
|
5970
|
+
while (currentNode) {
|
|
5971
|
+
if (ts.isClassDeclaration(currentNode)) {
|
|
5972
|
+
classDeclaration = currentNode;
|
|
5973
|
+
break;
|
|
5974
|
+
}
|
|
5975
|
+
currentNode = currentNode.parent;
|
|
5976
|
+
}
|
|
5977
|
+
if (!classDeclaration || !classDeclaration.name) return void 0;
|
|
5978
|
+
const parsedServiceMapService = yield* option(typeParser.extendsServiceMapService(classDeclaration));
|
|
5979
|
+
if (parsedServiceMapService._tag === "None") return void 0;
|
|
5980
|
+
return ts.idText(classDeclaration.name);
|
|
5981
|
+
}
|
|
5982
|
+
);
|
|
5983
|
+
const tryGetLayerInferredTraceName = fn("effectFnOpportunity.tryGetLayerInferredTraceName")(
|
|
5984
|
+
function* (node, suggestedTraceName) {
|
|
5985
|
+
if (!suggestedTraceName) return void 0;
|
|
5986
|
+
if (!(node.parent && ts.isPropertyAssignment(node.parent) && node.parent.initializer === node && node.parent.parent && ts.isObjectLiteralExpression(node.parent.parent))) {
|
|
5987
|
+
return void 0;
|
|
5988
|
+
}
|
|
5989
|
+
const objectLiteral = node.parent.parent;
|
|
5990
|
+
const succeedServiceName = yield* tryMatchLayerSucceedInference(objectLiteral);
|
|
5991
|
+
if (succeedServiceName) return `${succeedServiceName}.${suggestedTraceName}`;
|
|
5992
|
+
const syncServiceName = yield* tryMatchLayerSyncInference(objectLiteral);
|
|
5993
|
+
if (syncServiceName) return `${syncServiceName}.${suggestedTraceName}`;
|
|
5994
|
+
const effectServiceName = yield* tryMatchLayerEffectInference(objectLiteral);
|
|
5995
|
+
if (effectServiceName) return `${effectServiceName}.${suggestedTraceName}`;
|
|
5996
|
+
const ofServiceName = yield* tryMatchOfInference(objectLiteral);
|
|
5997
|
+
if (ofServiceName) return `${ofServiceName}.${suggestedTraceName}`;
|
|
5998
|
+
const serviceMapMakeServiceName = yield* tryMatchServiceMapMakeInference(objectLiteral);
|
|
5999
|
+
return serviceMapMakeServiceName ? `${serviceMapMakeServiceName}.${suggestedTraceName}` : void 0;
|
|
6000
|
+
}
|
|
6001
|
+
);
|
|
6002
|
+
const getInferredTraceName = fn("effectFnOpportunity.getInferredTraceName")(
|
|
6003
|
+
function* (node, suggestedTraceName) {
|
|
6004
|
+
const inferredFromLayer = yield* tryGetLayerInferredTraceName(node, suggestedTraceName);
|
|
6005
|
+
if (inferredFromLayer) return inferredFromLayer;
|
|
6006
|
+
if (ts.isFunctionDeclaration(node) && node.name && hasExportModifier(node)) {
|
|
6007
|
+
return ts.idText(node.name);
|
|
6008
|
+
}
|
|
6009
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name) && node.parent.initializer === node) {
|
|
6010
|
+
const variableDeclarationList = node.parent.parent;
|
|
6011
|
+
const variableStatement = variableDeclarationList?.parent;
|
|
6012
|
+
if (variableDeclarationList && ts.isVariableDeclarationList(variableDeclarationList) && variableStatement && ts.isVariableStatement(variableStatement) && hasExportModifier(variableStatement) && (variableDeclarationList.flags & ts.NodeFlags.Const) !== 0) {
|
|
6013
|
+
return ts.idText(node.parent.name);
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
return void 0;
|
|
6017
|
+
}
|
|
6018
|
+
);
|
|
5785
6019
|
const areParametersReferencedIn = (fnNode, nodes) => {
|
|
5786
6020
|
if (fnNode.parameters.length === 0 || nodes.length === 0) return false;
|
|
5787
6021
|
const firstParam = fnNode.parameters[0];
|
|
@@ -5866,7 +6100,10 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5866
6100
|
);
|
|
5867
6101
|
};
|
|
5868
6102
|
const parseEffectFnOpportunityTargetGen = fn("effectFnOpportunity.parseEffectFnOpportunityTarget")(
|
|
5869
|
-
function* (node, returnType,
|
|
6103
|
+
function* (node, returnType, nameIdentifier) {
|
|
6104
|
+
const suggestedTraceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
|
|
6105
|
+
const inferredTraceName = yield* getInferredTraceName(node, suggestedTraceName);
|
|
6106
|
+
const hasStrictLayerInferredName = inferredTraceName !== void 0 && inferredTraceName !== suggestedTraceName;
|
|
5870
6107
|
if (yield* isInsideEffectFn(node)) {
|
|
5871
6108
|
return yield* TypeParserIssue.issue;
|
|
5872
6109
|
}
|
|
@@ -5875,11 +6112,11 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5875
6112
|
const opportunity = yield* pipe(
|
|
5876
6113
|
tryParseGenOpportunity(node),
|
|
5877
6114
|
orElse2(() => {
|
|
5878
|
-
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
|
|
6115
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body) && !hasStrictLayerInferredName) {
|
|
5879
6116
|
return TypeParserIssue.issue;
|
|
5880
6117
|
}
|
|
5881
6118
|
const body = ts.isArrowFunction(node) ? node.body : node.body;
|
|
5882
|
-
if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
|
|
6119
|
+
if ((!body || !ts.isBlock(body) || body.statements.length <= 5) && !hasStrictLayerInferredName) {
|
|
5883
6120
|
return TypeParserIssue.issue;
|
|
5884
6121
|
}
|
|
5885
6122
|
return succeed3({
|
|
@@ -5894,7 +6131,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5894
6131
|
node,
|
|
5895
6132
|
nameIdentifier,
|
|
5896
6133
|
effectModuleName: opportunity.effectModuleName,
|
|
5897
|
-
inferredTraceName
|
|
6134
|
+
inferredTraceName,
|
|
6135
|
+
suggestedTraceName,
|
|
5898
6136
|
explicitTraceExpression: opportunity.explicitTraceExpression,
|
|
5899
6137
|
pipeArguments: opportunity.pipeArguments,
|
|
5900
6138
|
generatorFunction: opportunity.generatorFunction,
|
|
@@ -5904,27 +6142,26 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5904
6142
|
);
|
|
5905
6143
|
const parseEffectFnOpportunityTarget = (node) => {
|
|
5906
6144
|
if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
|
|
5907
|
-
return
|
|
6145
|
+
return;
|
|
5908
6146
|
}
|
|
5909
6147
|
if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
|
|
5910
|
-
return
|
|
6148
|
+
return;
|
|
5911
6149
|
}
|
|
5912
6150
|
if (ts.isFunctionExpression(node) && node.name) {
|
|
5913
|
-
return
|
|
6151
|
+
return;
|
|
5914
6152
|
}
|
|
5915
6153
|
if (node.type) {
|
|
5916
|
-
return
|
|
6154
|
+
return;
|
|
5917
6155
|
}
|
|
5918
6156
|
const functionType = typeChecker.getTypeAtLocation(node);
|
|
5919
|
-
if (!functionType) return
|
|
6157
|
+
if (!functionType) return;
|
|
5920
6158
|
const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
|
|
5921
|
-
if (callSignatures.length !== 1) return
|
|
6159
|
+
if (callSignatures.length !== 1) return;
|
|
5922
6160
|
const signature = callSignatures[0];
|
|
5923
6161
|
const returnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
5924
6162
|
const nameIdentifier = getNameIdentifier(node);
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
return parseEffectFnOpportunityTargetGen(node, returnType, traceName, nameIdentifier);
|
|
6163
|
+
if (!nameIdentifier) return;
|
|
6164
|
+
return parseEffectFnOpportunityTargetGen(node, returnType, nameIdentifier);
|
|
5928
6165
|
};
|
|
5929
6166
|
const getFunctionBodyBlock = (node) => {
|
|
5930
6167
|
if (ts.isArrowFunction(node)) {
|
|
@@ -5998,18 +6235,21 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
5998
6235
|
while (nodeToVisit.length > 0) {
|
|
5999
6236
|
const node = nodeToVisit.shift();
|
|
6000
6237
|
ts.forEachChild(node, appendNodeToVisit);
|
|
6001
|
-
const
|
|
6002
|
-
if (
|
|
6003
|
-
|
|
6238
|
+
const test = parseEffectFnOpportunityTarget(node);
|
|
6239
|
+
if (!test) continue;
|
|
6240
|
+
const target = yield* orUndefined(test);
|
|
6241
|
+
if (!target) continue;
|
|
6242
|
+
if (target.hasParamsInPipeArgs) continue;
|
|
6004
6243
|
const {
|
|
6005
6244
|
effectModuleName,
|
|
6006
6245
|
explicitTraceExpression,
|
|
6007
6246
|
inferredTraceName,
|
|
6008
6247
|
nameIdentifier,
|
|
6009
6248
|
node: targetNode,
|
|
6010
|
-
pipeArguments: pipeArguments2
|
|
6011
|
-
|
|
6012
|
-
|
|
6249
|
+
pipeArguments: pipeArguments2,
|
|
6250
|
+
suggestedTraceName
|
|
6251
|
+
} = target;
|
|
6252
|
+
const innerFunction = target.generatorFunction ?? targetNode;
|
|
6013
6253
|
const fixes = [];
|
|
6014
6254
|
if (pluginOptions.effectFn.includes("span") && explicitTraceExpression) {
|
|
6015
6255
|
fixes.push({
|
|
@@ -6029,7 +6269,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6029
6269
|
})
|
|
6030
6270
|
});
|
|
6031
6271
|
}
|
|
6032
|
-
if (pluginOptions.effectFn.includes("untraced") && target.
|
|
6272
|
+
if (pluginOptions.effectFn.includes("untraced") && target.generatorFunction) {
|
|
6033
6273
|
fixes.push({
|
|
6034
6274
|
fixName: "effectFnOpportunity_toEffectFnUntraced",
|
|
6035
6275
|
description: "Convert to Effect.fnUntraced",
|
|
@@ -6051,22 +6291,41 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6051
6291
|
})
|
|
6052
6292
|
});
|
|
6053
6293
|
}
|
|
6054
|
-
if (
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6294
|
+
if (!explicitTraceExpression) {
|
|
6295
|
+
if (pluginOptions.effectFn.includes("inferred-span") && inferredTraceName) {
|
|
6296
|
+
fixes.push({
|
|
6297
|
+
fixName: "effectFnOpportunity_toEffectFnSpanInferred",
|
|
6298
|
+
description: `Convert to Effect.fn("${inferredTraceName}")`,
|
|
6299
|
+
apply: gen(function* () {
|
|
6300
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6301
|
+
const newNode = createEffectFnNode(
|
|
6302
|
+
targetNode,
|
|
6303
|
+
innerFunction,
|
|
6304
|
+
effectModuleName,
|
|
6305
|
+
inferredTraceName,
|
|
6306
|
+
pipeArguments2
|
|
6307
|
+
);
|
|
6308
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
6309
|
+
})
|
|
6310
|
+
});
|
|
6311
|
+
}
|
|
6312
|
+
if (pluginOptions.effectFn.includes("suggested-span") && suggestedTraceName && (!pluginOptions.effectFn.includes("inferred-span") || suggestedTraceName !== inferredTraceName)) {
|
|
6313
|
+
fixes.push({
|
|
6314
|
+
fixName: "effectFnOpportunity_toEffectFnSpanSuggested",
|
|
6315
|
+
description: `Convert to Effect.fn("${suggestedTraceName}")`,
|
|
6316
|
+
apply: gen(function* () {
|
|
6317
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
6318
|
+
const newNode = createEffectFnNode(
|
|
6319
|
+
targetNode,
|
|
6320
|
+
innerFunction,
|
|
6321
|
+
effectModuleName,
|
|
6322
|
+
suggestedTraceName,
|
|
6323
|
+
pipeArguments2
|
|
6324
|
+
);
|
|
6325
|
+
changeTracker.replaceNode(sourceFile, targetNode, newNode);
|
|
6326
|
+
})
|
|
6327
|
+
});
|
|
6328
|
+
}
|
|
6070
6329
|
}
|
|
6071
6330
|
if (fixes.length === 0) continue;
|
|
6072
6331
|
const generateExpectedSignature = () => {
|
|
@@ -6079,7 +6338,7 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6079
6338
|
}
|
|
6080
6339
|
return "_";
|
|
6081
6340
|
}).join(", ");
|
|
6082
|
-
const fnSignature = `function*${typeParamNames}(${paramNames}) { ... }`;
|
|
6341
|
+
const fnSignature = ts.isArrowFunction(innerFunction) ? `${typeParamNames}(${paramNames}) => { ... }` : isGeneratorFunction(innerFunction) ? `function*${typeParamNames}(${paramNames}) { ... }` : `function${typeParamNames}(${paramNames}) { ... }`;
|
|
6083
6342
|
const pipeArgsForWithSpan = pipeArguments2.slice(0, -1);
|
|
6084
6343
|
const pipeArgsSuffix = (args3) => args3.length > 0 ? ", ...pipeTransformations" : "";
|
|
6085
6344
|
switch (firstFix.fixName) {
|
|
@@ -6093,6 +6352,8 @@ var effectFnOpportunity = createDiagnostic({
|
|
|
6093
6352
|
return `${effectModuleName}.fn(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6094
6353
|
case "effectFnOpportunity_toEffectFnSpanInferred":
|
|
6095
6354
|
return `${effectModuleName}.fn("${inferredTraceName}")(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6355
|
+
case "effectFnOpportunity_toEffectFnSpanSuggested":
|
|
6356
|
+
return `${effectModuleName}.fn("${suggestedTraceName}")(${fnSignature}${pipeArgsSuffix(pipeArguments2)})`;
|
|
6096
6357
|
default:
|
|
6097
6358
|
return `${effectModuleName}.fn(${fnSignature})`;
|
|
6098
6359
|
}
|
|
@@ -6113,6 +6374,8 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6113
6374
|
code: 23,
|
|
6114
6375
|
description: "Warns when using the deprecated adapter parameter in Effect.gen",
|
|
6115
6376
|
severity: "warning",
|
|
6377
|
+
fixable: false,
|
|
6378
|
+
supportedEffect: ["v3", "v4"],
|
|
6116
6379
|
apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
|
|
6117
6380
|
const ts = yield* service(TypeScriptApi);
|
|
6118
6381
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6145,12 +6408,80 @@ var effectGenUsesAdapter = createDiagnostic({
|
|
|
6145
6408
|
})
|
|
6146
6409
|
});
|
|
6147
6410
|
|
|
6411
|
+
// src/diagnostics/effectInFailure.ts
|
|
6412
|
+
var effectInFailure = createDiagnostic({
|
|
6413
|
+
name: "effectInFailure",
|
|
6414
|
+
code: 49,
|
|
6415
|
+
description: "Warns when an Effect is used inside an Effect failure channel",
|
|
6416
|
+
severity: "warning",
|
|
6417
|
+
fixable: false,
|
|
6418
|
+
supportedEffect: ["v3", "v4"],
|
|
6419
|
+
apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
|
|
6420
|
+
const ts = yield* service(TypeScriptApi);
|
|
6421
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6422
|
+
const typeParser = yield* service(TypeParser);
|
|
6423
|
+
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
6424
|
+
const isStrictEffectType = cachedBy(
|
|
6425
|
+
fn("effectInFailure.isStrictEffectType")(function* (type, atLocation) {
|
|
6426
|
+
yield* typeParser.strictEffectType(type, atLocation);
|
|
6427
|
+
return true;
|
|
6428
|
+
}),
|
|
6429
|
+
"effectInFailure.isStrictEffectType",
|
|
6430
|
+
(type) => type
|
|
6431
|
+
);
|
|
6432
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
6433
|
+
const stack = [sourceFile];
|
|
6434
|
+
const shouldSkipBecauseChildMatched = /* @__PURE__ */ new WeakSet();
|
|
6435
|
+
while (stack.length > 0) {
|
|
6436
|
+
const node = stack.pop();
|
|
6437
|
+
if (!visited.has(node)) {
|
|
6438
|
+
visited.add(node);
|
|
6439
|
+
stack.push(node);
|
|
6440
|
+
ts.forEachChild(node, (child) => {
|
|
6441
|
+
stack.push(child);
|
|
6442
|
+
return void 0;
|
|
6443
|
+
});
|
|
6444
|
+
continue;
|
|
6445
|
+
}
|
|
6446
|
+
if (shouldSkipBecauseChildMatched.has(node)) {
|
|
6447
|
+
if (node.parent) shouldSkipBecauseChildMatched.add(node.parent);
|
|
6448
|
+
continue;
|
|
6449
|
+
}
|
|
6450
|
+
const type = typeCheckerUtils.getTypeAtLocation(node);
|
|
6451
|
+
if (!type) continue;
|
|
6452
|
+
const effect = yield* orUndefined(typeParser.strictEffectType(type, node));
|
|
6453
|
+
if (!effect) continue;
|
|
6454
|
+
const failureMembers = typeCheckerUtils.unrollUnionMembers(effect.E);
|
|
6455
|
+
let memberWithEffect = void 0;
|
|
6456
|
+
for (const member of failureMembers) {
|
|
6457
|
+
const isMemberEffect = yield* orUndefined(isStrictEffectType(member, node));
|
|
6458
|
+
if (isMemberEffect) {
|
|
6459
|
+
memberWithEffect = member;
|
|
6460
|
+
break;
|
|
6461
|
+
}
|
|
6462
|
+
}
|
|
6463
|
+
if (!memberWithEffect) continue;
|
|
6464
|
+
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.`;
|
|
6465
|
+
report({
|
|
6466
|
+
location: node,
|
|
6467
|
+
messageText,
|
|
6468
|
+
fixes: []
|
|
6469
|
+
});
|
|
6470
|
+
if (node.parent) {
|
|
6471
|
+
shouldSkipBecauseChildMatched.add(node.parent);
|
|
6472
|
+
}
|
|
6473
|
+
}
|
|
6474
|
+
})
|
|
6475
|
+
});
|
|
6476
|
+
|
|
6148
6477
|
// src/diagnostics/effectInVoidSuccess.ts
|
|
6149
6478
|
var effectInVoidSuccess = createDiagnostic({
|
|
6150
6479
|
name: "effectInVoidSuccess",
|
|
6151
6480
|
code: 14,
|
|
6152
6481
|
description: "Detects nested Effects in void success channels that may cause unexecuted effects",
|
|
6153
6482
|
severity: "warning",
|
|
6483
|
+
fixable: false,
|
|
6484
|
+
supportedEffect: ["v3", "v4"],
|
|
6154
6485
|
apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
|
|
6155
6486
|
const ts = yield* service(TypeScriptApi);
|
|
6156
6487
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6200,6 +6531,8 @@ var effectMapVoid = createDiagnostic({
|
|
|
6200
6531
|
code: 40,
|
|
6201
6532
|
description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
|
|
6202
6533
|
severity: "suggestion",
|
|
6534
|
+
fixable: true,
|
|
6535
|
+
supportedEffect: ["v3", "v4"],
|
|
6203
6536
|
apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
|
|
6204
6537
|
const ts = yield* service(TypeScriptApi);
|
|
6205
6538
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6264,6 +6597,8 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6264
6597
|
code: 47,
|
|
6265
6598
|
description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
|
|
6266
6599
|
severity: "suggestion",
|
|
6600
|
+
fixable: true,
|
|
6601
|
+
supportedEffect: ["v3", "v4"],
|
|
6267
6602
|
apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
|
|
6268
6603
|
const ts = yield* service(TypeScriptApi);
|
|
6269
6604
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6309,12 +6644,66 @@ var effectSucceedWithVoid = createDiagnostic({
|
|
|
6309
6644
|
})
|
|
6310
6645
|
});
|
|
6311
6646
|
|
|
6647
|
+
// src/diagnostics/extendsNativeError.ts
|
|
6648
|
+
var extendsNativeError = createDiagnostic({
|
|
6649
|
+
name: "extendsNativeError",
|
|
6650
|
+
code: 50,
|
|
6651
|
+
description: "Warns when a class directly extends the native Error class",
|
|
6652
|
+
severity: "off",
|
|
6653
|
+
fixable: false,
|
|
6654
|
+
supportedEffect: ["v3", "v4"],
|
|
6655
|
+
apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
|
|
6656
|
+
const ts = yield* service(TypeScriptApi);
|
|
6657
|
+
const typeChecker = yield* service(TypeCheckerApi);
|
|
6658
|
+
const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
|
|
6659
|
+
if (!errorSymbol) return;
|
|
6660
|
+
const nodeToVisit = [];
|
|
6661
|
+
const appendNodeToVisit = (node) => {
|
|
6662
|
+
nodeToVisit.push(node);
|
|
6663
|
+
return void 0;
|
|
6664
|
+
};
|
|
6665
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
6666
|
+
while (nodeToVisit.length > 0) {
|
|
6667
|
+
const node = nodeToVisit.shift();
|
|
6668
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
6669
|
+
for (const clause of node.heritageClauses) {
|
|
6670
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
|
|
6671
|
+
const typeExpression = clause.types[0].expression;
|
|
6672
|
+
const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
|
|
6673
|
+
const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
|
|
6674
|
+
const isNativeError = resolvedSymbol === errorSymbol || (() => {
|
|
6675
|
+
if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
|
|
6676
|
+
const exprType = typeChecker.getTypeAtLocation(typeExpression);
|
|
6677
|
+
const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
|
|
6678
|
+
if (constructSignatures.length > 0) {
|
|
6679
|
+
const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
|
|
6680
|
+
return instanceType.symbol === errorSymbol;
|
|
6681
|
+
}
|
|
6682
|
+
return false;
|
|
6683
|
+
})();
|
|
6684
|
+
if (isNativeError) {
|
|
6685
|
+
report({
|
|
6686
|
+
location: node.name ?? typeExpression,
|
|
6687
|
+
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.",
|
|
6688
|
+
fixes: []
|
|
6689
|
+
});
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
6695
|
+
}
|
|
6696
|
+
})
|
|
6697
|
+
});
|
|
6698
|
+
|
|
6312
6699
|
// src/diagnostics/floatingEffect.ts
|
|
6313
6700
|
var floatingEffect = createDiagnostic({
|
|
6314
6701
|
name: "floatingEffect",
|
|
6315
6702
|
code: 3,
|
|
6316
6703
|
description: "Ensures Effects are yielded or assigned to variables, not left floating",
|
|
6317
6704
|
severity: "error",
|
|
6705
|
+
fixable: false,
|
|
6706
|
+
supportedEffect: ["v3", "v4"],
|
|
6318
6707
|
apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
|
|
6319
6708
|
const ts = yield* service(TypeScriptApi);
|
|
6320
6709
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6366,6 +6755,8 @@ var genericEffectServices = createDiagnostic({
|
|
|
6366
6755
|
code: 10,
|
|
6367
6756
|
description: "Prevents services with type parameters that cannot be discriminated at runtime",
|
|
6368
6757
|
severity: "warning",
|
|
6758
|
+
fixable: false,
|
|
6759
|
+
supportedEffect: ["v3", "v4"],
|
|
6369
6760
|
apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
|
|
6370
6761
|
const ts = yield* service(TypeScriptApi);
|
|
6371
6762
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6413,6 +6804,8 @@ var globalErrorInEffectCatch = createDiagnostic({
|
|
|
6413
6804
|
code: 36,
|
|
6414
6805
|
description: "Warns when catch callbacks return global Error type instead of typed errors",
|
|
6415
6806
|
severity: "warning",
|
|
6807
|
+
fixable: false,
|
|
6808
|
+
supportedEffect: ["v3", "v4"],
|
|
6416
6809
|
apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
|
|
6417
6810
|
const ts = yield* service(TypeScriptApi);
|
|
6418
6811
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6473,6 +6866,8 @@ var globalErrorInEffectFailure = createDiagnostic({
|
|
|
6473
6866
|
code: 35,
|
|
6474
6867
|
description: "Warns when the global Error type is used in an Effect failure channel",
|
|
6475
6868
|
severity: "warning",
|
|
6869
|
+
fixable: false,
|
|
6870
|
+
supportedEffect: ["v3", "v4"],
|
|
6476
6871
|
apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
|
|
6477
6872
|
const ts = yield* service(TypeScriptApi);
|
|
6478
6873
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6526,6 +6921,8 @@ var importFromBarrel = createDiagnostic({
|
|
|
6526
6921
|
code: 12,
|
|
6527
6922
|
description: "Suggests importing from specific module paths instead of barrel exports",
|
|
6528
6923
|
severity: "off",
|
|
6924
|
+
fixable: true,
|
|
6925
|
+
supportedEffect: ["v3", "v4"],
|
|
6529
6926
|
apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
|
|
6530
6927
|
const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
|
|
6531
6928
|
if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
|
|
@@ -6666,6 +7063,8 @@ var instanceOfSchema = createDiagnostic({
|
|
|
6666
7063
|
code: 45,
|
|
6667
7064
|
description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
|
|
6668
7065
|
severity: "off",
|
|
7066
|
+
fixable: true,
|
|
7067
|
+
supportedEffect: ["v3", "v4"],
|
|
6669
7068
|
apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
|
|
6670
7069
|
const ts = yield* service(TypeScriptApi);
|
|
6671
7070
|
const typeParser = yield* service(TypeParser);
|
|
@@ -6729,6 +7128,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
|
|
|
6729
7128
|
code: 37,
|
|
6730
7129
|
description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
|
|
6731
7130
|
severity: "warning",
|
|
7131
|
+
fixable: true,
|
|
7132
|
+
supportedEffect: ["v3", "v4"],
|
|
6732
7133
|
apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
|
|
6733
7134
|
const ts = yield* service(TypeScriptApi);
|
|
6734
7135
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6842,6 +7243,8 @@ var leakingRequirements = createDiagnostic({
|
|
|
6842
7243
|
code: 8,
|
|
6843
7244
|
description: "Detects implementation services leaked in service methods",
|
|
6844
7245
|
severity: "suggestion",
|
|
7246
|
+
fixable: false,
|
|
7247
|
+
supportedEffect: ["v3", "v4"],
|
|
6845
7248
|
apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
|
|
6846
7249
|
const ts = yield* service(TypeScriptApi);
|
|
6847
7250
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -6996,6 +7399,8 @@ var missedPipeableOpportunity = createDiagnostic({
|
|
|
6996
7399
|
code: 26,
|
|
6997
7400
|
description: "Enforces the use of pipeable style for nested function calls",
|
|
6998
7401
|
severity: "off",
|
|
7402
|
+
fixable: true,
|
|
7403
|
+
supportedEffect: ["v3", "v4"],
|
|
6999
7404
|
apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
|
|
7000
7405
|
const ts = yield* service(TypeScriptApi);
|
|
7001
7406
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7176,6 +7581,8 @@ var missingEffectContext = createDiagnostic({
|
|
|
7176
7581
|
code: 1,
|
|
7177
7582
|
description: "Reports missing service requirements in Effect context channel",
|
|
7178
7583
|
severity: "error",
|
|
7584
|
+
fixable: false,
|
|
7585
|
+
supportedEffect: ["v3", "v4"],
|
|
7179
7586
|
apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
|
|
7180
7587
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7181
7588
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7225,6 +7632,8 @@ var missingEffectError = createDiagnostic({
|
|
|
7225
7632
|
code: 1,
|
|
7226
7633
|
description: "Reports missing error types in Effect error channel",
|
|
7227
7634
|
severity: "error",
|
|
7635
|
+
fixable: true,
|
|
7636
|
+
supportedEffect: ["v3", "v4"],
|
|
7228
7637
|
apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
|
|
7229
7638
|
const ts = yield* service(TypeScriptApi);
|
|
7230
7639
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7366,6 +7775,8 @@ var missingEffectServiceDependency = createDiagnostic({
|
|
|
7366
7775
|
code: 22,
|
|
7367
7776
|
description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
|
|
7368
7777
|
severity: "off",
|
|
7778
|
+
fixable: false,
|
|
7779
|
+
supportedEffect: ["v3"],
|
|
7369
7780
|
apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
|
|
7370
7781
|
const ts = yield* service(TypeScriptApi);
|
|
7371
7782
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7460,6 +7871,8 @@ var missingLayerContext = createDiagnostic({
|
|
|
7460
7871
|
code: 38,
|
|
7461
7872
|
description: "Reports missing service requirements in Layer context channel",
|
|
7462
7873
|
severity: "error",
|
|
7874
|
+
fixable: false,
|
|
7875
|
+
supportedEffect: ["v3", "v4"],
|
|
7463
7876
|
apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
|
|
7464
7877
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
7465
7878
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7509,10 +7922,13 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7509
7922
|
code: 7,
|
|
7510
7923
|
description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
|
|
7511
7924
|
severity: "error",
|
|
7925
|
+
fixable: true,
|
|
7926
|
+
supportedEffect: ["v3", "v4"],
|
|
7512
7927
|
apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
|
|
7513
7928
|
const ts = yield* service(TypeScriptApi);
|
|
7514
7929
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
7515
7930
|
const typeParser = yield* service(TypeParser);
|
|
7931
|
+
const tsUtils = yield* service(TypeScriptUtils);
|
|
7516
7932
|
const nodeToVisit = [];
|
|
7517
7933
|
const appendNodeToVisit = (node) => {
|
|
7518
7934
|
nodeToVisit.push(node);
|
|
@@ -7522,50 +7938,32 @@ var missingReturnYieldStar = createDiagnostic({
|
|
|
7522
7938
|
while (nodeToVisit.length > 0) {
|
|
7523
7939
|
const node = nodeToVisit.shift();
|
|
7524
7940
|
ts.forEachChild(node, appendNodeToVisit);
|
|
7525
|
-
if (ts.
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
node,
|
|
7552
|
-
ts.factory.createReturnStatement(
|
|
7553
|
-
node
|
|
7554
|
-
)
|
|
7555
|
-
);
|
|
7556
|
-
})
|
|
7557
|
-
}] : [];
|
|
7558
|
-
report({
|
|
7559
|
-
location: node,
|
|
7560
|
-
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.`,
|
|
7561
|
-
fixes: fix
|
|
7562
|
-
});
|
|
7563
|
-
}
|
|
7564
|
-
}
|
|
7565
|
-
}
|
|
7566
|
-
}
|
|
7567
|
-
}
|
|
7568
|
-
}
|
|
7941
|
+
if (!ts.isExpressionStatement(node)) continue;
|
|
7942
|
+
const unwrapped = tsUtils.skipOuterExpressions(node.expression);
|
|
7943
|
+
if (!ts.isYieldExpression(unwrapped) || !unwrapped.expression || !unwrapped.asteriskToken) continue;
|
|
7944
|
+
const type = typeCheckerUtils.getTypeAtLocation(unwrapped.expression);
|
|
7945
|
+
if (!type) continue;
|
|
7946
|
+
const maybeEffect = yield* option(typeParser.effectYieldableType(type, unwrapped.expression));
|
|
7947
|
+
if (!(isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never)) continue;
|
|
7948
|
+
const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
|
|
7949
|
+
if (!effectGen || scopeNode && scopeNode !== effectGen.generatorFunction) continue;
|
|
7950
|
+
const fix = [{
|
|
7951
|
+
fixName: "missingReturnYieldStar_fix",
|
|
7952
|
+
description: "Add return statement",
|
|
7953
|
+
apply: gen(function* () {
|
|
7954
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
7955
|
+
changeTracker.replaceNode(
|
|
7956
|
+
sourceFile,
|
|
7957
|
+
node,
|
|
7958
|
+
ts.factory.createReturnStatement(node.expression)
|
|
7959
|
+
);
|
|
7960
|
+
})
|
|
7961
|
+
}];
|
|
7962
|
+
report({
|
|
7963
|
+
location: unwrapped,
|
|
7964
|
+
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.`,
|
|
7965
|
+
fixes: fix
|
|
7966
|
+
});
|
|
7569
7967
|
}
|
|
7570
7968
|
})
|
|
7571
7969
|
});
|
|
@@ -7576,6 +7974,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
|
|
|
7576
7974
|
code: 4,
|
|
7577
7975
|
description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
|
|
7578
7976
|
severity: "error",
|
|
7977
|
+
fixable: true,
|
|
7978
|
+
supportedEffect: ["v3", "v4"],
|
|
7579
7979
|
apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
|
|
7580
7980
|
const ts = yield* service(TypeScriptApi);
|
|
7581
7981
|
const typeParser = yield* service(TypeParser);
|
|
@@ -7651,6 +8051,8 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7651
8051
|
code: 18,
|
|
7652
8052
|
description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
|
|
7653
8053
|
severity: "warning",
|
|
8054
|
+
fixable: true,
|
|
8055
|
+
supportedEffect: ["v3", "v4"],
|
|
7654
8056
|
apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
|
|
7655
8057
|
const ts = yield* service(TypeScriptApi);
|
|
7656
8058
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -7737,12 +8139,85 @@ var multipleEffectProvide = createDiagnostic({
|
|
|
7737
8139
|
})
|
|
7738
8140
|
});
|
|
7739
8141
|
|
|
8142
|
+
// src/diagnostics/nodeBuiltinImport.ts
|
|
8143
|
+
var moduleAlternativesV3 = /* @__PURE__ */ new Map([
|
|
8144
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8145
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8146
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8147
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
|
|
8148
|
+
["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8149
|
+
["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8150
|
+
["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8151
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8152
|
+
["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8153
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
|
|
8154
|
+
["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
|
|
8155
|
+
["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
|
|
8156
|
+
]);
|
|
8157
|
+
var moduleAlternativesV4 = /* @__PURE__ */ new Map([
|
|
8158
|
+
["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8159
|
+
["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8160
|
+
["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8161
|
+
["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
|
|
8162
|
+
["path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8163
|
+
["node:path", { alternative: "Path", module: "path", package: "effect" }],
|
|
8164
|
+
["path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8165
|
+
["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
|
|
8166
|
+
["path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8167
|
+
["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
|
|
8168
|
+
["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
|
|
8169
|
+
["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
|
|
8170
|
+
]);
|
|
8171
|
+
var nodeBuiltinImport = createDiagnostic({
|
|
8172
|
+
name: "nodeBuiltinImport",
|
|
8173
|
+
code: 52,
|
|
8174
|
+
description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
|
|
8175
|
+
severity: "off",
|
|
8176
|
+
fixable: false,
|
|
8177
|
+
supportedEffect: ["v3", "v4"],
|
|
8178
|
+
apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
|
|
8179
|
+
const ts = yield* service(TypeScriptApi);
|
|
8180
|
+
const typeParser = yield* service(TypeParser);
|
|
8181
|
+
const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
|
|
8182
|
+
for (const statement of sourceFile.statements) {
|
|
8183
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
8184
|
+
const specifier = statement.moduleSpecifier.text;
|
|
8185
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8186
|
+
if (match2) {
|
|
8187
|
+
report({
|
|
8188
|
+
location: statement.moduleSpecifier,
|
|
8189
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8190
|
+
fixes: []
|
|
8191
|
+
});
|
|
8192
|
+
}
|
|
8193
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
8194
|
+
for (const decl of statement.declarationList.declarations) {
|
|
8195
|
+
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])) {
|
|
8196
|
+
const arg = decl.initializer.arguments[0];
|
|
8197
|
+
const specifier = arg.text;
|
|
8198
|
+
const match2 = moduleAlternatives.get(specifier);
|
|
8199
|
+
if (match2) {
|
|
8200
|
+
report({
|
|
8201
|
+
location: arg,
|
|
8202
|
+
messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
|
|
8203
|
+
fixes: []
|
|
8204
|
+
});
|
|
8205
|
+
}
|
|
8206
|
+
}
|
|
8207
|
+
}
|
|
8208
|
+
}
|
|
8209
|
+
}
|
|
8210
|
+
})
|
|
8211
|
+
});
|
|
8212
|
+
|
|
7740
8213
|
// src/diagnostics/nonObjectEffectServiceType.ts
|
|
7741
8214
|
var nonObjectEffectServiceType = createDiagnostic({
|
|
7742
8215
|
name: "nonObjectEffectServiceType",
|
|
7743
8216
|
code: 24,
|
|
7744
8217
|
description: "Ensures Effect.Service types are objects, not primitives",
|
|
7745
8218
|
severity: "error",
|
|
8219
|
+
fixable: false,
|
|
8220
|
+
supportedEffect: ["v3"],
|
|
7746
8221
|
apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
|
|
7747
8222
|
const ts = yield* service(TypeScriptApi);
|
|
7748
8223
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -7882,9 +8357,7 @@ var effectModuleMigrationDb = {
|
|
|
7882
8357
|
"failSync": asUnchanged,
|
|
7883
8358
|
"fiberId": asUnchanged,
|
|
7884
8359
|
"filter": asUnchanged,
|
|
7885
|
-
"filterMap":
|
|
7886
|
-
"Use Effect.filter or Effect.map with Option instead."
|
|
7887
|
-
),
|
|
8360
|
+
"filterMap": asUnchanged,
|
|
7888
8361
|
"filterOrElse": asUnchanged,
|
|
7889
8362
|
"filterOrFail": asUnchanged,
|
|
7890
8363
|
"flatMap": asUnchanged,
|
|
@@ -8172,9 +8645,7 @@ var effectModuleMigrationDb = {
|
|
|
8172
8645
|
"finalizersMask": asRemoved(
|
|
8173
8646
|
"Finalizer masking has been removed in Effect v4."
|
|
8174
8647
|
),
|
|
8175
|
-
"findFirst":
|
|
8176
|
-
"Use Effect.forEach with early return instead."
|
|
8177
|
-
),
|
|
8648
|
+
"findFirst": asUnchanged,
|
|
8178
8649
|
"firstSuccessOf": asRemoved(
|
|
8179
8650
|
"Use Effect.raceAll instead."
|
|
8180
8651
|
),
|
|
@@ -8529,6 +9000,8 @@ var outdatedApi = createDiagnostic({
|
|
|
8529
9000
|
code: 48,
|
|
8530
9001
|
description: "Detects usage of APIs that have been removed or renamed in Effect v4",
|
|
8531
9002
|
severity: "warning",
|
|
9003
|
+
fixable: false,
|
|
9004
|
+
supportedEffect: ["v4"],
|
|
8532
9005
|
apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
|
|
8533
9006
|
const typeParser = yield* service(TypeParser);
|
|
8534
9007
|
const ts = yield* service(TypeScriptApi);
|
|
@@ -9665,6 +10138,8 @@ var outdatedEffectCodegen = createDiagnostic({
|
|
|
9665
10138
|
code: 19,
|
|
9666
10139
|
description: "Detects when generated code is outdated and needs to be regenerated",
|
|
9667
10140
|
severity: "warning",
|
|
10141
|
+
fixable: true,
|
|
10142
|
+
supportedEffect: ["v3", "v4"],
|
|
9668
10143
|
apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
|
|
9669
10144
|
const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
|
|
9670
10145
|
for (const { codegen, hash: hash2, range } of codegensWithRanges) {
|
|
@@ -9711,6 +10186,8 @@ var overriddenSchemaConstructor = createDiagnostic({
|
|
|
9711
10186
|
code: 30,
|
|
9712
10187
|
description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
|
|
9713
10188
|
severity: "error",
|
|
10189
|
+
fixable: true,
|
|
10190
|
+
supportedEffect: ["v3", "v4"],
|
|
9714
10191
|
apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
|
|
9715
10192
|
const ts = yield* service(TypeScriptApi);
|
|
9716
10193
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9848,6 +10325,8 @@ var preferSchemaOverJson = createDiagnostic({
|
|
|
9848
10325
|
code: 44,
|
|
9849
10326
|
description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
|
|
9850
10327
|
severity: "suggestion",
|
|
10328
|
+
fixable: false,
|
|
10329
|
+
supportedEffect: ["v3", "v4"],
|
|
9851
10330
|
apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
|
|
9852
10331
|
const ts = yield* service(TypeScriptApi);
|
|
9853
10332
|
const typeParser = yield* service(TypeParser);
|
|
@@ -9958,6 +10437,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
|
|
|
9958
10437
|
code: 42,
|
|
9959
10438
|
description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
|
|
9960
10439
|
severity: "suggestion",
|
|
10440
|
+
fixable: true,
|
|
10441
|
+
supportedEffect: ["v3", "v4"],
|
|
9961
10442
|
apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
|
|
9962
10443
|
const ts = yield* service(TypeScriptApi);
|
|
9963
10444
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10008,6 +10489,8 @@ var returnEffectInGen = createDiagnostic({
|
|
|
10008
10489
|
code: 11,
|
|
10009
10490
|
description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
|
|
10010
10491
|
severity: "suggestion",
|
|
10492
|
+
fixable: true,
|
|
10493
|
+
supportedEffect: ["v3", "v4"],
|
|
10011
10494
|
apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
|
|
10012
10495
|
const ts = yield* service(TypeScriptApi);
|
|
10013
10496
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10077,6 +10560,8 @@ var runEffectInsideEffect = createDiagnostic({
|
|
|
10077
10560
|
code: 32,
|
|
10078
10561
|
description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
|
|
10079
10562
|
severity: "suggestion",
|
|
10563
|
+
fixable: true,
|
|
10564
|
+
supportedEffect: ["v3"],
|
|
10080
10565
|
apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
|
|
10081
10566
|
const ts = yield* service(TypeScriptApi);
|
|
10082
10567
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10201,6 +10686,8 @@ var schemaStructWithTag = createDiagnostic({
|
|
|
10201
10686
|
code: 34,
|
|
10202
10687
|
description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
|
|
10203
10688
|
severity: "suggestion",
|
|
10689
|
+
fixable: true,
|
|
10690
|
+
supportedEffect: ["v3", "v4"],
|
|
10204
10691
|
apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
|
|
10205
10692
|
const ts = yield* service(TypeScriptApi);
|
|
10206
10693
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10293,6 +10780,8 @@ var schemaSyncInEffect = createDiagnostic({
|
|
|
10293
10780
|
code: 43,
|
|
10294
10781
|
description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
|
|
10295
10782
|
severity: "suggestion",
|
|
10783
|
+
fixable: false,
|
|
10784
|
+
supportedEffect: ["v3", "v4"],
|
|
10296
10785
|
apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
|
|
10297
10786
|
const ts = yield* service(TypeScriptApi);
|
|
10298
10787
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10342,6 +10831,8 @@ var schemaUnionOfLiterals = createDiagnostic({
|
|
|
10342
10831
|
code: 33,
|
|
10343
10832
|
description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
|
|
10344
10833
|
severity: "off",
|
|
10834
|
+
fixable: true,
|
|
10835
|
+
supportedEffect: ["v3"],
|
|
10345
10836
|
apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
|
|
10346
10837
|
const ts = yield* service(TypeScriptApi);
|
|
10347
10838
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10417,6 +10908,8 @@ var scopeInLayerEffect = createDiagnostic({
|
|
|
10417
10908
|
code: 13,
|
|
10418
10909
|
description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
|
|
10419
10910
|
severity: "warning",
|
|
10911
|
+
fixable: true,
|
|
10912
|
+
supportedEffect: ["v3"],
|
|
10420
10913
|
apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
|
|
10421
10914
|
const ts = yield* service(TypeScriptApi);
|
|
10422
10915
|
const tsUtils = yield* service(TypeScriptUtils);
|
|
@@ -10506,12 +10999,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
|
|
|
10506
10999
|
})
|
|
10507
11000
|
});
|
|
10508
11001
|
|
|
11002
|
+
// src/diagnostics/serviceNotAsClass.ts
|
|
11003
|
+
var serviceNotAsClass = createDiagnostic({
|
|
11004
|
+
name: "serviceNotAsClass",
|
|
11005
|
+
code: 51,
|
|
11006
|
+
description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
|
|
11007
|
+
severity: "off",
|
|
11008
|
+
fixable: true,
|
|
11009
|
+
supportedEffect: ["v4"],
|
|
11010
|
+
apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
|
|
11011
|
+
const ts = yield* service(TypeScriptApi);
|
|
11012
|
+
const typeParser = yield* service(TypeParser);
|
|
11013
|
+
if (typeParser.supportedEffect() === "v3") return;
|
|
11014
|
+
const nodeToVisit = [];
|
|
11015
|
+
const appendNodeToVisit = (node) => {
|
|
11016
|
+
nodeToVisit.push(node);
|
|
11017
|
+
return void 0;
|
|
11018
|
+
};
|
|
11019
|
+
ts.forEachChild(sourceFile, appendNodeToVisit);
|
|
11020
|
+
while (nodeToVisit.length > 0) {
|
|
11021
|
+
const node = nodeToVisit.shift();
|
|
11022
|
+
ts.forEachChild(node, appendNodeToVisit);
|
|
11023
|
+
if (!ts.isVariableDeclaration(node)) continue;
|
|
11024
|
+
if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
|
|
11025
|
+
const callExpr = node.initializer;
|
|
11026
|
+
if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
|
|
11027
|
+
const typeArgs = callExpr.typeArguments;
|
|
11028
|
+
const declList = node.parent;
|
|
11029
|
+
if (!ts.isVariableDeclarationList(declList)) continue;
|
|
11030
|
+
if (!(declList.flags & ts.NodeFlags.Const)) continue;
|
|
11031
|
+
const isServiceMapService = yield* pipe(
|
|
11032
|
+
typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
|
|
11033
|
+
orUndefined
|
|
11034
|
+
);
|
|
11035
|
+
if (!isServiceMapService) continue;
|
|
11036
|
+
const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
|
|
11037
|
+
const variableStatement = declList.parent;
|
|
11038
|
+
const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
|
|
11039
|
+
const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
|
|
11040
|
+
report({
|
|
11041
|
+
location: callExpr,
|
|
11042
|
+
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, "")}") {}`,
|
|
11043
|
+
fixes: [{
|
|
11044
|
+
fixName: "serviceNotAsClass",
|
|
11045
|
+
description: `Convert to class declaration`,
|
|
11046
|
+
apply: gen(function* () {
|
|
11047
|
+
const changeTracker = yield* service(ChangeTracker);
|
|
11048
|
+
const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
|
|
11049
|
+
const innerCall = ts.factory.createCallExpression(
|
|
11050
|
+
callExpr.expression,
|
|
11051
|
+
[ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
|
|
11052
|
+
[]
|
|
11053
|
+
);
|
|
11054
|
+
const outerCall = ts.factory.createCallExpression(
|
|
11055
|
+
innerCall,
|
|
11056
|
+
void 0,
|
|
11057
|
+
[...callExpr.arguments]
|
|
11058
|
+
);
|
|
11059
|
+
const heritageClause = ts.factory.createHeritageClause(
|
|
11060
|
+
ts.SyntaxKind.ExtendsKeyword,
|
|
11061
|
+
[ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
|
|
11062
|
+
);
|
|
11063
|
+
const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
|
|
11064
|
+
const classDeclaration = ts.factory.createClassDeclaration(
|
|
11065
|
+
modifiers,
|
|
11066
|
+
ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
|
|
11067
|
+
void 0,
|
|
11068
|
+
[heritageClause],
|
|
11069
|
+
[]
|
|
11070
|
+
);
|
|
11071
|
+
changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
|
|
11072
|
+
})
|
|
11073
|
+
}]
|
|
11074
|
+
});
|
|
11075
|
+
}
|
|
11076
|
+
})
|
|
11077
|
+
});
|
|
11078
|
+
|
|
10509
11079
|
// src/diagnostics/strictBooleanExpressions.ts
|
|
10510
11080
|
var strictBooleanExpressions = createDiagnostic({
|
|
10511
11081
|
name: "strictBooleanExpressions",
|
|
10512
11082
|
code: 17,
|
|
10513
11083
|
description: "Enforces boolean types in conditional expressions for type safety",
|
|
10514
11084
|
severity: "off",
|
|
11085
|
+
fixable: false,
|
|
11086
|
+
supportedEffect: ["v3", "v4"],
|
|
10515
11087
|
apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
|
|
10516
11088
|
const ts = yield* service(TypeScriptApi);
|
|
10517
11089
|
const typeChecker = yield* service(TypeCheckerApi);
|
|
@@ -10583,6 +11155,8 @@ var strictEffectProvide = createDiagnostic({
|
|
|
10583
11155
|
code: 27,
|
|
10584
11156
|
description: "Warns when using Effect.provide with layers outside of application entry points",
|
|
10585
11157
|
severity: "off",
|
|
11158
|
+
fixable: false,
|
|
11159
|
+
supportedEffect: ["v3", "v4"],
|
|
10586
11160
|
apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
|
|
10587
11161
|
const ts = yield* service(TypeScriptApi);
|
|
10588
11162
|
const typeCheckerUtils = yield* service(TypeCheckerUtils);
|
|
@@ -10634,6 +11208,8 @@ var tryCatchInEffectGen = createDiagnostic({
|
|
|
10634
11208
|
code: 15,
|
|
10635
11209
|
description: "Discourages try/catch in Effect generators in favor of Effect error handling",
|
|
10636
11210
|
severity: "suggestion",
|
|
11211
|
+
fixable: false,
|
|
11212
|
+
supportedEffect: ["v3", "v4"],
|
|
10637
11213
|
apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
|
|
10638
11214
|
const ts = yield* service(TypeScriptApi);
|
|
10639
11215
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10691,6 +11267,8 @@ var unknownInEffectCatch = createDiagnostic({
|
|
|
10691
11267
|
code: 31,
|
|
10692
11268
|
description: "Warns when catch callbacks return unknown instead of typed errors",
|
|
10693
11269
|
severity: "warning",
|
|
11270
|
+
fixable: false,
|
|
11271
|
+
supportedEffect: ["v3", "v4"],
|
|
10694
11272
|
apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
|
|
10695
11273
|
const ts = yield* service(TypeScriptApi);
|
|
10696
11274
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10752,6 +11330,8 @@ var unnecessaryEffectGen = createDiagnostic({
|
|
|
10752
11330
|
code: 5,
|
|
10753
11331
|
description: "Suggests removing Effect.gen when it contains only a single return statement",
|
|
10754
11332
|
severity: "suggestion",
|
|
11333
|
+
fixable: true,
|
|
11334
|
+
supportedEffect: ["v3", "v4"],
|
|
10755
11335
|
apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
|
|
10756
11336
|
const ts = yield* service(TypeScriptApi);
|
|
10757
11337
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10796,6 +11376,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
|
|
|
10796
11376
|
code: 29,
|
|
10797
11377
|
description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
|
|
10798
11378
|
severity: "suggestion",
|
|
11379
|
+
fixable: true,
|
|
11380
|
+
supportedEffect: ["v3", "v4"],
|
|
10799
11381
|
apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
|
|
10800
11382
|
const ts = yield* service(TypeScriptApi);
|
|
10801
11383
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10855,6 +11437,8 @@ var unnecessaryPipe = createDiagnostic({
|
|
|
10855
11437
|
code: 9,
|
|
10856
11438
|
description: "Removes pipe calls with no arguments",
|
|
10857
11439
|
severity: "suggestion",
|
|
11440
|
+
fixable: true,
|
|
11441
|
+
supportedEffect: ["v3", "v4"],
|
|
10858
11442
|
apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
|
|
10859
11443
|
const ts = yield* service(TypeScriptApi);
|
|
10860
11444
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10901,6 +11485,8 @@ var unnecessaryPipeChain = createDiagnostic({
|
|
|
10901
11485
|
code: 16,
|
|
10902
11486
|
description: "Simplifies chained pipe calls into a single pipe call",
|
|
10903
11487
|
severity: "suggestion",
|
|
11488
|
+
fixable: true,
|
|
11489
|
+
supportedEffect: ["v3", "v4"],
|
|
10904
11490
|
apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
|
|
10905
11491
|
const ts = yield* service(TypeScriptApi);
|
|
10906
11492
|
const typeParser = yield* service(TypeParser);
|
|
@@ -10976,6 +11562,8 @@ var unsupportedServiceAccessors = createDiagnostic({
|
|
|
10976
11562
|
code: 21,
|
|
10977
11563
|
description: "Warns about service accessors that need codegen due to generic/complex signatures",
|
|
10978
11564
|
severity: "warning",
|
|
11565
|
+
fixable: true,
|
|
11566
|
+
supportedEffect: ["v3", "v4"],
|
|
10979
11567
|
apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
|
|
10980
11568
|
const ts = yield* service(TypeScriptApi);
|
|
10981
11569
|
const nodeToVisit = [];
|
|
@@ -11042,6 +11630,7 @@ var diagnostics = [
|
|
|
11042
11630
|
missingEffectServiceDependency,
|
|
11043
11631
|
missingLayerContext,
|
|
11044
11632
|
floatingEffect,
|
|
11633
|
+
effectInFailure,
|
|
11045
11634
|
missingStarInYieldEffectGen,
|
|
11046
11635
|
unnecessaryEffectGen,
|
|
11047
11636
|
unnecessaryFailYieldableError,
|
|
@@ -11077,7 +11666,10 @@ var diagnostics = [
|
|
|
11077
11666
|
effectFnOpportunity,
|
|
11078
11667
|
redundantSchemaTagIdentifier,
|
|
11079
11668
|
schemaSyncInEffect,
|
|
11080
|
-
preferSchemaOverJson
|
|
11669
|
+
preferSchemaOverJson,
|
|
11670
|
+
extendsNativeError,
|
|
11671
|
+
serviceNotAsClass,
|
|
11672
|
+
nodeBuiltinImport
|
|
11081
11673
|
];
|
|
11082
11674
|
|
|
11083
11675
|
// src/transform.ts
|