@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.
@@ -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.14/node_modules/effect/dist/Pipeable.js
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.14/node_modules/effect/dist/Function.js
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.14/node_modules/effect/dist/internal/equal.js
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.14/node_modules/effect/dist/Predicate.js
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.14/node_modules/effect/dist/Hash.js
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.14/node_modules/effect/dist/Equal.js
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.14/node_modules/effect/dist/Redactable.js
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.14/node_modules/effect/dist/Formatter.js
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.14/node_modules/effect/dist/Inspectable.js
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.14/node_modules/effect/dist/Utils.js
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.14/node_modules/effect/dist/internal/core.js
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.14/node_modules/effect/dist/internal/option.js
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.14/node_modules/effect/dist/internal/result.js
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.14/node_modules/effect/dist/Order.js
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.14/node_modules/effect/dist/Option.js
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.14/node_modules/effect/dist/Result.js
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.14/node_modules/effect/dist/Filter.js
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.14/node_modules/effect/dist/Array.js
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, f) => {
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
- const result = apply(f, as[i], i);
1244
- if (!isFailure2(result)) {
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((_) => _.toLowerCase()) : defaults.effectFn,
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, traceName, nameIdentifier) {
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: traceName,
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 TypeParserIssue.issue;
6149
+ return;
5912
6150
  }
5913
6151
  if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
5914
- return TypeParserIssue.issue;
6152
+ return;
5915
6153
  }
5916
6154
  if (ts.isFunctionExpression(node) && node.name) {
5917
- return TypeParserIssue.issue;
6155
+ return;
5918
6156
  }
5919
6157
  if (node.type) {
5920
- return TypeParserIssue.issue;
6158
+ return;
5921
6159
  }
5922
6160
  const functionType = typeChecker.getTypeAtLocation(node);
5923
- if (!functionType) return TypeParserIssue.issue;
6161
+ if (!functionType) return;
5924
6162
  const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
5925
- if (callSignatures.length !== 1) return TypeParserIssue.issue;
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
- const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
5930
- if (!traceName) return TypeParserIssue.issue;
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 target = yield* pipe(parseEffectFnOpportunityTarget(node), option);
6006
- if (isNone2(target)) continue;
6007
- if (target.value.hasParamsInPipeArgs) continue;
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
- } = target.value;
6016
- const innerFunction = target.value.generatorFunction ?? targetNode;
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.value.generatorFunction) {
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 (pluginOptions.effectFn.includes("inferred-span") && inferredTraceName && !explicitTraceExpression) {
6059
- fixes.push({
6060
- fixName: "effectFnOpportunity_toEffectFnSpanInferred",
6061
- description: `Convert to Effect.fn("${inferredTraceName}")`,
6062
- apply: gen(function* () {
6063
- const changeTracker = yield* service(ChangeTracker);
6064
- const newNode = createEffectFnNode(
6065
- targetNode,
6066
- innerFunction,
6067
- effectModuleName,
6068
- inferredTraceName,
6069
- pipeArguments2
6070
- );
6071
- changeTracker.replaceNode(sourceFile, targetNode, newNode);
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.isYieldExpression(node) && node.expression && node.asteriskToken) {
7530
- const type = typeCheckerUtils.getTypeAtLocation(node.expression);
7531
- if (type) {
7532
- const maybeEffect = yield* option(typeParser.effectType(type, node.expression));
7533
- if (isSome2(maybeEffect) && maybeEffect.value.A.flags & ts.TypeFlags.Never) {
7534
- const generatorFunctionOrReturnStatement = ts.findAncestor(
7535
- node,
7536
- (_) => ts.isFunctionExpression(_) || ts.isFunctionDeclaration(_) || ts.isMethodDeclaration(_) || ts.isReturnStatement(_) || ts.isThrowStatement(_)
7537
- );
7538
- if (generatorFunctionOrReturnStatement && !ts.isReturnStatement(generatorFunctionOrReturnStatement) && !ts.isThrowStatement(generatorFunctionOrReturnStatement)) {
7539
- if (generatorFunctionOrReturnStatement && generatorFunctionOrReturnStatement.parent) {
7540
- const effectGenNode = generatorFunctionOrReturnStatement.parent;
7541
- const effectGenLike = yield* pipe(
7542
- typeParser.effectGen(effectGenNode),
7543
- orElse2(() => typeParser.effectFnUntracedGen(effectGenNode)),
7544
- orElse2(() => typeParser.effectFnGen(effectGenNode)),
7545
- option
7546
- );
7547
- if (isSome2(effectGenLike)) {
7548
- const fix = node.expression ? [{
7549
- fixName: "missingReturnYieldStar_fix",
7550
- description: "Add return statement",
7551
- apply: gen(function* () {
7552
- const changeTracker = yield* service(ChangeTracker);
7553
- changeTracker.replaceNode(
7554
- sourceFile,
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": asRemoved(
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": asRemoved(
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: