@effect/language-service 0.74.0 → 0.75.1

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.
@@ -852,6 +852,7 @@ var dedupe = (self) => dedupeWith(self, equivalence());
852
852
  var join = /* @__PURE__ */ dual(2, (self, sep) => fromIterable(self).join(sep));
853
853
 
854
854
  // src/core/Nano.ts
855
+ var debugPerformance = false;
855
856
  var NanoTag = class {
856
857
  constructor(key) {
857
858
  this.key = key;
@@ -949,7 +950,6 @@ var NanoFiber = class {
949
950
  _yielded = void 0;
950
951
  _services = {};
951
952
  _cache = {};
952
- _perf = false;
953
953
  _lastSpan = "";
954
954
  runLoop(nano) {
955
955
  let current = nano;
@@ -980,7 +980,7 @@ var WithSpanProto = {
980
980
  ...PrimitiveProto,
981
981
  [evaluate](fiber) {
982
982
  const [fa, name] = this[args];
983
- if (!fiber._perf) return fa;
983
+ if (!debugPerformance) return fa;
984
984
  const previousSpan = fiber._lastSpan;
985
985
  fiber._lastSpan = name;
986
986
  const start = performance.now();
@@ -1008,7 +1008,6 @@ var withSpan = (name) => (fa) => {
1008
1008
  };
1009
1009
  var unsafeRun = (nano) => {
1010
1010
  const fiber = new NanoFiber();
1011
- globalThis.currentFiber = fiber;
1012
1011
  const result = fiber.runLoop(nano);
1013
1012
  if (result._tag === "Success") {
1014
1013
  return right2(result.value);
@@ -1920,6 +1919,26 @@ var getApplicableRefactors = fn("LSP.getApplicableRefactors")(function* (refacto
1920
1919
  }
1921
1920
  return effectRefactors;
1922
1921
  });
1922
+ function codeFixNameToFullyQualifiedName(name) {
1923
+ return `@effect/language-service/codefixes/${name}`;
1924
+ }
1925
+ var codeFixesToApplicableRefactor = fn("LSP.codeFixesToApplicableRefactor")(function* (codeFixes, sourceFile, positionOrRange) {
1926
+ const effectRefactors = [];
1927
+ const range = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1928
+ const inRangeCodeFixes = codeFixes.filter((_) => _.start <= range.pos && _.end >= range.end);
1929
+ for (const codeFix of inRangeCodeFixes) {
1930
+ effectRefactors.push({
1931
+ name: codeFixNameToFullyQualifiedName(codeFix.fixName),
1932
+ description: "Quick Fix: " + codeFix.description,
1933
+ actions: [{
1934
+ name: codeFixNameToFullyQualifiedName(codeFix.fixName),
1935
+ description: "Quick Fix: " + codeFix.description,
1936
+ kind: "refactor.rewrite.codeFixEffect." + codeFix.fixName
1937
+ }]
1938
+ });
1939
+ }
1940
+ return effectRefactors;
1941
+ });
1923
1942
  var getEditsForRefactor = fn("LSP.getEditsForRefactor")(function* (refactors, sourceFile, positionOrRange, refactorName) {
1924
1943
  const refactor = refactors.find((refactor2) => refactorNameToFullyQualifiedName(refactor2.name) === refactorName);
1925
1944
  if (!refactor) {
@@ -1928,6 +1947,16 @@ var getEditsForRefactor = fn("LSP.getEditsForRefactor")(function* (refactors, so
1928
1947
  const textRange = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1929
1948
  return yield* refactor.apply(sourceFile, textRange);
1930
1949
  });
1950
+ var getEditsForCodeFixes = fn("LSP.getEditsForCodeFixes")(function* (codeFixes, positionOrRange, refactorName) {
1951
+ const textRange = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1952
+ const fixToRun = codeFixes.find(
1953
+ (_) => codeFixNameToFullyQualifiedName(_.fixName) === refactorName && _.start <= textRange.pos && _.end >= textRange.end
1954
+ );
1955
+ if (!fixToRun) {
1956
+ return yield* fail(new RefactorNotApplicableError());
1957
+ }
1958
+ return fixToRun;
1959
+ });
1931
1960
  var getCompletionsAtPosition = fn("LSP.getCompletionsAtPosition")(function* (completions, sourceFile, position, options, formatCodeSettings) {
1932
1961
  let effectCompletions = [];
1933
1962
  for (const completion of completions) {
@@ -2011,7 +2040,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
2011
2040
  message: ts.DiagnosticCategory.Message,
2012
2041
  suggestion: ts.DiagnosticCategory.Suggestion
2013
2042
  };
2014
- const execute = (rule) => gen(function* () {
2043
+ const execute = fn("LSP.execute")(function* (rule) {
2015
2044
  const diagnostics2 = [];
2016
2045
  const codeFixes = [];
2017
2046
  const ruleNameLowered = rule.name.toLowerCase();
@@ -2797,6 +2826,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2797
2826
  if (signatures.length !== 1) {
2798
2827
  return typeParserIssue("Covariant type has no call signature", type);
2799
2828
  }
2829
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2830
+ return typeParserIssue("Invariant type should not have type parameters", type);
2831
+ }
2800
2832
  return succeed(typeChecker.getReturnTypeOfSignature(signatures[0]));
2801
2833
  }
2802
2834
  function contravariantTypeArgument(type) {
@@ -2804,6 +2836,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2804
2836
  if (signatures.length !== 1) {
2805
2837
  return typeParserIssue("Contravariant type has no call signature", type);
2806
2838
  }
2839
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2840
+ return typeParserIssue("Invariant type should not have type parameters", type);
2841
+ }
2807
2842
  return succeed(typeCheckerUtils.getTypeParameterAtPosition(signatures[0], 0));
2808
2843
  }
2809
2844
  function invariantTypeArgument(type) {
@@ -2811,6 +2846,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2811
2846
  if (signatures.length !== 1) {
2812
2847
  return typeParserIssue("Invariant type has no call signature", type);
2813
2848
  }
2849
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2850
+ return typeParserIssue("Invariant type should not have type parameters", type);
2851
+ }
2814
2852
  return succeed(typeChecker.getReturnTypeOfSignature(signatures[0]));
2815
2853
  }
2816
2854
  const pipeableType = cachedBy(
@@ -4698,32 +4736,38 @@ var catchAllToMapError = createDiagnostic({
4698
4736
  return void 0;
4699
4737
  };
4700
4738
  const getEffectFailCallInfo = (body) => {
4701
- return gen(function* () {
4702
- if (ts.isCallExpression(body)) {
4703
- const isFailCall = yield* pipe(
4704
- typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4705
- orUndefined
4706
- );
4707
- if (isFailCall && body.arguments.length >= 1) {
4708
- return { failCall: body, failArg: body.arguments[0] };
4709
- }
4710
- }
4711
- if (ts.isBlock(body)) {
4712
- const statements = body.statements;
4713
- if (statements.length === 1) {
4714
- const stmt = statements[0];
4715
- if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4716
- const isFailCall = yield* pipe(
4717
- typeParser.isNodeReferenceToEffectModuleApi("fail")(stmt.expression.expression),
4718
- orUndefined
4719
- );
4720
- if (isFailCall && stmt.expression.arguments.length >= 1) {
4721
- return { failCall: stmt.expression, failArg: stmt.expression.arguments[0] };
4722
- }
4739
+ if (ts.isCallExpression(body)) {
4740
+ return pipe(
4741
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4742
+ orUndefined,
4743
+ map4((isFailCall) => {
4744
+ if (isFailCall && body.arguments.length >= 1) {
4745
+ return { failCall: body, failArg: body.arguments[0] };
4723
4746
  }
4747
+ return void 0;
4748
+ })
4749
+ );
4750
+ }
4751
+ if (ts.isBlock(body)) {
4752
+ const statements = body.statements;
4753
+ if (statements.length === 1) {
4754
+ const stmt = statements[0];
4755
+ if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4756
+ const callExpr = stmt.expression;
4757
+ return pipe(
4758
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpr.expression),
4759
+ orUndefined,
4760
+ map4((isFailCall) => {
4761
+ if (isFailCall && callExpr.arguments.length >= 1) {
4762
+ return { failCall: callExpr, failArg: callExpr.arguments[0] };
4763
+ }
4764
+ return void 0;
4765
+ })
4766
+ );
4724
4767
  }
4725
4768
  }
4726
- });
4769
+ }
4770
+ return void_;
4727
4771
  };
4728
4772
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
4729
4773
  for (const flow2 of flows) {
@@ -4968,20 +5012,21 @@ var deterministicKeys = createDiagnostic({
4968
5012
  const typeScriptUtils = yield* service(TypeScriptUtils);
4969
5013
  const options = yield* service(LanguageServicePluginOptions);
4970
5014
  const parseExtendsCustom = cachedBy(
4971
- fn("parseExtendsCustom")(function* (classDeclaration) {
5015
+ (classDeclaration) => {
4972
5016
  if (!options.extendedKeyDetection) {
4973
- return yield* typeParserIssue("Extended key detection is disabled", void 0, classDeclaration);
5017
+ return TypeParserIssue.issue;
4974
5018
  }
4975
5019
  if (!classDeclaration.name) {
4976
- return yield* typeParserIssue("Class has no name", void 0, classDeclaration);
5020
+ return TypeParserIssue.issue;
4977
5021
  }
4978
5022
  if (!ts.isIdentifier(classDeclaration.name)) {
4979
- return yield* typeParserIssue("Class name is not an identifier", void 0, classDeclaration);
5023
+ return TypeParserIssue.issue;
4980
5024
  }
4981
5025
  const heritageClauses = classDeclaration.heritageClauses;
4982
5026
  if (!heritageClauses) {
4983
- return yield* typeParserIssue("Class has no heritage clauses", void 0, classDeclaration);
5027
+ return TypeParserIssue.issue;
4984
5028
  }
5029
+ const className = classDeclaration.name;
4985
5030
  const nodeToVisit2 = [...classDeclaration.heritageClauses];
4986
5031
  const appendNodeToVisit2 = (node) => {
4987
5032
  nodeToVisit2.push(node);
@@ -5002,7 +5047,7 @@ var deterministicKeys = createDiagnostic({
5002
5047
  const parameterSourceFile = typeScriptUtils.getSourceFileOfNode(declaration);
5003
5048
  const paramText = parameterSourceFile.text.substring(declaration.pos, declaration.end);
5004
5049
  if (paramText.toLowerCase().includes("@effect-identifier")) {
5005
- return { className: classDeclaration.name, keyStringLiteral: arg, target: "custom" };
5050
+ return succeed({ className, keyStringLiteral: arg, target: "custom" });
5006
5051
  }
5007
5052
  }
5008
5053
  }
@@ -5011,12 +5056,8 @@ var deterministicKeys = createDiagnostic({
5011
5056
  }
5012
5057
  ts.forEachChild(node, appendNodeToVisit2);
5013
5058
  }
5014
- return yield* typeParserIssue(
5015
- "Class does not extend any custom pattern",
5016
- void 0,
5017
- classDeclaration
5018
- );
5019
- }),
5059
+ return TypeParserIssue.issue;
5060
+ },
5020
5061
  "deterministicKeys.parseExtendsCustom",
5021
5062
  (classDeclaration) => classDeclaration
5022
5063
  );
@@ -5295,7 +5336,7 @@ var effectFnOpportunity = createDiagnostic({
5295
5336
  }
5296
5337
  return false;
5297
5338
  };
5298
- const tryExtractWithSpanExpression = (expr) => gen(function* () {
5339
+ const tryExtractWithSpanExpression = fn("effectFnOpportunity.tryExtractWithSpanExpression")(function* (expr) {
5299
5340
  if (!ts.isCallExpression(expr)) return void 0;
5300
5341
  const callee = expr.expression;
5301
5342
  const isWithSpan = yield* pipe(
@@ -5307,7 +5348,9 @@ var effectFnOpportunity = createDiagnostic({
5307
5348
  if (expr.arguments.length === 0) return void 0;
5308
5349
  return expr.arguments[0];
5309
5350
  });
5310
- const tryParseGenOpportunity = (fnNode) => gen(function* () {
5351
+ const tryParseGenOpportunity = fn(
5352
+ "effectFnOpportunity.tryParseGenOpportunity"
5353
+ )(function* (fnNode) {
5311
5354
  const bodyExpression = getBodyExpression(fnNode);
5312
5355
  if (!bodyExpression) return yield* TypeParserIssue.issue;
5313
5356
  const { pipeArguments: pipeArguments2, subject } = yield* pipe(
@@ -5343,62 +5386,67 @@ var effectFnOpportunity = createDiagnostic({
5343
5386
  orElse2(() => succeed(false))
5344
5387
  );
5345
5388
  };
5346
- const parseEffectFnOpportunityTarget = (node) => gen(function* () {
5389
+ const parseEffectFnOpportunityTargetGen = fn("effectFnOpportunity.parseEffectFnOpportunityTarget")(
5390
+ function* (node, returnType, traceName, nameIdentifier) {
5391
+ if (yield* isInsideEffectFn(node)) {
5392
+ return yield* TypeParserIssue.issue;
5393
+ }
5394
+ const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
5395
+ yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
5396
+ const opportunity = yield* pipe(
5397
+ tryParseGenOpportunity(node),
5398
+ orElse2(() => {
5399
+ if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
5400
+ return TypeParserIssue.issue;
5401
+ }
5402
+ const body = ts.isArrowFunction(node) ? node.body : node.body;
5403
+ if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
5404
+ return TypeParserIssue.issue;
5405
+ }
5406
+ return succeed({
5407
+ effectModuleName: sourceEffectModuleName,
5408
+ pipeArguments: [],
5409
+ generatorFunction: void 0,
5410
+ explicitTraceExpression: void 0
5411
+ });
5412
+ })
5413
+ );
5414
+ return {
5415
+ node,
5416
+ nameIdentifier,
5417
+ effectModuleName: opportunity.effectModuleName,
5418
+ inferredTraceName: traceName,
5419
+ explicitTraceExpression: opportunity.explicitTraceExpression,
5420
+ pipeArguments: opportunity.pipeArguments,
5421
+ generatorFunction: opportunity.generatorFunction,
5422
+ hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
5423
+ };
5424
+ }
5425
+ );
5426
+ const parseEffectFnOpportunityTarget = (node) => {
5347
5427
  if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
5348
- return yield* TypeParserIssue.issue;
5428
+ return TypeParserIssue.issue;
5349
5429
  }
5350
5430
  if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
5351
- return yield* TypeParserIssue.issue;
5431
+ return TypeParserIssue.issue;
5352
5432
  }
5353
5433
  if (ts.isFunctionExpression(node) && node.name) {
5354
- return yield* TypeParserIssue.issue;
5434
+ return TypeParserIssue.issue;
5355
5435
  }
5356
5436
  if (node.type) {
5357
- return yield* TypeParserIssue.issue;
5358
- }
5359
- if (yield* isInsideEffectFn(node)) {
5360
- return yield* TypeParserIssue.issue;
5437
+ return TypeParserIssue.issue;
5361
5438
  }
5362
5439
  const functionType = typeChecker.getTypeAtLocation(node);
5363
- if (!functionType) return yield* TypeParserIssue.issue;
5440
+ if (!functionType) return TypeParserIssue.issue;
5364
5441
  const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
5365
- if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
5442
+ if (callSignatures.length !== 1) return TypeParserIssue.issue;
5366
5443
  const signature = callSignatures[0];
5367
5444
  const returnType = typeChecker.getReturnTypeOfSignature(signature);
5368
- const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
5369
- yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
5370
5445
  const nameIdentifier = getNameIdentifier(node);
5371
5446
  const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
5372
- if (!traceName) return yield* TypeParserIssue.issue;
5373
- const opportunity = yield* pipe(
5374
- tryParseGenOpportunity(node),
5375
- orElse2(() => {
5376
- if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
5377
- return TypeParserIssue.issue;
5378
- }
5379
- const body = ts.isArrowFunction(node) ? node.body : node.body;
5380
- if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
5381
- return TypeParserIssue.issue;
5382
- }
5383
- return succeed({
5384
- effectModuleName: sourceEffectModuleName,
5385
- pipeArguments: [],
5386
- generatorFunction: void 0,
5387
- explicitTraceExpression: void 0
5388
- });
5389
- })
5390
- );
5391
- return {
5392
- node,
5393
- nameIdentifier,
5394
- effectModuleName: opportunity.effectModuleName,
5395
- inferredTraceName: traceName,
5396
- explicitTraceExpression: opportunity.explicitTraceExpression,
5397
- pipeArguments: opportunity.pipeArguments,
5398
- generatorFunction: opportunity.generatorFunction,
5399
- hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
5400
- };
5401
- });
5447
+ if (!traceName) return TypeParserIssue.issue;
5448
+ return parseEffectFnOpportunityTargetGen(node, returnType, traceName, nameIdentifier);
5449
+ };
5402
5450
  const getFunctionBodyBlock = (node) => {
5403
5451
  if (ts.isArrowFunction(node)) {
5404
5452
  if (ts.isBlock(node.body)) {
@@ -5639,7 +5687,7 @@ var effectInVoidSuccess = createDiagnostic({
5639
5687
  );
5640
5688
  return { voidedEffect };
5641
5689
  }
5642
- return yield* fail(typeParserIssue("expectedEffect success is not void"));
5690
+ return yield* TypeParserIssue.issue;
5643
5691
  });
5644
5692
  const entries = typeCheckerUtils.expectedAndRealType(sourceFile);
5645
5693
  for (const [node, expectedType, valueNode, realType] of entries) {
@@ -7451,25 +7499,27 @@ var generate = fn("writeTagClassAccessors.generate")(function* (sourceFile, serv
7451
7499
  return succeed(typeNode);
7452
7500
  })
7453
7501
  );
7454
- const proxySignature = (signature, atLocation2, className2) => gen(function* () {
7455
- const signatureDeclaration = typeChecker.signatureToSignatureDeclaration(
7456
- signature,
7457
- ts.SyntaxKind.FunctionType,
7458
- atLocation2,
7459
- ts.NodeBuilderFlags.NoTruncation
7460
- );
7461
- if (!signatureDeclaration) return yield* fail("error generating signature");
7462
- const returnType = yield* generateReturnType(
7463
- typeChecker.getReturnTypeOfSignature(signature),
7464
- atLocation2,
7465
- className2
7466
- );
7467
- return ts.factory.createFunctionTypeNode(
7468
- signatureDeclaration.typeParameters,
7469
- signatureDeclaration.parameters,
7470
- returnType
7471
- );
7472
- });
7502
+ const proxySignature = fn("writeTagClassAccessors.proxySignature")(
7503
+ function* (signature, atLocation2, className2) {
7504
+ const signatureDeclaration = typeChecker.signatureToSignatureDeclaration(
7505
+ signature,
7506
+ ts.SyntaxKind.FunctionType,
7507
+ atLocation2,
7508
+ ts.NodeBuilderFlags.NoTruncation
7509
+ );
7510
+ if (!signatureDeclaration) return yield* fail("error generating signature");
7511
+ const returnType = yield* generateReturnType(
7512
+ typeChecker.getReturnTypeOfSignature(signature),
7513
+ atLocation2,
7514
+ className2
7515
+ );
7516
+ return ts.factory.createFunctionTypeNode(
7517
+ signatureDeclaration.typeParameters,
7518
+ signatureDeclaration.parameters,
7519
+ returnType
7520
+ );
7521
+ }
7522
+ );
7473
7523
  for (const { property, propertyType } of involvedMembers) {
7474
7524
  const callSignatures = [];
7475
7525
  let propertyDeclaration = void 0;
@@ -7606,7 +7656,7 @@ var annotate = createCodegen({
7606
7656
  const tsUtils = yield* service(TypeScriptUtils);
7607
7657
  const typeChecker = yield* service(TypeCheckerApi);
7608
7658
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
7609
- const parse3 = (node) => gen(function* () {
7659
+ const parse3 = fn("annotate.parse")(function* (node) {
7610
7660
  let variableDeclarations = [];
7611
7661
  const result = [];
7612
7662
  if (ts.isVariableStatement(node)) {
@@ -8286,7 +8336,7 @@ var typeToSchema = createCodegen({
8286
8336
  new CodegenNotApplicableError("the typeToSchema codegen can be used only once per file")
8287
8337
  );
8288
8338
  }
8289
- const parse3 = (node) => gen(function* () {
8339
+ const parse3 = fn("typeToSchema.parse")(function* (node) {
8290
8340
  if (!ts.isTypeAliasDeclaration(node)) {
8291
8341
  return yield* fail(
8292
8342
  new CodegenNotApplicableError(
@@ -8563,73 +8613,99 @@ var preferSchemaOverJson = createDiagnostic({
8563
8613
  apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
8564
8614
  const ts = yield* service(TypeScriptApi);
8565
8615
  const typeParser = yield* service(TypeParser);
8566
- const parseJsonMethod = (node) => gen(function* () {
8567
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8568
- const expression = node.expression;
8569
- if (!ts.isPropertyAccessExpression(expression)) return yield* fail("expression is not a property access");
8570
- const objectExpr = expression.expression;
8571
- const methodName = ts.idText(expression.name);
8572
- if (!ts.isIdentifier(objectExpr) || ts.idText(objectExpr) !== "JSON") {
8573
- return yield* fail("object is not JSON");
8616
+ const isJsonCall = (node) => ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && ts.idText(node.expression.expression) === "JSON" && (ts.idText(node.expression.name) === "parse" || ts.idText(node.expression.name) === "stringify");
8617
+ const findEnclosingEffectTry = (jsonCall) => {
8618
+ const parent = jsonCall.parent;
8619
+ let lazy;
8620
+ if (ts.isArrowFunction(parent) && parent.body === jsonCall && parent.parameters.length === 0 && (!parent.typeParameters || parent.typeParameters.length === 0)) {
8621
+ lazy = parent;
8622
+ }
8623
+ if (!lazy && ts.isReturnStatement(parent) && parent.expression === jsonCall) {
8624
+ const block = parent.parent;
8625
+ if (ts.isBlock(block) && block.statements.length === 1) {
8626
+ const fn2 = block.parent;
8627
+ if ((ts.isArrowFunction(fn2) || ts.isFunctionExpression(fn2)) && fn2.parameters.length === 0 && (!fn2.typeParameters || fn2.typeParameters.length === 0)) {
8628
+ lazy = fn2;
8629
+ }
8630
+ }
8574
8631
  }
8575
- if (methodName !== "parse" && methodName !== "stringify") {
8576
- return yield* fail("method is not parse or stringify");
8632
+ if (!lazy) return void 0;
8633
+ const lazyParent = lazy.parent;
8634
+ if (ts.isCallExpression(lazyParent) && lazyParent.arguments.length > 0 && lazyParent.arguments[0] === lazy) {
8635
+ return lazyParent;
8577
8636
  }
8578
- return { node, methodName };
8579
- });
8580
- const effectTrySimple = (node) => gen(function* () {
8581
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8637
+ if (ts.isPropertyAssignment(lazyParent) && ts.isIdentifier(lazyParent.name) && ts.idText(lazyParent.name) === "try") {
8638
+ const objLiteral = lazyParent.parent;
8639
+ if (ts.isObjectLiteralExpression(objLiteral)) {
8640
+ const callExpr = objLiteral.parent;
8641
+ if (ts.isCallExpression(callExpr) && callExpr.arguments.length > 0 && callExpr.arguments[0] === objLiteral) {
8642
+ return callExpr;
8643
+ }
8644
+ }
8645
+ }
8646
+ return void 0;
8647
+ };
8648
+ const jsonCalls = [];
8649
+ const collectJsonCalls = (node) => {
8650
+ if (isJsonCall(node)) {
8651
+ jsonCalls.push(node);
8652
+ }
8653
+ ts.forEachChild(node, collectJsonCalls);
8654
+ };
8655
+ ts.forEachChild(sourceFile, collectJsonCalls);
8656
+ if (jsonCalls.length === 0) return;
8657
+ const effectTrySimple = fn("preferSchemaOverJson.effectTrySimple")(function* (node) {
8582
8658
  yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
8583
- if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
8659
+ if (node.arguments.length === 0) return yield* TypeParserIssue.issue;
8584
8660
  const lazyFn = yield* typeParser.lazyExpression(node.arguments[0]);
8585
- const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
8586
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8661
+ if (!isJsonCall(lazyFn.expression)) return yield* TypeParserIssue.issue;
8662
+ return lazyFn.expression;
8587
8663
  });
8588
- const effectTryObject = (node) => gen(function* () {
8589
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8664
+ const effectTryObject = fn("preferSchemaOverJson.effectTryObject")(function* (node) {
8590
8665
  yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
8591
- if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
8666
+ if (node.arguments.length === 0) return yield* TypeParserIssue.issue;
8592
8667
  const arg = node.arguments[0];
8593
- if (!ts.isObjectLiteralExpression(arg)) return yield* fail("argument is not an object literal");
8668
+ if (!ts.isObjectLiteralExpression(arg)) return yield* TypeParserIssue.issue;
8594
8669
  const tryProp = arg.properties.find(
8595
8670
  (p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && ts.idText(p.name) === "try"
8596
8671
  );
8597
- if (!tryProp) return yield* fail("object has no 'try' property");
8672
+ if (!tryProp) return yield* TypeParserIssue.issue;
8598
8673
  const lazyFn = yield* typeParser.lazyExpression(tryProp.initializer);
8599
- const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
8600
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8674
+ if (!isJsonCall(lazyFn.expression)) return yield* TypeParserIssue.issue;
8675
+ return lazyFn.expression;
8601
8676
  });
8602
- const jsonMethodInEffectGen = (node) => gen(function* () {
8603
- const jsonMethod = yield* parseJsonMethod(node);
8604
- const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
8605
- if (!effectGen || effectGen.body.statements.length === 0) {
8606
- return yield* fail("not inside an Effect generator");
8677
+ const jsonMethodInEffectGen = fn("preferSchemaOverJson.jsonMethodInEffectGen")(
8678
+ function* (jsonCall) {
8679
+ const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(jsonCall);
8680
+ if (!effectGen || effectGen.body.statements.length === 0) {
8681
+ return yield* TypeParserIssue.issue;
8682
+ }
8683
+ if (scopeNode && scopeNode !== effectGen.generatorFunction) {
8684
+ return yield* TypeParserIssue.issue;
8685
+ }
8686
+ return jsonCall;
8607
8687
  }
8608
- if (scopeNode && scopeNode !== effectGen.generatorFunction) {
8609
- return yield* fail("inside a nested function scope");
8688
+ );
8689
+ for (const jsonCall of jsonCalls) {
8690
+ const effectTryCall = findEnclosingEffectTry(jsonCall);
8691
+ let match2;
8692
+ if (effectTryCall) {
8693
+ match2 = yield* pipe(
8694
+ firstSuccessOf([
8695
+ effectTrySimple(effectTryCall),
8696
+ effectTryObject(effectTryCall)
8697
+ ]),
8698
+ option
8699
+ );
8700
+ } else {
8701
+ match2 = yield* pipe(
8702
+ jsonMethodInEffectGen(jsonCall),
8703
+ option
8704
+ );
8610
8705
  }
8611
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8612
- });
8613
- const nodeToVisit = [];
8614
- const appendNodeToVisit = (node) => {
8615
- nodeToVisit.push(node);
8616
- return void 0;
8617
- };
8618
- ts.forEachChild(sourceFile, appendNodeToVisit);
8619
- while (nodeToVisit.length > 0) {
8620
- const node = nodeToVisit.shift();
8621
- ts.forEachChild(node, appendNodeToVisit);
8622
- const match2 = yield* pipe(
8623
- firstSuccessOf([
8624
- effectTrySimple(node),
8625
- effectTryObject(node),
8626
- jsonMethodInEffectGen(node)
8627
- ]),
8628
- option
8629
- );
8630
8706
  if (isSome2(match2)) {
8631
8707
  report({
8632
- location: match2.value.node,
8708
+ location: match2.value,
8633
8709
  messageText: "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
8634
8710
  fixes: []
8635
8711
  });
@@ -9273,19 +9349,24 @@ var strictEffectProvide = createDiagnostic({
9273
9349
  const ts = yield* service(TypeScriptApi);
9274
9350
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
9275
9351
  const typeParser = yield* service(TypeParser);
9276
- const parseEffectProvideWithLayer = (node) => gen(function* () {
9352
+ const parseEffectProvideWithLayerGen = fn("strictEffectProvide.parseEffectProvideWithLayer")(
9353
+ function* (node) {
9354
+ yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
9355
+ return yield* firstSuccessOf(
9356
+ node.arguments.map((arg) => {
9357
+ const argType = typeCheckerUtils.getTypeAtLocation(arg);
9358
+ if (!argType) return typeParserIssue("Could not get argument type");
9359
+ return typeParser.layerType(argType, arg);
9360
+ })
9361
+ );
9362
+ }
9363
+ );
9364
+ const parseEffectProvideWithLayer = (node) => {
9277
9365
  if (!ts.isCallExpression(node) || node.arguments.length === 0) {
9278
- return yield* typeParserIssue("Not an Effect.provide call");
9279
- }
9280
- yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
9281
- return yield* firstSuccessOf(
9282
- node.arguments.map((arg) => {
9283
- const argType = typeCheckerUtils.getTypeAtLocation(arg);
9284
- if (!argType) return typeParserIssue("Could not get argument type");
9285
- return typeParser.layerType(argType, arg);
9286
- })
9287
- );
9288
- });
9366
+ return TypeParserIssue.issue;
9367
+ }
9368
+ return parseEffectProvideWithLayerGen(node);
9369
+ };
9289
9370
  const nodeToVisit = [];
9290
9371
  const appendNodeToVisit = (node) => {
9291
9372
  nodeToVisit.push(node);