@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.74.0",
3
+ "version": "0.75.1",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "bin": {
package/transform.js CHANGED
@@ -849,6 +849,7 @@ var dedupe = (self) => dedupeWith(self, equivalence());
849
849
  var join = /* @__PURE__ */ dual(2, (self, sep) => fromIterable(self).join(sep));
850
850
 
851
851
  // src/core/Nano.ts
852
+ var debugPerformance = false;
852
853
  var NanoTag = class {
853
854
  constructor(key) {
854
855
  this.key = key;
@@ -946,7 +947,6 @@ var NanoFiber = class {
946
947
  _yielded = void 0;
947
948
  _services = {};
948
949
  _cache = {};
949
- _perf = false;
950
950
  _lastSpan = "";
951
951
  runLoop(nano) {
952
952
  let current = nano;
@@ -977,7 +977,7 @@ var WithSpanProto = {
977
977
  ...PrimitiveProto,
978
978
  [evaluate](fiber) {
979
979
  const [fa, name] = this[args];
980
- if (!fiber._perf) return fa;
980
+ if (!debugPerformance) return fa;
981
981
  const previousSpan = fiber._lastSpan;
982
982
  fiber._lastSpan = name;
983
983
  const start = performance.now();
@@ -1920,6 +1920,26 @@ var getApplicableRefactors = fn("LSP.getApplicableRefactors")(function* (refacto
1920
1920
  }
1921
1921
  return effectRefactors;
1922
1922
  });
1923
+ function codeFixNameToFullyQualifiedName(name) {
1924
+ return `@effect/language-service/codefixes/${name}`;
1925
+ }
1926
+ var codeFixesToApplicableRefactor = fn("LSP.codeFixesToApplicableRefactor")(function* (codeFixes, sourceFile, positionOrRange) {
1927
+ const effectRefactors = [];
1928
+ const range = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1929
+ const inRangeCodeFixes = codeFixes.filter((_) => _.start <= range.pos && _.end >= range.end);
1930
+ for (const codeFix of inRangeCodeFixes) {
1931
+ effectRefactors.push({
1932
+ name: codeFixNameToFullyQualifiedName(codeFix.fixName),
1933
+ description: "Quick Fix: " + codeFix.description,
1934
+ actions: [{
1935
+ name: codeFixNameToFullyQualifiedName(codeFix.fixName),
1936
+ description: "Quick Fix: " + codeFix.description,
1937
+ kind: "refactor.rewrite.codeFixEffect." + codeFix.fixName
1938
+ }]
1939
+ });
1940
+ }
1941
+ return effectRefactors;
1942
+ });
1923
1943
  var getEditsForRefactor = fn("LSP.getEditsForRefactor")(function* (refactors, sourceFile, positionOrRange, refactorName) {
1924
1944
  const refactor = refactors.find((refactor2) => refactorNameToFullyQualifiedName(refactor2.name) === refactorName);
1925
1945
  if (!refactor) {
@@ -1928,6 +1948,16 @@ var getEditsForRefactor = fn("LSP.getEditsForRefactor")(function* (refactors, so
1928
1948
  const textRange = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1929
1949
  return yield* refactor.apply(sourceFile, textRange);
1930
1950
  });
1951
+ var getEditsForCodeFixes = fn("LSP.getEditsForCodeFixes")(function* (codeFixes, positionOrRange, refactorName) {
1952
+ const textRange = typeof positionOrRange === "number" ? { pos: positionOrRange, end: positionOrRange } : positionOrRange;
1953
+ const fixToRun = codeFixes.find(
1954
+ (_) => codeFixNameToFullyQualifiedName(_.fixName) === refactorName && _.start <= textRange.pos && _.end >= textRange.end
1955
+ );
1956
+ if (!fixToRun) {
1957
+ return yield* fail(new RefactorNotApplicableError());
1958
+ }
1959
+ return fixToRun;
1960
+ });
1931
1961
  var getCompletionsAtPosition = fn("LSP.getCompletionsAtPosition")(function* (completions, sourceFile, position, options, formatCodeSettings) {
1932
1962
  let effectCompletions = [];
1933
1963
  for (const completion of completions) {
@@ -2011,7 +2041,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
2011
2041
  message: ts.DiagnosticCategory.Message,
2012
2042
  suggestion: ts.DiagnosticCategory.Suggestion
2013
2043
  };
2014
- const execute = (rule) => gen(function* () {
2044
+ const execute = fn("LSP.execute")(function* (rule) {
2015
2045
  const diagnostics2 = [];
2016
2046
  const codeFixes = [];
2017
2047
  const ruleNameLowered = rule.name.toLowerCase();
@@ -2792,6 +2822,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2792
2822
  if (signatures.length !== 1) {
2793
2823
  return typeParserIssue("Covariant type has no call signature", type);
2794
2824
  }
2825
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2826
+ return typeParserIssue("Invariant type should not have type parameters", type);
2827
+ }
2795
2828
  return succeed(typeChecker.getReturnTypeOfSignature(signatures[0]));
2796
2829
  }
2797
2830
  function contravariantTypeArgument(type) {
@@ -2799,6 +2832,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2799
2832
  if (signatures.length !== 1) {
2800
2833
  return typeParserIssue("Contravariant type has no call signature", type);
2801
2834
  }
2835
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2836
+ return typeParserIssue("Invariant type should not have type parameters", type);
2837
+ }
2802
2838
  return succeed(typeCheckerUtils.getTypeParameterAtPosition(signatures[0], 0));
2803
2839
  }
2804
2840
  function invariantTypeArgument(type) {
@@ -2806,6 +2842,9 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2806
2842
  if (signatures.length !== 1) {
2807
2843
  return typeParserIssue("Invariant type has no call signature", type);
2808
2844
  }
2845
+ if (signatures[0].typeParameters && signatures[0].typeParameters.length > 0) {
2846
+ return typeParserIssue("Invariant type should not have type parameters", type);
2847
+ }
2809
2848
  return succeed(typeChecker.getReturnTypeOfSignature(signatures[0]));
2810
2849
  }
2811
2850
  const pipeableType = cachedBy(
@@ -4693,32 +4732,38 @@ var catchAllToMapError = createDiagnostic({
4693
4732
  return void 0;
4694
4733
  };
4695
4734
  const getEffectFailCallInfo = (body) => {
4696
- return gen(function* () {
4697
- if (ts.isCallExpression(body)) {
4698
- const isFailCall = yield* pipe(
4699
- typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4700
- orUndefined
4701
- );
4702
- if (isFailCall && body.arguments.length >= 1) {
4703
- return { failCall: body, failArg: body.arguments[0] };
4704
- }
4705
- }
4706
- if (ts.isBlock(body)) {
4707
- const statements = body.statements;
4708
- if (statements.length === 1) {
4709
- const stmt = statements[0];
4710
- if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4711
- const isFailCall = yield* pipe(
4712
- typeParser.isNodeReferenceToEffectModuleApi("fail")(stmt.expression.expression),
4713
- orUndefined
4714
- );
4715
- if (isFailCall && stmt.expression.arguments.length >= 1) {
4716
- return { failCall: stmt.expression, failArg: stmt.expression.arguments[0] };
4717
- }
4735
+ if (ts.isCallExpression(body)) {
4736
+ return pipe(
4737
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(body.expression),
4738
+ orUndefined,
4739
+ map4((isFailCall) => {
4740
+ if (isFailCall && body.arguments.length >= 1) {
4741
+ return { failCall: body, failArg: body.arguments[0] };
4718
4742
  }
4743
+ return void 0;
4744
+ })
4745
+ );
4746
+ }
4747
+ if (ts.isBlock(body)) {
4748
+ const statements = body.statements;
4749
+ if (statements.length === 1) {
4750
+ const stmt = statements[0];
4751
+ if (ts.isReturnStatement(stmt) && stmt.expression && ts.isCallExpression(stmt.expression)) {
4752
+ const callExpr = stmt.expression;
4753
+ return pipe(
4754
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpr.expression),
4755
+ orUndefined,
4756
+ map4((isFailCall) => {
4757
+ if (isFailCall && callExpr.arguments.length >= 1) {
4758
+ return { failCall: callExpr, failArg: callExpr.arguments[0] };
4759
+ }
4760
+ return void 0;
4761
+ })
4762
+ );
4719
4763
  }
4720
4764
  }
4721
- });
4765
+ }
4766
+ return void_;
4722
4767
  };
4723
4768
  const flows = yield* typeParser.pipingFlows(true)(sourceFile);
4724
4769
  for (const flow2 of flows) {
@@ -4963,20 +5008,21 @@ var deterministicKeys = createDiagnostic({
4963
5008
  const typeScriptUtils = yield* service(TypeScriptUtils);
4964
5009
  const options = yield* service(LanguageServicePluginOptions);
4965
5010
  const parseExtendsCustom = cachedBy(
4966
- fn("parseExtendsCustom")(function* (classDeclaration) {
5011
+ (classDeclaration) => {
4967
5012
  if (!options.extendedKeyDetection) {
4968
- return yield* typeParserIssue("Extended key detection is disabled", void 0, classDeclaration);
5013
+ return TypeParserIssue.issue;
4969
5014
  }
4970
5015
  if (!classDeclaration.name) {
4971
- return yield* typeParserIssue("Class has no name", void 0, classDeclaration);
5016
+ return TypeParserIssue.issue;
4972
5017
  }
4973
5018
  if (!ts.isIdentifier(classDeclaration.name)) {
4974
- return yield* typeParserIssue("Class name is not an identifier", void 0, classDeclaration);
5019
+ return TypeParserIssue.issue;
4975
5020
  }
4976
5021
  const heritageClauses = classDeclaration.heritageClauses;
4977
5022
  if (!heritageClauses) {
4978
- return yield* typeParserIssue("Class has no heritage clauses", void 0, classDeclaration);
5023
+ return TypeParserIssue.issue;
4979
5024
  }
5025
+ const className = classDeclaration.name;
4980
5026
  const nodeToVisit2 = [...classDeclaration.heritageClauses];
4981
5027
  const appendNodeToVisit2 = (node) => {
4982
5028
  nodeToVisit2.push(node);
@@ -4997,7 +5043,7 @@ var deterministicKeys = createDiagnostic({
4997
5043
  const parameterSourceFile = typeScriptUtils.getSourceFileOfNode(declaration);
4998
5044
  const paramText = parameterSourceFile.text.substring(declaration.pos, declaration.end);
4999
5045
  if (paramText.toLowerCase().includes("@effect-identifier")) {
5000
- return { className: classDeclaration.name, keyStringLiteral: arg, target: "custom" };
5046
+ return succeed({ className, keyStringLiteral: arg, target: "custom" });
5001
5047
  }
5002
5048
  }
5003
5049
  }
@@ -5006,12 +5052,8 @@ var deterministicKeys = createDiagnostic({
5006
5052
  }
5007
5053
  ts.forEachChild(node, appendNodeToVisit2);
5008
5054
  }
5009
- return yield* typeParserIssue(
5010
- "Class does not extend any custom pattern",
5011
- void 0,
5012
- classDeclaration
5013
- );
5014
- }),
5055
+ return TypeParserIssue.issue;
5056
+ },
5015
5057
  "deterministicKeys.parseExtendsCustom",
5016
5058
  (classDeclaration) => classDeclaration
5017
5059
  );
@@ -5290,7 +5332,7 @@ var effectFnOpportunity = createDiagnostic({
5290
5332
  }
5291
5333
  return false;
5292
5334
  };
5293
- const tryExtractWithSpanExpression = (expr) => gen(function* () {
5335
+ const tryExtractWithSpanExpression = fn("effectFnOpportunity.tryExtractWithSpanExpression")(function* (expr) {
5294
5336
  if (!ts.isCallExpression(expr)) return void 0;
5295
5337
  const callee = expr.expression;
5296
5338
  const isWithSpan = yield* pipe(
@@ -5302,7 +5344,9 @@ var effectFnOpportunity = createDiagnostic({
5302
5344
  if (expr.arguments.length === 0) return void 0;
5303
5345
  return expr.arguments[0];
5304
5346
  });
5305
- const tryParseGenOpportunity = (fnNode) => gen(function* () {
5347
+ const tryParseGenOpportunity = fn(
5348
+ "effectFnOpportunity.tryParseGenOpportunity"
5349
+ )(function* (fnNode) {
5306
5350
  const bodyExpression = getBodyExpression(fnNode);
5307
5351
  if (!bodyExpression) return yield* TypeParserIssue.issue;
5308
5352
  const { pipeArguments: pipeArguments2, subject } = yield* pipe(
@@ -5338,62 +5382,67 @@ var effectFnOpportunity = createDiagnostic({
5338
5382
  orElse2(() => succeed(false))
5339
5383
  );
5340
5384
  };
5341
- const parseEffectFnOpportunityTarget = (node) => gen(function* () {
5385
+ const parseEffectFnOpportunityTargetGen = fn("effectFnOpportunity.parseEffectFnOpportunityTarget")(
5386
+ function* (node, returnType, traceName, nameIdentifier) {
5387
+ if (yield* isInsideEffectFn(node)) {
5388
+ return yield* TypeParserIssue.issue;
5389
+ }
5390
+ const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
5391
+ yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
5392
+ const opportunity = yield* pipe(
5393
+ tryParseGenOpportunity(node),
5394
+ orElse2(() => {
5395
+ if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
5396
+ return TypeParserIssue.issue;
5397
+ }
5398
+ const body = ts.isArrowFunction(node) ? node.body : node.body;
5399
+ if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
5400
+ return TypeParserIssue.issue;
5401
+ }
5402
+ return succeed({
5403
+ effectModuleName: sourceEffectModuleName,
5404
+ pipeArguments: [],
5405
+ generatorFunction: void 0,
5406
+ explicitTraceExpression: void 0
5407
+ });
5408
+ })
5409
+ );
5410
+ return {
5411
+ node,
5412
+ nameIdentifier,
5413
+ effectModuleName: opportunity.effectModuleName,
5414
+ inferredTraceName: traceName,
5415
+ explicitTraceExpression: opportunity.explicitTraceExpression,
5416
+ pipeArguments: opportunity.pipeArguments,
5417
+ generatorFunction: opportunity.generatorFunction,
5418
+ hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
5419
+ };
5420
+ }
5421
+ );
5422
+ const parseEffectFnOpportunityTarget = (node) => {
5342
5423
  if (!ts.isFunctionExpression(node) && !ts.isArrowFunction(node) && !ts.isFunctionDeclaration(node)) {
5343
- return yield* TypeParserIssue.issue;
5424
+ return TypeParserIssue.issue;
5344
5425
  }
5345
5426
  if ((ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) && node.asteriskToken) {
5346
- return yield* TypeParserIssue.issue;
5427
+ return TypeParserIssue.issue;
5347
5428
  }
5348
5429
  if (ts.isFunctionExpression(node) && node.name) {
5349
- return yield* TypeParserIssue.issue;
5430
+ return TypeParserIssue.issue;
5350
5431
  }
5351
5432
  if (node.type) {
5352
- return yield* TypeParserIssue.issue;
5353
- }
5354
- if (yield* isInsideEffectFn(node)) {
5355
- return yield* TypeParserIssue.issue;
5433
+ return TypeParserIssue.issue;
5356
5434
  }
5357
5435
  const functionType = typeChecker.getTypeAtLocation(node);
5358
- if (!functionType) return yield* TypeParserIssue.issue;
5436
+ if (!functionType) return TypeParserIssue.issue;
5359
5437
  const callSignatures = typeChecker.getSignaturesOfType(functionType, ts.SignatureKind.Call);
5360
- if (callSignatures.length !== 1) return yield* TypeParserIssue.issue;
5438
+ if (callSignatures.length !== 1) return TypeParserIssue.issue;
5361
5439
  const signature = callSignatures[0];
5362
5440
  const returnType = typeChecker.getReturnTypeOfSignature(signature);
5363
- const unionMembers = typeCheckerUtils.unrollUnionMembers(returnType);
5364
- yield* all(...unionMembers.map((member) => typeParser.strictEffectType(member, node)));
5365
5441
  const nameIdentifier = getNameIdentifier(node);
5366
5442
  const traceName = nameIdentifier ? ts.isIdentifier(nameIdentifier) ? ts.idText(nameIdentifier) : nameIdentifier.text : void 0;
5367
- if (!traceName) return yield* TypeParserIssue.issue;
5368
- const opportunity = yield* pipe(
5369
- tryParseGenOpportunity(node),
5370
- orElse2(() => {
5371
- if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) {
5372
- return TypeParserIssue.issue;
5373
- }
5374
- const body = ts.isArrowFunction(node) ? node.body : node.body;
5375
- if (!body || !ts.isBlock(body) || body.statements.length <= 5) {
5376
- return TypeParserIssue.issue;
5377
- }
5378
- return succeed({
5379
- effectModuleName: sourceEffectModuleName,
5380
- pipeArguments: [],
5381
- generatorFunction: void 0,
5382
- explicitTraceExpression: void 0
5383
- });
5384
- })
5385
- );
5386
- return {
5387
- node,
5388
- nameIdentifier,
5389
- effectModuleName: opportunity.effectModuleName,
5390
- inferredTraceName: traceName,
5391
- explicitTraceExpression: opportunity.explicitTraceExpression,
5392
- pipeArguments: opportunity.pipeArguments,
5393
- generatorFunction: opportunity.generatorFunction,
5394
- hasParamsInPipeArgs: areParametersReferencedIn(node, opportunity.pipeArguments)
5395
- };
5396
- });
5443
+ if (!traceName) return TypeParserIssue.issue;
5444
+ return parseEffectFnOpportunityTargetGen(node, returnType, traceName, nameIdentifier);
5445
+ };
5397
5446
  const getFunctionBodyBlock = (node) => {
5398
5447
  if (ts.isArrowFunction(node)) {
5399
5448
  if (ts.isBlock(node.body)) {
@@ -5634,7 +5683,7 @@ var effectInVoidSuccess = createDiagnostic({
5634
5683
  );
5635
5684
  return { voidedEffect };
5636
5685
  }
5637
- return yield* fail(typeParserIssue("expectedEffect success is not void"));
5686
+ return yield* TypeParserIssue.issue;
5638
5687
  });
5639
5688
  const entries = typeCheckerUtils.expectedAndRealType(sourceFile);
5640
5689
  for (const [node, expectedType, valueNode, realType] of entries) {
@@ -7446,25 +7495,27 @@ var generate = fn("writeTagClassAccessors.generate")(function* (sourceFile, serv
7446
7495
  return succeed(typeNode);
7447
7496
  })
7448
7497
  );
7449
- const proxySignature = (signature, atLocation2, className2) => gen(function* () {
7450
- const signatureDeclaration = typeChecker.signatureToSignatureDeclaration(
7451
- signature,
7452
- ts.SyntaxKind.FunctionType,
7453
- atLocation2,
7454
- ts.NodeBuilderFlags.NoTruncation
7455
- );
7456
- if (!signatureDeclaration) return yield* fail("error generating signature");
7457
- const returnType = yield* generateReturnType(
7458
- typeChecker.getReturnTypeOfSignature(signature),
7459
- atLocation2,
7460
- className2
7461
- );
7462
- return ts.factory.createFunctionTypeNode(
7463
- signatureDeclaration.typeParameters,
7464
- signatureDeclaration.parameters,
7465
- returnType
7466
- );
7467
- });
7498
+ const proxySignature = fn("writeTagClassAccessors.proxySignature")(
7499
+ function* (signature, atLocation2, className2) {
7500
+ const signatureDeclaration = typeChecker.signatureToSignatureDeclaration(
7501
+ signature,
7502
+ ts.SyntaxKind.FunctionType,
7503
+ atLocation2,
7504
+ ts.NodeBuilderFlags.NoTruncation
7505
+ );
7506
+ if (!signatureDeclaration) return yield* fail("error generating signature");
7507
+ const returnType = yield* generateReturnType(
7508
+ typeChecker.getReturnTypeOfSignature(signature),
7509
+ atLocation2,
7510
+ className2
7511
+ );
7512
+ return ts.factory.createFunctionTypeNode(
7513
+ signatureDeclaration.typeParameters,
7514
+ signatureDeclaration.parameters,
7515
+ returnType
7516
+ );
7517
+ }
7518
+ );
7468
7519
  for (const { property, propertyType } of involvedMembers) {
7469
7520
  const callSignatures = [];
7470
7521
  let propertyDeclaration = void 0;
@@ -7601,7 +7652,7 @@ var annotate = createCodegen({
7601
7652
  const tsUtils = yield* service(TypeScriptUtils);
7602
7653
  const typeChecker = yield* service(TypeCheckerApi);
7603
7654
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
7604
- const parse3 = (node) => gen(function* () {
7655
+ const parse3 = fn("annotate.parse")(function* (node) {
7605
7656
  let variableDeclarations = [];
7606
7657
  const result = [];
7607
7658
  if (ts.isVariableStatement(node)) {
@@ -8281,7 +8332,7 @@ var typeToSchema = createCodegen({
8281
8332
  new CodegenNotApplicableError("the typeToSchema codegen can be used only once per file")
8282
8333
  );
8283
8334
  }
8284
- const parse3 = (node) => gen(function* () {
8335
+ const parse3 = fn("typeToSchema.parse")(function* (node) {
8285
8336
  if (!ts.isTypeAliasDeclaration(node)) {
8286
8337
  return yield* fail(
8287
8338
  new CodegenNotApplicableError(
@@ -8558,73 +8609,99 @@ var preferSchemaOverJson = createDiagnostic({
8558
8609
  apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
8559
8610
  const ts = yield* service(TypeScriptApi);
8560
8611
  const typeParser = yield* service(TypeParser);
8561
- const parseJsonMethod = (node) => gen(function* () {
8562
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8563
- const expression = node.expression;
8564
- if (!ts.isPropertyAccessExpression(expression)) return yield* fail("expression is not a property access");
8565
- const objectExpr = expression.expression;
8566
- const methodName = ts.idText(expression.name);
8567
- if (!ts.isIdentifier(objectExpr) || ts.idText(objectExpr) !== "JSON") {
8568
- return yield* fail("object is not JSON");
8612
+ 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");
8613
+ const findEnclosingEffectTry = (jsonCall) => {
8614
+ const parent = jsonCall.parent;
8615
+ let lazy;
8616
+ if (ts.isArrowFunction(parent) && parent.body === jsonCall && parent.parameters.length === 0 && (!parent.typeParameters || parent.typeParameters.length === 0)) {
8617
+ lazy = parent;
8618
+ }
8619
+ if (!lazy && ts.isReturnStatement(parent) && parent.expression === jsonCall) {
8620
+ const block = parent.parent;
8621
+ if (ts.isBlock(block) && block.statements.length === 1) {
8622
+ const fn2 = block.parent;
8623
+ if ((ts.isArrowFunction(fn2) || ts.isFunctionExpression(fn2)) && fn2.parameters.length === 0 && (!fn2.typeParameters || fn2.typeParameters.length === 0)) {
8624
+ lazy = fn2;
8625
+ }
8626
+ }
8569
8627
  }
8570
- if (methodName !== "parse" && methodName !== "stringify") {
8571
- return yield* fail("method is not parse or stringify");
8628
+ if (!lazy) return void 0;
8629
+ const lazyParent = lazy.parent;
8630
+ if (ts.isCallExpression(lazyParent) && lazyParent.arguments.length > 0 && lazyParent.arguments[0] === lazy) {
8631
+ return lazyParent;
8572
8632
  }
8573
- return { node, methodName };
8574
- });
8575
- const effectTrySimple = (node) => gen(function* () {
8576
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8633
+ if (ts.isPropertyAssignment(lazyParent) && ts.isIdentifier(lazyParent.name) && ts.idText(lazyParent.name) === "try") {
8634
+ const objLiteral = lazyParent.parent;
8635
+ if (ts.isObjectLiteralExpression(objLiteral)) {
8636
+ const callExpr = objLiteral.parent;
8637
+ if (ts.isCallExpression(callExpr) && callExpr.arguments.length > 0 && callExpr.arguments[0] === objLiteral) {
8638
+ return callExpr;
8639
+ }
8640
+ }
8641
+ }
8642
+ return void 0;
8643
+ };
8644
+ const jsonCalls = [];
8645
+ const collectJsonCalls = (node) => {
8646
+ if (isJsonCall(node)) {
8647
+ jsonCalls.push(node);
8648
+ }
8649
+ ts.forEachChild(node, collectJsonCalls);
8650
+ };
8651
+ ts.forEachChild(sourceFile, collectJsonCalls);
8652
+ if (jsonCalls.length === 0) return;
8653
+ const effectTrySimple = fn("preferSchemaOverJson.effectTrySimple")(function* (node) {
8577
8654
  yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
8578
- if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
8655
+ if (node.arguments.length === 0) return yield* TypeParserIssue.issue;
8579
8656
  const lazyFn = yield* typeParser.lazyExpression(node.arguments[0]);
8580
- const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
8581
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8657
+ if (!isJsonCall(lazyFn.expression)) return yield* TypeParserIssue.issue;
8658
+ return lazyFn.expression;
8582
8659
  });
8583
- const effectTryObject = (node) => gen(function* () {
8584
- if (!ts.isCallExpression(node)) return yield* fail("node is not a call expression");
8660
+ const effectTryObject = fn("preferSchemaOverJson.effectTryObject")(function* (node) {
8585
8661
  yield* typeParser.isNodeReferenceToEffectModuleApi("try")(node.expression);
8586
- if (node.arguments.length === 0) return yield* fail("Effect.try has no arguments");
8662
+ if (node.arguments.length === 0) return yield* TypeParserIssue.issue;
8587
8663
  const arg = node.arguments[0];
8588
- if (!ts.isObjectLiteralExpression(arg)) return yield* fail("argument is not an object literal");
8664
+ if (!ts.isObjectLiteralExpression(arg)) return yield* TypeParserIssue.issue;
8589
8665
  const tryProp = arg.properties.find(
8590
8666
  (p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && ts.idText(p.name) === "try"
8591
8667
  );
8592
- if (!tryProp) return yield* fail("object has no 'try' property");
8668
+ if (!tryProp) return yield* TypeParserIssue.issue;
8593
8669
  const lazyFn = yield* typeParser.lazyExpression(tryProp.initializer);
8594
- const jsonMethod = yield* parseJsonMethod(lazyFn.expression);
8595
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8670
+ if (!isJsonCall(lazyFn.expression)) return yield* TypeParserIssue.issue;
8671
+ return lazyFn.expression;
8596
8672
  });
8597
- const jsonMethodInEffectGen = (node) => gen(function* () {
8598
- const jsonMethod = yield* parseJsonMethod(node);
8599
- const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(node);
8600
- if (!effectGen || effectGen.body.statements.length === 0) {
8601
- return yield* fail("not inside an Effect generator");
8673
+ const jsonMethodInEffectGen = fn("preferSchemaOverJson.jsonMethodInEffectGen")(
8674
+ function* (jsonCall) {
8675
+ const { effectGen, scopeNode } = yield* typeParser.findEnclosingScopes(jsonCall);
8676
+ if (!effectGen || effectGen.body.statements.length === 0) {
8677
+ return yield* TypeParserIssue.issue;
8678
+ }
8679
+ if (scopeNode && scopeNode !== effectGen.generatorFunction) {
8680
+ return yield* TypeParserIssue.issue;
8681
+ }
8682
+ return jsonCall;
8602
8683
  }
8603
- if (scopeNode && scopeNode !== effectGen.generatorFunction) {
8604
- return yield* fail("inside a nested function scope");
8684
+ );
8685
+ for (const jsonCall of jsonCalls) {
8686
+ const effectTryCall = findEnclosingEffectTry(jsonCall);
8687
+ let match2;
8688
+ if (effectTryCall) {
8689
+ match2 = yield* pipe(
8690
+ firstSuccessOf([
8691
+ effectTrySimple(effectTryCall),
8692
+ effectTryObject(effectTryCall)
8693
+ ]),
8694
+ option
8695
+ );
8696
+ } else {
8697
+ match2 = yield* pipe(
8698
+ jsonMethodInEffectGen(jsonCall),
8699
+ option
8700
+ );
8605
8701
  }
8606
- return { node: jsonMethod.node, methodName: jsonMethod.methodName };
8607
- });
8608
- const nodeToVisit = [];
8609
- const appendNodeToVisit = (node) => {
8610
- nodeToVisit.push(node);
8611
- return void 0;
8612
- };
8613
- ts.forEachChild(sourceFile, appendNodeToVisit);
8614
- while (nodeToVisit.length > 0) {
8615
- const node = nodeToVisit.shift();
8616
- ts.forEachChild(node, appendNodeToVisit);
8617
- const match2 = yield* pipe(
8618
- firstSuccessOf([
8619
- effectTrySimple(node),
8620
- effectTryObject(node),
8621
- jsonMethodInEffectGen(node)
8622
- ]),
8623
- option
8624
- );
8625
8702
  if (isSome2(match2)) {
8626
8703
  report({
8627
- location: match2.value.node,
8704
+ location: match2.value,
8628
8705
  messageText: "Consider using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify",
8629
8706
  fixes: []
8630
8707
  });
@@ -9268,19 +9345,24 @@ var strictEffectProvide = createDiagnostic({
9268
9345
  const ts = yield* service(TypeScriptApi);
9269
9346
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
9270
9347
  const typeParser = yield* service(TypeParser);
9271
- const parseEffectProvideWithLayer = (node) => gen(function* () {
9348
+ const parseEffectProvideWithLayerGen = fn("strictEffectProvide.parseEffectProvideWithLayer")(
9349
+ function* (node) {
9350
+ yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
9351
+ return yield* firstSuccessOf(
9352
+ node.arguments.map((arg) => {
9353
+ const argType = typeCheckerUtils.getTypeAtLocation(arg);
9354
+ if (!argType) return typeParserIssue("Could not get argument type");
9355
+ return typeParser.layerType(argType, arg);
9356
+ })
9357
+ );
9358
+ }
9359
+ );
9360
+ const parseEffectProvideWithLayer = (node) => {
9272
9361
  if (!ts.isCallExpression(node) || node.arguments.length === 0) {
9273
- return yield* typeParserIssue("Not an Effect.provide call");
9274
- }
9275
- yield* typeParser.isNodeReferenceToEffectModuleApi("provide")(node.expression);
9276
- return yield* firstSuccessOf(
9277
- node.arguments.map((arg) => {
9278
- const argType = typeCheckerUtils.getTypeAtLocation(arg);
9279
- if (!argType) return typeParserIssue("Could not get argument type");
9280
- return typeParser.layerType(argType, arg);
9281
- })
9282
- );
9283
- });
9362
+ return TypeParserIssue.issue;
9363
+ }
9364
+ return parseEffectProvideWithLayerGen(node);
9365
+ };
9284
9366
  const nodeToVisit = [];
9285
9367
  const appendNodeToVisit = (node) => {
9286
9368
  nodeToVisit.push(node);