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