@effect/language-service 0.84.3 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Pipeable.js
3
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Pipeable.js
4
4
  var pipeArguments = (self, args3) => {
5
5
  switch (args3.length) {
6
6
  case 0:
@@ -44,7 +44,7 @@ var Class = /* @__PURE__ */ (function() {
44
44
  return PipeableBase;
45
45
  })();
46
46
 
47
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Function.js
47
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Function.js
48
48
  var dual = function(arity, body) {
49
49
  if (typeof arity === "function") {
50
50
  return function() {
@@ -92,9 +92,9 @@ function pipe(a, ...args3) {
92
92
  return pipeArguments(a, args3);
93
93
  }
94
94
 
95
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Equivalence.js
95
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Equivalence.js
96
96
  var make = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that);
97
- function Array2(item) {
97
+ function Array_(item) {
98
98
  return make((self, that) => {
99
99
  if (self.length !== that.length) return false;
100
100
  for (let i = 0; i < self.length; i++) {
@@ -104,7 +104,7 @@ function Array2(item) {
104
104
  });
105
105
  }
106
106
 
107
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/internal/equal.js
107
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/equal.js
108
108
  var getAllObjectKeys = (obj) => {
109
109
  const keys2 = new Set(Reflect.ownKeys(obj));
110
110
  if (obj.constructor === Object) return keys2;
@@ -127,7 +127,7 @@ var getAllObjectKeys = (obj) => {
127
127
  };
128
128
  var byReferenceInstances = /* @__PURE__ */ new WeakSet();
129
129
 
130
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Predicate.js
130
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Predicate.js
131
131
  function isString(input) {
132
132
  return typeof input === "string";
133
133
  }
@@ -148,7 +148,7 @@ function isObjectKeyword(input) {
148
148
  }
149
149
  var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObjectKeyword(self) && property in self);
150
150
 
151
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Hash.js
151
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Hash.js
152
152
  var symbol = "~effect/interfaces/Hash";
153
153
  var hash = (self) => {
154
154
  switch (typeof self) {
@@ -267,7 +267,7 @@ function withVisitedTracking(obj, fn2) {
267
267
  return result;
268
268
  }
269
269
 
270
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Equal.js
270
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Equal.js
271
271
  var symbol2 = "~effect/interfaces/Equal";
272
272
  function equals() {
273
273
  if (arguments.length === 1) {
@@ -429,7 +429,7 @@ var compareSets = /* @__PURE__ */ makeCompareSet(compareBoth);
429
429
  var isEqual = (u) => hasProperty(u, symbol2);
430
430
  var asEquivalence = () => equals;
431
431
 
432
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Redactable.js
432
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Redactable.js
433
433
  var symbolRedactable = /* @__PURE__ */ Symbol.for("~effect/Inspectable/redactable");
434
434
  var isRedactable = (u) => hasProperty(u, symbolRedactable);
435
435
  function redact(u) {
@@ -448,7 +448,7 @@ var emptyServiceMap = {
448
448
  }
449
449
  };
450
450
 
451
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Formatter.js
451
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Formatter.js
452
452
  function format(input, options) {
453
453
  const space = options?.space ?? 0;
454
454
  const seen = /* @__PURE__ */ new WeakSet();
@@ -527,7 +527,7 @@ function safeToString(input) {
527
527
  }
528
528
  }
529
529
 
530
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Inspectable.js
530
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Inspectable.js
531
531
  var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
532
532
  var toJson = (input) => {
533
533
  try {
@@ -571,7 +571,7 @@ var Class2 = class {
571
571
  }
572
572
  };
573
573
 
574
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Utils.js
574
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Utils.js
575
575
  var SingleShotGen = class _SingleShotGen {
576
576
  called = false;
577
577
  self;
@@ -614,7 +614,7 @@ var forced = {
614
614
  var isNotOptimizedAway = /* @__PURE__ */ standard[InternalTypeId](() => new Error().stack)?.includes(InternalTypeId) === true;
615
615
  var internalCall = isNotOptimizedAway ? standard[InternalTypeId] : forced[InternalTypeId];
616
616
 
617
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/internal/core.js
617
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/core.js
618
618
  var EffectTypeId = `~effect/Effect`;
619
619
  var ExitTypeId = `~effect/Exit`;
620
620
  var effectVariance = {
@@ -961,7 +961,7 @@ var DoneVoid = {
961
961
  value: void 0
962
962
  };
963
963
 
964
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/internal/option.js
964
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/option.js
965
965
  var TypeId = "~effect/data/Option";
966
966
  var CommonProto = {
967
967
  [TypeId]: {
@@ -1032,7 +1032,7 @@ var some = (value) => {
1032
1032
  return a;
1033
1033
  };
1034
1034
 
1035
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/internal/result.js
1035
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/result.js
1036
1036
  var TypeId2 = "~effect/data/Result";
1037
1037
  var CommonProto2 = {
1038
1038
  [TypeId2]: {
@@ -1103,7 +1103,7 @@ var succeed = (success) => {
1103
1103
  return a;
1104
1104
  };
1105
1105
 
1106
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Result.js
1106
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Result.js
1107
1107
  var succeed2 = succeed;
1108
1108
  var fail2 = fail;
1109
1109
  var isFailure2 = isFailure;
@@ -1111,10 +1111,10 @@ var isSuccess2 = isSuccess;
1111
1111
  var map = /* @__PURE__ */ dual(2, (self, f) => isSuccess2(self) ? succeed2(f(self.success)) : fail2(self.failure));
1112
1112
  var getOrElse = /* @__PURE__ */ dual(2, (self, onFailure) => isFailure2(self) ? onFailure(self.failure) : self.success);
1113
1113
 
1114
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/internal/array.js
1114
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/internal/array.js
1115
1115
  var isArrayNonEmpty = (self) => self.length > 0;
1116
1116
 
1117
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Order.js
1117
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Order.js
1118
1118
  function make2(compare) {
1119
1119
  return (self, that) => self === that ? 0 : compare(self, that);
1120
1120
  }
@@ -1137,7 +1137,7 @@ var combine2 = /* @__PURE__ */ dual(2, (self, that) => make2((a1, a2) => {
1137
1137
  }));
1138
1138
  var mapInput = /* @__PURE__ */ dual(2, (self, f) => make2((b1, b2) => self(f(b1), f(b2))));
1139
1139
 
1140
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Option.js
1140
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Option.js
1141
1141
  var none2 = () => none;
1142
1142
  var some2 = some;
1143
1143
  var isNone2 = isNone;
@@ -1148,7 +1148,7 @@ var fromNullishOr = (a) => a == null ? none2() : some2(a);
1148
1148
  var getOrUndefined = /* @__PURE__ */ getOrElse2(constUndefined);
1149
1149
  var map2 = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : some2(f(self.value)));
1150
1150
 
1151
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Record.js
1151
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Record.js
1152
1152
  var map3 = /* @__PURE__ */ dual(2, (self, f) => {
1153
1153
  const out = {
1154
1154
  ...self
@@ -1160,12 +1160,12 @@ var map3 = /* @__PURE__ */ dual(2, (self, f) => {
1160
1160
  });
1161
1161
  var keys = (self) => Object.keys(self);
1162
1162
 
1163
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Array.js
1164
- var Array3 = globalThis.Array;
1165
- var fromIterable = (collection) => Array3.isArray(collection) ? collection : Array3.from(collection);
1163
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Array.js
1164
+ var Array2 = globalThis.Array;
1165
+ var fromIterable = (collection) => Array2.isArray(collection) ? collection : Array2.from(collection);
1166
1166
  var append = /* @__PURE__ */ dual(2, (self, last) => [...self, last]);
1167
1167
  var appendAll = /* @__PURE__ */ dual(2, (self, that) => fromIterable(self).concat(fromIterable(that)));
1168
- var isArray = Array3.isArray;
1168
+ var isArray = Array2.isArray;
1169
1169
  var isArrayEmpty = (self) => self.length === 0;
1170
1170
  var isReadonlyArrayEmpty = isArrayEmpty;
1171
1171
  var isReadonlyArrayNonEmpty = isArrayNonEmpty;
@@ -1187,7 +1187,7 @@ var head = /* @__PURE__ */ get(0);
1187
1187
  var headNonEmpty = /* @__PURE__ */ getUnsafe(0);
1188
1188
  var tailNonEmpty = (self) => self.slice(1);
1189
1189
  var sort = /* @__PURE__ */ dual(2, (self, O) => {
1190
- const out = Array3.from(self);
1190
+ const out = Array2.from(self);
1191
1191
  out.sort(O);
1192
1192
  return out;
1193
1193
  });
@@ -1251,7 +1251,7 @@ var dedupeWith = /* @__PURE__ */ dual(2, (self, isEquivalent) => {
1251
1251
  var dedupe = (self) => dedupeWith(self, asEquivalence());
1252
1252
  var join = /* @__PURE__ */ dual(2, (self, sep) => fromIterable(self).join(sep));
1253
1253
 
1254
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Data.js
1254
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Data.js
1255
1255
  var Class3 = class extends Class {
1256
1256
  constructor(props) {
1257
1257
  super();
@@ -1262,7 +1262,7 @@ var Class3 = class extends Class {
1262
1262
  };
1263
1263
  var TaggedError2 = TaggedError;
1264
1264
 
1265
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Encoding.js
1265
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Encoding.js
1266
1266
  var EncodingErrorTypeId = "~effect/encoding/EncodingError";
1267
1267
  var EncodingError = class extends (/* @__PURE__ */ TaggedError2("EncodingError")) {
1268
1268
  /**
@@ -1298,7 +1298,7 @@ var base64EncodeUint8Array = (bytes) => {
1298
1298
  var base64abc = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"];
1299
1299
  var base64UrlEncodeUint8Array = (data) => base64EncodeUint8Array(data).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
1300
1300
 
1301
- // ../../node_modules/.pnpm/effect@4.0.0-beta.38/node_modules/effect/dist/Graph.js
1301
+ // ../../node_modules/.pnpm/effect@4.0.0-beta.43/node_modules/effect/dist/Graph.js
1302
1302
  var TypeId3 = "~effect/collections/Graph";
1303
1303
  var Edge = class extends Class3 {
1304
1304
  };
@@ -4770,33 +4770,33 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4770
4770
  ),
4771
4771
  ([Identifier, Service]) => ({ Identifier, Service })
4772
4772
  );
4773
- const serviceVarianceStruct = (type, atLocation) => map5(
4774
- all(
4775
- varianceStructInvariantType(type, atLocation, "_Identifier"),
4776
- varianceStructInvariantType(type, atLocation, "_Service")
4777
- ),
4778
- ([Identifier, Service]) => ({ Identifier, Service })
4779
- );
4780
4773
  const serviceType = cachedBy(
4781
4774
  fn("TypeParser.serviceType")(function* (type, atLocation) {
4775
+ if (supportedEffect() !== "v4") return yield* typeParserIssue("v4 only");
4782
4776
  yield* pipeableType(type, atLocation);
4783
- const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
4784
- (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
4785
- );
4786
- if (propertiesSymbols.length === 0) {
4787
- return yield* typeParserIssue("Type has no tag variance struct", type, atLocation);
4777
+ const typeIdSymbol = typeChecker.getPropertyOfType(type, "~effect/ServiceMap/Service");
4778
+ if (!typeIdSymbol) {
4779
+ return yield* typeParserIssue("Type has no service key type id", type, atLocation);
4788
4780
  }
4789
- propertiesSymbols.sort((a, b) => ts.symbolName(b).indexOf("TypeId") - ts.symbolName(a).indexOf("TypeId"));
4790
- return yield* firstSuccessOf(propertiesSymbols.map((propertySymbol) => {
4791
- const propertyType = typeChecker.getTypeOfSymbolAtLocation(propertySymbol, atLocation);
4792
- return serviceVarianceStruct(propertyType, atLocation);
4793
- }));
4781
+ const identifierSymbol = typeChecker.getPropertyOfType(type, "Identifier");
4782
+ if (!identifierSymbol) {
4783
+ return yield* typeParserIssue("Type has no 'Identifier' property", type, atLocation);
4784
+ }
4785
+ const serviceSymbol = typeChecker.getPropertyOfType(type, "Service");
4786
+ if (!serviceSymbol) {
4787
+ return yield* typeParserIssue("Type has no 'Service' property", type, atLocation);
4788
+ }
4789
+ return {
4790
+ Identifier: typeChecker.getTypeOfSymbolAtLocation(identifierSymbol, atLocation),
4791
+ Service: typeChecker.getTypeOfSymbolAtLocation(serviceSymbol, atLocation)
4792
+ };
4794
4793
  }),
4795
4794
  "TypeParser.serviceType",
4796
4795
  (type) => type
4797
4796
  );
4798
4797
  const contextTag = cachedBy(
4799
4798
  fn("TypeParser.contextTag")(function* (type, atLocation) {
4799
+ if (supportedEffect() !== "v3") return yield* typeParserIssue("v3 only");
4800
4800
  yield* pipeableType(type, atLocation);
4801
4801
  const propertiesSymbols = typeChecker.getPropertiesOfType(type).filter(
4802
4802
  (_) => _.flags & ts.SymbolFlags.Property && !(_.flags & ts.SymbolFlags.Optional) && _.valueDeclaration
@@ -4937,6 +4937,19 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
4937
4937
  "TypeParser.promiseLike",
4938
4938
  (type) => type
4939
4939
  );
4940
+ const promiseType = cachedBy(
4941
+ function(type, atLocation) {
4942
+ const promiseSymbol = typeChecker.resolveName("Promise", void 0, ts.SymbolFlags.Type, false);
4943
+ if (!promiseSymbol) return typeParserIssue("global Promise type not found", type, atLocation);
4944
+ const globalPromiseType = typeChecker.getDeclaredTypeOfSymbol(promiseSymbol);
4945
+ if (type === globalPromiseType || "target" in type && type.target === globalPromiseType || typeChecker.isTypeAssignableTo(type, globalPromiseType)) {
4946
+ return succeed3(type);
4947
+ }
4948
+ return typeParserIssue("type is not a Promise", type, atLocation);
4949
+ },
4950
+ "TypeParser.promiseType",
4951
+ (type) => type
4952
+ );
4940
4953
  const extendsSchemaClass = cachedBy(
4941
4954
  fn("TypeParser.extendsSchemaClass")(function* (atLocation) {
4942
4955
  if (!atLocation.name) {
@@ -5956,6 +5969,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
5956
5969
  singleArgCall,
5957
5970
  scopeType,
5958
5971
  promiseLike,
5972
+ promiseType,
5959
5973
  extendsEffectTag,
5960
5974
  extendsEffectService,
5961
5975
  extendsServiceMapService,
@@ -7315,6 +7329,37 @@ var anyUnknownInErrorContext = createDiagnostic({
7315
7329
  })
7316
7330
  });
7317
7331
 
7332
+ // src/diagnostics/asyncFunction.ts
7333
+ var asyncFunction = createDiagnostic({
7334
+ name: "asyncFunction",
7335
+ code: 69,
7336
+ description: "Warns when declaring async functions and suggests using Effect values and Effect.gen for async control flow",
7337
+ group: "effectNative",
7338
+ severity: "off",
7339
+ fixable: false,
7340
+ supportedEffect: ["v3", "v4"],
7341
+ apply: fn("asyncFunction.apply")(function* (sourceFile, report) {
7342
+ const ts = yield* service(TypeScriptApi);
7343
+ const hasAsyncModifier = (node) => ts.getModifiers(node)?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) === true;
7344
+ const visit = (node) => {
7345
+ if (!ts.isFunctionDeclaration(node) && !ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isMethodDeclaration(node)) {
7346
+ ts.forEachChild(node, visit);
7347
+ return void 0;
7348
+ }
7349
+ if (hasAsyncModifier(node)) {
7350
+ report({
7351
+ location: node,
7352
+ messageText: "This code declares an async function, consider representing this async control flow with Effect values and `Effect.gen`.",
7353
+ fixes: []
7354
+ });
7355
+ }
7356
+ ts.forEachChild(node, visit);
7357
+ return void 0;
7358
+ };
7359
+ ts.forEachChild(sourceFile, visit);
7360
+ })
7361
+ });
7362
+
7318
7363
  // src/diagnostics/catchAllToMapError.ts
7319
7364
  var catchAllToMapError = createDiagnostic({
7320
7365
  name: "catchAllToMapError",
@@ -7543,6 +7588,59 @@ var classSelfMismatch = createDiagnostic({
7543
7588
  })
7544
7589
  });
7545
7590
 
7591
+ // src/diagnostics/cryptoRandomUUIDInEffect.ts
7592
+ var makeCryptoRandomUUIDApply = (checkInEffect) => fn(`cryptoRandomUUID${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
7593
+ const ts = yield* service(TypeScriptApi);
7594
+ const typeChecker = yield* service(TypeCheckerApi);
7595
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
7596
+ const typeParser = yield* service(TypeParser);
7597
+ const cryptoSymbol = typeChecker.resolveName("crypto", void 0, ts.SymbolFlags.Value, false);
7598
+ if (!cryptoSymbol) return;
7599
+ const nodeToVisit = [];
7600
+ const appendNodeToVisit = (node) => {
7601
+ nodeToVisit.push(node);
7602
+ return void 0;
7603
+ };
7604
+ ts.forEachChild(sourceFile, appendNodeToVisit);
7605
+ while (nodeToVisit.length > 0) {
7606
+ const node = nodeToVisit.shift();
7607
+ ts.forEachChild(node, appendNodeToVisit);
7608
+ if (!ts.isCallExpression(node) || !ts.isPropertyAccessExpression(node.expression) || ts.idText(node.expression.name) !== "randomUUID") continue;
7609
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression.expression);
7610
+ if (!symbol3) continue;
7611
+ if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== cryptoSymbol) continue;
7612
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
7613
+ if (inEffect !== checkInEffect) continue;
7614
+ report({
7615
+ location: node,
7616
+ messageText: checkInEffect ? "This Effect code uses `crypto.randomUUID()`, prefer the Effect `Random` module instead because it uses Effect-injected randomness rather than the `crypto` module behind the scenes." : "This code uses `crypto.randomUUID()`, prefer the Effect `Random` module instead because it uses Effect-injected randomness rather than the `crypto` module behind the scenes.",
7617
+ fixes: []
7618
+ });
7619
+ }
7620
+ });
7621
+ var cryptoRandomUUIDInEffect = createDiagnostic({
7622
+ name: "cryptoRandomUUIDInEffect",
7623
+ code: 67,
7624
+ description: "Warns when using crypto.randomUUID() inside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenes",
7625
+ group: "effectNative",
7626
+ severity: "off",
7627
+ fixable: false,
7628
+ supportedEffect: ["v4"],
7629
+ apply: makeCryptoRandomUUIDApply(true)
7630
+ });
7631
+
7632
+ // src/diagnostics/cryptoRandomUUID.ts
7633
+ var cryptoRandomUUID = createDiagnostic({
7634
+ name: "cryptoRandomUUID",
7635
+ code: 66,
7636
+ description: "Warns when using crypto.randomUUID() outside Effect generators instead of the Effect Random module, which uses Effect-injected randomness rather than the crypto module behind the scenes",
7637
+ group: "effectNative",
7638
+ severity: "off",
7639
+ fixable: false,
7640
+ supportedEffect: ["v4"],
7641
+ apply: makeCryptoRandomUUIDApply(false)
7642
+ });
7643
+
7546
7644
  // src/diagnostics/deterministicKeys.ts
7547
7645
  var deterministicKeys = createDiagnostic({
7548
7646
  name: "deterministicKeys",
@@ -7694,6 +7792,40 @@ ${versions.map((version) => `- found ${version} at ${resolvedPackages[packageNam
7694
7792
  })
7695
7793
  });
7696
7794
 
7795
+ // src/diagnostics/effectDoNotation.ts
7796
+ var effectDoNotation = createDiagnostic({
7797
+ name: "effectDoNotation",
7798
+ code: 73,
7799
+ description: "Suggests using Effect.gen or Effect.fn instead of the Effect.Do notation helpers",
7800
+ group: "style",
7801
+ severity: "off",
7802
+ fixable: false,
7803
+ supportedEffect: ["v3", "v4"],
7804
+ apply: fn("effectDoNotation.apply")(function* (sourceFile, report) {
7805
+ const ts = yield* service(TypeScriptApi);
7806
+ const typeParser = yield* service(TypeParser);
7807
+ const nodeToVisit = [];
7808
+ const appendNodeToVisit = (node) => {
7809
+ nodeToVisit.push(node);
7810
+ return void 0;
7811
+ };
7812
+ ts.forEachChild(sourceFile, appendNodeToVisit);
7813
+ while (nodeToVisit.length > 0) {
7814
+ const node = nodeToVisit.shift();
7815
+ const isReference = yield* orUndefined(typeParser.isNodeReferenceToEffectModuleApi("Do")(node));
7816
+ if (isReference) {
7817
+ report({
7818
+ location: node,
7819
+ messageText: "This uses the Effect do emulation. `Effect.gen` or `Effect.fn` achieve the same result with native JS scopes.",
7820
+ fixes: []
7821
+ });
7822
+ continue;
7823
+ }
7824
+ ts.forEachChild(node, appendNodeToVisit);
7825
+ }
7826
+ })
7827
+ });
7828
+
7697
7829
  // src/diagnostics/effectFnIife.ts
7698
7830
  var effectFnIife = createDiagnostic({
7699
7831
  name: "effectFnIife",
@@ -8640,6 +8772,43 @@ var effectInVoidSuccess = createDiagnostic({
8640
8772
  })
8641
8773
  });
8642
8774
 
8775
+ // src/diagnostics/effectMapFlatten.ts
8776
+ var effectMapFlatten = createDiagnostic({
8777
+ name: "effectMapFlatten",
8778
+ code: 74,
8779
+ description: "Suggests using Effect.flatMap instead of Effect.map followed by Effect.flatten in piping flows",
8780
+ group: "style",
8781
+ severity: "suggestion",
8782
+ fixable: false,
8783
+ supportedEffect: ["v3", "v4"],
8784
+ apply: fn("effectMapFlatten.apply")(function* (sourceFile, report) {
8785
+ const typeParser = yield* service(TypeParser);
8786
+ const flows = yield* typeParser.pipingFlows(false)(sourceFile);
8787
+ for (const flow2 of flows) {
8788
+ for (let index = 0; index < flow2.transformations.length - 1; index++) {
8789
+ const mapTransformation = flow2.transformations[index];
8790
+ const flattenTransformation = flow2.transformations[index + 1];
8791
+ if (!mapTransformation || !flattenTransformation || !mapTransformation?.args || flattenTransformation?.args || mapTransformation.kind !== "pipe" && mapTransformation.kind !== "pipeable" || flattenTransformation.kind !== mapTransformation.kind) {
8792
+ continue;
8793
+ }
8794
+ const isMapCall = yield* orUndefined(
8795
+ typeParser.isNodeReferenceToEffectModuleApi("map")(mapTransformation.callee)
8796
+ );
8797
+ const isFlattenCall = yield* orUndefined(
8798
+ typeParser.isNodeReferenceToEffectModuleApi("flatten")(flattenTransformation.callee)
8799
+ );
8800
+ if (isMapCall && isFlattenCall) {
8801
+ report({
8802
+ location: flattenTransformation.callee,
8803
+ messageText: "`Effect.map` + `Effect.flatten` is the same as `Effect.flatMap` that expresses the same steps more directly.",
8804
+ fixes: []
8805
+ });
8806
+ }
8807
+ }
8808
+ }
8809
+ })
8810
+ });
8811
+
8643
8812
  // src/diagnostics/effectMapVoid.ts
8644
8813
  var effectMapVoid = createDiagnostic({
8645
8814
  name: "effectMapVoid",
@@ -8907,6 +9076,7 @@ var genericEffectServices = createDiagnostic({
8907
9076
  for (const [type, reportAt] of typesToCheck) {
8908
9077
  yield* pipe(
8909
9078
  typeParser.contextTag(type, node),
9079
+ orElse2(() => typeParser.serviceType(type, node)),
8910
9080
  map5(() => {
8911
9081
  report({
8912
9082
  location: reportAt,
@@ -9670,6 +9840,55 @@ var layerMergeAllWithDependencies = createDiagnostic({
9670
9840
  })
9671
9841
  });
9672
9842
 
9843
+ // src/diagnostics/lazyPromiseInEffectSync.ts
9844
+ var lazyPromiseInEffectSync = createDiagnostic({
9845
+ name: "lazyPromiseInEffectSync",
9846
+ code: 70,
9847
+ description: "Warns when Effect.sync lazily returns a Promise instead of using an async Effect constructor",
9848
+ group: "antipattern",
9849
+ severity: "warning",
9850
+ fixable: false,
9851
+ supportedEffect: ["v3", "v4"],
9852
+ apply: fn("lazyPromiseInEffectSync.apply")(function* (sourceFile, report) {
9853
+ const ts = yield* service(TypeScriptApi);
9854
+ const typeChecker = yield* service(TypeCheckerApi);
9855
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
9856
+ const typeParser = yield* service(TypeParser);
9857
+ const nodeToVisit = [];
9858
+ const appendNodeToVisit = (node) => {
9859
+ nodeToVisit.push(node);
9860
+ return void 0;
9861
+ };
9862
+ ts.forEachChild(sourceFile, appendNodeToVisit);
9863
+ while (nodeToVisit.length > 0) {
9864
+ const node = nodeToVisit.shift();
9865
+ ts.forEachChild(node, appendNodeToVisit);
9866
+ if (!ts.isCallExpression(node)) continue;
9867
+ const isSyncCall = yield* orUndefined(
9868
+ typeParser.isNodeReferenceToEffectModuleApi("sync")(node.expression)
9869
+ );
9870
+ if (!isSyncCall) continue;
9871
+ const lazyArg = node.arguments[0];
9872
+ if (!lazyArg) continue;
9873
+ const lazyArgType = typeCheckerUtils.getTypeAtLocation(lazyArg);
9874
+ if (!lazyArgType) continue;
9875
+ const entries2 = typeCheckerUtils.unrollUnionMembers(lazyArgType).flatMap(
9876
+ (member) => typeChecker.getSignaturesOfType(member, ts.SignatureKind.Call).map(
9877
+ (signature) => typeParser.promiseType(typeChecker.getReturnTypeOfSignature(signature), lazyArg)
9878
+ )
9879
+ );
9880
+ if (entries2.length === 0) continue;
9881
+ const promiseReturn = yield* orUndefined(firstSuccessOf(entries2));
9882
+ if (!promiseReturn) continue;
9883
+ report({
9884
+ location: lazyArg,
9885
+ messageText: "This `Effect.sync` thunk returns a Promise. Use `Effect.promise` or `Effect.tryPromise` to represent async work.",
9886
+ fixes: []
9887
+ });
9888
+ }
9889
+ })
9890
+ });
9891
+
9673
9892
  // src/diagnostics/leakingRequirements.ts
9674
9893
  var leakingRequirements = createDiagnostic({
9675
9894
  name: "leakingRequirements",
@@ -10603,6 +10822,74 @@ var multipleEffectProvide = createDiagnostic({
10603
10822
  })
10604
10823
  });
10605
10824
 
10825
+ // src/diagnostics/nestedEffectGenYield.ts
10826
+ var nestedEffectGenYield = createDiagnostic({
10827
+ name: "nestedEffectGenYield",
10828
+ code: 71,
10829
+ description: "Warns when yielding a nested bare Effect.gen inside an existing Effect generator context",
10830
+ group: "style",
10831
+ severity: "off",
10832
+ fixable: false,
10833
+ supportedEffect: ["v3", "v4"],
10834
+ apply: fn("nestedEffectGenYield.apply")(function* (sourceFile, report) {
10835
+ const ts = yield* service(TypeScriptApi);
10836
+ const typeParser = yield* service(TypeParser);
10837
+ const nodeToVisit = [];
10838
+ const appendNodeToVisit = (node) => {
10839
+ nodeToVisit.push(node);
10840
+ return void 0;
10841
+ };
10842
+ ts.forEachChild(sourceFile, appendNodeToVisit);
10843
+ while (nodeToVisit.length > 0) {
10844
+ const node = nodeToVisit.shift();
10845
+ ts.forEachChild(node, appendNodeToVisit);
10846
+ if (!ts.isYieldExpression(node) || !node.asteriskToken || !node.expression) continue;
10847
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
10848
+ if (!inEffect) continue;
10849
+ const bareNestedEffectGen = yield* orUndefined(typeParser.effectGen(node.expression));
10850
+ if (!bareNestedEffectGen) continue;
10851
+ report({
10852
+ location: node.expression,
10853
+ messageText: "This `yield*` is applied to a nested `Effect.gen(...)` that can be inlined in the parent Effect generator context.",
10854
+ fixes: []
10855
+ });
10856
+ }
10857
+ })
10858
+ });
10859
+
10860
+ // src/diagnostics/newPromise.ts
10861
+ var newPromise = createDiagnostic({
10862
+ name: "newPromise",
10863
+ code: 68,
10864
+ description: "Warns when constructing promises with new Promise instead of using Effect APIs",
10865
+ group: "effectNative",
10866
+ severity: "off",
10867
+ fixable: false,
10868
+ supportedEffect: ["v3", "v4"],
10869
+ apply: fn("newPromise.apply")(function* (sourceFile, report) {
10870
+ const ts = yield* service(TypeScriptApi);
10871
+ const typeChecker = yield* service(TypeCheckerApi);
10872
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
10873
+ const promiseSymbol = typeChecker.resolveName("Promise", void 0, ts.SymbolFlags.Value, false);
10874
+ if (!promiseSymbol) return;
10875
+ const visit = (node) => {
10876
+ if (ts.isNewExpression(node)) {
10877
+ const symbol3 = typeChecker.getSymbolAtLocation(node.expression);
10878
+ if (symbol3 && typeCheckerUtils.resolveToGlobalSymbol(symbol3) === promiseSymbol) {
10879
+ report({
10880
+ location: node,
10881
+ messageText: "This code constructs `new Promise(...)`, prefer Effect APIs such as `Effect.async`, `Effect.promise`, or `Effect.tryPromise` instead of manual Promise construction.",
10882
+ fixes: []
10883
+ });
10884
+ }
10885
+ }
10886
+ ts.forEachChild(node, visit);
10887
+ return void 0;
10888
+ };
10889
+ ts.forEachChild(sourceFile, visit);
10890
+ })
10891
+ });
10892
+
10606
10893
  // src/diagnostics/nodeBuiltinImport.ts
10607
10894
  var moduleAlternativesV3 = /* @__PURE__ */ new Map([
10608
10895
  ["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
@@ -10946,6 +11233,14 @@ var effectModuleMigrationDb = {
10946
11233
  "yieldNow": asUnchanged,
10947
11234
  "zip": asUnchanged,
10948
11235
  "zipWith": asUnchanged,
11236
+ "annotateLogsScoped": asUnchanged,
11237
+ "awaitAllChildren": asUnchanged,
11238
+ "bind": asUnchanged,
11239
+ "bindTo": asUnchanged,
11240
+ "Do": asUnchanged,
11241
+ "let": asUnchanged,
11242
+ "partition": asUnchanged,
11243
+ "validate": asUnchanged,
10949
11244
  // Renamed APIs (v3 name → v4 name)
10950
11245
  "catchAll": asRenamedSameBehaviour("catch"),
10951
11246
  "catchAllCause": asRenamedSameBehaviour("catchCause"),
@@ -10965,14 +11260,6 @@ var effectModuleMigrationDb = {
10965
11260
  "serviceOptional": asRenamedSameBehaviour("serviceOption"),
10966
11261
  "tapErrorCause": asRenamedSameBehaviour("tapCause"),
10967
11262
  // Removed APIs
10968
- "annotateLogsScoped": asUnchanged,
10969
- "awaitAllChildren": asUnchanged,
10970
- "bind": asUnchanged,
10971
- "bindTo": asUnchanged,
10972
- "Do": asUnchanged,
10973
- "let": asUnchanged,
10974
- "partition": asUnchanged,
10975
- "validate": asUnchanged,
10976
11263
  "catchSomeDefect": asRemoved(
10977
11264
  "Use Effect.catchDefect or Effect.matchCause to handle specific defects."
10978
11265
  ),
@@ -11837,6 +12124,63 @@ var preferSchemaOverJson = createDiagnostic({
11837
12124
  })
11838
12125
  });
11839
12126
 
12127
+ // src/diagnostics/processEnvInEffect.ts
12128
+ var isEnvPropertyAccess = (tsApi, node) => tsApi.isPropertyAccessExpression(node) && tsApi.idText(node.name) === "env";
12129
+ var isProcessEnvMemberAccess = (tsApi, node) => (tsApi.isPropertyAccessExpression(node) || tsApi.isElementAccessExpression(node)) && isEnvPropertyAccess(tsApi, node.expression);
12130
+ var makeProcessEnvApply = (checkInEffect) => fn(`processEnv${checkInEffect ? "InEffect" : ""}.apply`)(function* (sourceFile, report) {
12131
+ const ts = yield* service(TypeScriptApi);
12132
+ const typeChecker = yield* service(TypeCheckerApi);
12133
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
12134
+ const typeParser = yield* service(TypeParser);
12135
+ const processSymbol = typeChecker.resolveName("process", void 0, ts.SymbolFlags.Value, false);
12136
+ if (!processSymbol) return;
12137
+ const nodeToVisit = [];
12138
+ const appendNodeToVisit = (node) => {
12139
+ nodeToVisit.push(node);
12140
+ return void 0;
12141
+ };
12142
+ ts.forEachChild(sourceFile, appendNodeToVisit);
12143
+ while (nodeToVisit.length > 0) {
12144
+ const node = nodeToVisit.shift();
12145
+ ts.forEachChild(node, appendNodeToVisit);
12146
+ if (!isProcessEnvMemberAccess(ts, node)) continue;
12147
+ const processNode2 = node.expression.expression;
12148
+ if (!ts.isIdentifier(processNode2) || ts.idText(processNode2) !== "process") continue;
12149
+ const symbol3 = typeChecker.getSymbolAtLocation(processNode2);
12150
+ if (!symbol3) continue;
12151
+ if (typeCheckerUtils.resolveToGlobalSymbol(symbol3) !== processSymbol) continue;
12152
+ const { inEffect } = yield* typeParser.findEnclosingScopes(node);
12153
+ if (inEffect !== checkInEffect) continue;
12154
+ report({
12155
+ location: node,
12156
+ messageText: checkInEffect ? "This Effect code reads from `process.env`, environment configuration in Effect code is represented through `Config` from Effect." : "This code reads from `process.env`, environment configuration is represented through `Config` from Effect.",
12157
+ fixes: []
12158
+ });
12159
+ }
12160
+ });
12161
+ var processEnvInEffect = createDiagnostic({
12162
+ name: "processEnvInEffect",
12163
+ code: 65,
12164
+ description: "Warns when reading process.env inside Effect generators instead of using Effect Config",
12165
+ group: "effectNative",
12166
+ severity: "off",
12167
+ fixable: false,
12168
+ supportedEffect: ["v3", "v4"],
12169
+ apply: makeProcessEnvApply(true)
12170
+ });
12171
+
12172
+ // src/diagnostics/processEnv.ts
12173
+ var processEnv = createDiagnostic({
12174
+ name: "processEnv",
12175
+ code: 64,
12176
+ description: "Warns when reading process.env outside Effect generators instead of using Effect Config",
12177
+ group: "effectNative",
12178
+ severity: "off",
12179
+ fixable: false,
12180
+ supportedEffect: ["v3", "v4"],
12181
+ apply: makeProcessEnvApply(false)
12182
+ });
12183
+
11840
12184
  // src/diagnostics/redundantSchemaTagIdentifier.ts
11841
12185
  var redundantSchemaTagIdentifier = createDiagnostic({
11842
12186
  name: "redundantSchemaTagIdentifier",
@@ -12774,6 +13118,56 @@ var unknownInEffectCatch = createDiagnostic({
12774
13118
  })
12775
13119
  });
12776
13120
 
13121
+ // src/diagnostics/unnecessaryArrowBlock.ts
13122
+ var unnecessaryArrowBlock = createDiagnostic({
13123
+ name: "unnecessaryArrowBlock",
13124
+ code: 72,
13125
+ description: "Suggests using a concise arrow body when the block only returns an expression",
13126
+ group: "style",
13127
+ severity: "off",
13128
+ fixable: true,
13129
+ supportedEffect: ["v3", "v4"],
13130
+ apply: fn("unnecessaryArrowBlock.apply")(function* (sourceFile, report) {
13131
+ const ts = yield* service(TypeScriptApi);
13132
+ const nodeToVisit = [];
13133
+ const appendNodeToVisit = (node) => {
13134
+ nodeToVisit.push(node);
13135
+ return void 0;
13136
+ };
13137
+ ts.forEachChild(sourceFile, appendNodeToVisit);
13138
+ while (nodeToVisit.length > 0) {
13139
+ const node = nodeToVisit.shift();
13140
+ ts.forEachChild(node, appendNodeToVisit);
13141
+ if (!ts.isArrowFunction(node) || !ts.isBlock(node.body)) continue;
13142
+ if (node.body.statements.length !== 1) continue;
13143
+ const [statement] = node.body.statements;
13144
+ if (!ts.isReturnStatement(statement) || !statement.expression) continue;
13145
+ const returnedExpression = statement.expression;
13146
+ report({
13147
+ location: node.body,
13148
+ messageText: "This arrow function block only returns an expression and can use a concise body.",
13149
+ fixes: [{
13150
+ fixName: "unnecessaryArrowBlock_fix",
13151
+ description: "Use a concise arrow body",
13152
+ apply: gen(function* () {
13153
+ const changeTracker = yield* service(ChangeTracker);
13154
+ const replacementNode = ts.factory.updateArrowFunction(
13155
+ node,
13156
+ node.modifiers,
13157
+ node.typeParameters,
13158
+ node.parameters,
13159
+ node.type,
13160
+ node.equalsGreaterThanToken,
13161
+ ts.factory.createParenthesizedExpression(returnedExpression)
13162
+ );
13163
+ changeTracker.replaceNode(sourceFile, node, replacementNode);
13164
+ })
13165
+ }]
13166
+ });
13167
+ }
13168
+ })
13169
+ });
13170
+
12777
13171
  // src/diagnostics/unnecessaryEffectGen.ts
12778
13172
  var unnecessaryEffectGen = createDiagnostic({
12779
13173
  name: "unnecessaryEffectGen",
@@ -13074,12 +13468,17 @@ var unsupportedServiceAccessors = createDiagnostic({
13074
13468
  var diagnostics = [
13075
13469
  outdatedApi,
13076
13470
  anyUnknownInErrorContext,
13471
+ asyncFunction,
13077
13472
  instanceOfSchema,
13078
13473
  catchAllToMapError,
13079
13474
  catchUnfailableEffect,
13080
13475
  classSelfMismatch,
13476
+ cryptoRandomUUID,
13477
+ cryptoRandomUUIDInEffect,
13081
13478
  duplicatePackage,
13479
+ effectDoNotation,
13082
13480
  effectFnImplicitAny,
13481
+ effectMapFlatten,
13083
13482
  effectGenUsesAdapter,
13084
13483
  missingEffectContext,
13085
13484
  missingEffectError,
@@ -13088,6 +13487,8 @@ var diagnostics = [
13088
13487
  floatingEffect,
13089
13488
  effectInFailure,
13090
13489
  missingStarInYieldEffectGen,
13490
+ newPromise,
13491
+ lazyPromiseInEffectSync,
13091
13492
  unnecessaryEffectGen,
13092
13493
  unnecessaryFailYieldableError,
13093
13494
  missingReturnYieldStar,
@@ -13096,6 +13497,8 @@ var diagnostics = [
13096
13497
  genericEffectServices,
13097
13498
  globalFetch,
13098
13499
  globalFetchInEffect,
13500
+ processEnv,
13501
+ processEnvInEffect,
13099
13502
  returnEffectInGen,
13100
13503
  tryCatchInEffectGen,
13101
13504
  importFromBarrel,
@@ -13113,6 +13516,8 @@ var diagnostics = [
13113
13516
  strictEffectProvide,
13114
13517
  unknownInEffectCatch,
13115
13518
  runEffectInsideEffect,
13519
+ nestedEffectGenYield,
13520
+ unnecessaryArrowBlock,
13116
13521
  schemaUnionOfLiterals,
13117
13522
  schemaStructWithTag,
13118
13523
  globalErrorInEffectCatch,
@@ -14430,7 +14835,7 @@ var middlewareGenLike = fn("middlewareGenLike")(function* (sourceFile, _span, pr
14430
14835
  // src/quickinfo/dedupeJsDocs.ts
14431
14836
  var SymbolDisplayPartEq = make((fa, fb) => fa.kind === fb.kind && fa.text === fb.text);
14432
14837
  var JSDocTagInfoEq = make(
14433
- (fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? Array2(SymbolDisplayPartEq)(fa.text, fb.text) : true)
14838
+ (fa, fb) => fa.name === fb.name && typeof fa.text === typeof fb.text && (typeof fa.text !== "undefined" ? Array_(SymbolDisplayPartEq)(fa.text, fb.text) : true)
14434
14839
  );
14435
14840
  function dedupeJsDocs(quickInfo2) {
14436
14841
  if (!quickInfo2) return succeed3(quickInfo2);