effect-analyzer 0.1.0 → 0.1.3

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.
@@ -161,6 +161,38 @@ function effectTypeSignatureFromTypeText(typeText) {
161
161
  }
162
162
  return void 0;
163
163
  }
164
+ function tryResolveGenericFromInnerExpression(node, typeChecker) {
165
+ try {
166
+ const { SyntaxKind } = loadTsMorph();
167
+ if (node.getKind() === SyntaxKind.CallExpression) {
168
+ const call = node;
169
+ const expr = call.getExpression();
170
+ if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {
171
+ const propAccess = expr;
172
+ if (propAccess.getName() === "pipe") {
173
+ const baseExpr = propAccess.getExpression();
174
+ if (baseExpr) {
175
+ const baseSig = extractEffectTypeSignature(baseExpr, typeChecker);
176
+ if (baseSig && !/^[A-Z]$/.test(baseSig.errorType)) {
177
+ return { errorType: baseSig.errorType };
178
+ }
179
+ }
180
+ }
181
+ }
182
+ const args = call.getArguments();
183
+ if (args.length > 0) {
184
+ for (const arg of args) {
185
+ const argSig = extractEffectTypeSignature(arg, typeChecker);
186
+ if (argSig && !/^[A-Z]$/.test(argSig.errorType)) {
187
+ return { errorType: argSig.errorType };
188
+ }
189
+ }
190
+ }
191
+ }
192
+ } catch {
193
+ }
194
+ return void 0;
195
+ }
164
196
  var extractEffectTypeSignature = (node, _typeChecker) => {
165
197
  let nodeType;
166
198
  try {
@@ -174,9 +206,23 @@ var extractEffectTypeSignature = (node, _typeChecker) => {
174
206
  const typeArgs = extractTypeArguments(nodeType);
175
207
  if (typeArgs) {
176
208
  const [aType, eType, rType] = typeArgs;
209
+ const errorTypeStr = typeToString(eType);
210
+ if (/^[A-Z]$/.test(errorTypeStr)) {
211
+ const resolved = tryResolveGenericFromInnerExpression(node, _typeChecker);
212
+ if (resolved) {
213
+ return {
214
+ successType: typeToString(aType),
215
+ errorType: resolved.errorType,
216
+ requirementsType: typeToString(rType),
217
+ isInferred: true,
218
+ typeConfidence: "inferred",
219
+ rawTypeString: nodeType.getText()
220
+ };
221
+ }
222
+ }
177
223
  return {
178
224
  successType: typeToString(aType),
179
- errorType: typeToString(eType),
225
+ errorType: errorTypeStr,
180
226
  requirementsType: typeToString(rType),
181
227
  isInferred: true,
182
228
  typeConfidence: "declared",
@@ -185,7 +231,22 @@ var extractEffectTypeSignature = (node, _typeChecker) => {
185
231
  }
186
232
  const typeText = nodeType.getText();
187
233
  const fromText = effectTypeSignatureFromTypeText(typeText);
188
- if (fromText) return fromText;
234
+ if (fromText) {
235
+ const eTrim = fromText.errorType.trim();
236
+ if (/^[A-Z]$/.test(eTrim)) {
237
+ const resolved = tryResolveGenericFromInnerExpression(node, _typeChecker);
238
+ if (resolved) {
239
+ return {
240
+ ...fromText,
241
+ errorType: resolved.errorType,
242
+ isInferred: true,
243
+ typeConfidence: "inferred",
244
+ rawTypeString: nodeType.getText()
245
+ };
246
+ }
247
+ }
248
+ return fromText;
249
+ }
189
250
  const fromCallee = tryExtractFromCalleeReturnType(node);
190
251
  if (fromCallee) return fromCallee;
191
252
  return {
@@ -434,877 +495,680 @@ function extractLayerTypeSignature(node) {
434
495
  };
435
496
  }
436
497
 
437
- // src/analysis-utils.ts
438
- var DEFAULT_OPTIONS = {
439
- tsConfigPath: "./tsconfig.json",
440
- resolveReferences: true,
441
- maxReferenceDepth: 5,
442
- includeLocations: true,
443
- assumeImported: false,
444
- enableEffectWorkflow: false,
445
- knownEffectInternalsRoot: void 0,
446
- minDiscoveryConfidence: "low",
447
- onlyExportedPrograms: false,
448
- enableEffectFlow: false
449
- };
450
- var idCounter = 0;
451
- var generateId = () => `effect-${++idCounter}`;
452
- var nodeTextCache = /* @__PURE__ */ new WeakMap();
453
- function getNodeText(node) {
454
- let text = nodeTextCache.get(node);
455
- if (text === void 0) {
456
- text = node.getText();
457
- nodeTextCache.set(node, text);
458
- }
459
- return text;
460
- }
461
- function collectErrorTypes(nodes) {
462
- const set = /* @__PURE__ */ new Set();
463
- const visit = (list) => {
464
- for (const node of list) {
465
- if (node.type === "effect") {
466
- const err = node.typeSignature?.errorType?.trim();
467
- if (err && err !== "never") {
468
- for (const part of splitTopLevelUnion(err)) {
469
- set.add(part);
470
- }
471
- }
472
- }
473
- const children = Option2.getOrElse(getStaticChildren(node), () => []);
474
- if (children.length > 0) visit(children);
475
- }
476
- };
477
- visit(nodes);
478
- return Array.from(set).sort();
479
- }
480
- function collectDependencies(nodes) {
481
- const byName = /* @__PURE__ */ new Map();
482
- const visit = (list) => {
483
- for (const node of list) {
484
- if (node.type === "effect") {
485
- const reqs = node.requiredServices;
486
- if (reqs) {
487
- for (const r of reqs) {
488
- if (!byName.has(r.serviceId)) {
489
- byName.set(r.serviceId, {
490
- name: r.serviceId,
491
- typeSignature: r.serviceType,
492
- isLayer: false
493
- });
494
- }
495
- }
496
- }
497
- if ((node.semanticRole === "environment" || node.semanticRole === "side-effect") && node.callee) {
498
- const callee = node.callee;
499
- const looksLikeService = /^[A-Z]/.test(callee) && !callee.startsWith("Effect.") && !callee.startsWith("Schema.") && !callee.startsWith("Data.") && !callee.startsWith("Config.") && !callee.startsWith("Command.") && !callee.startsWith("Stream.") && !callee.startsWith("Option.") && !callee.startsWith("Either.") && !callee.startsWith("Cause.") && !callee.startsWith("Exit.");
500
- if (looksLikeService && !byName.has(callee)) {
501
- byName.set(callee, {
502
- name: callee,
503
- typeSignature: node.typeSignature?.requirementsType,
504
- isLayer: false
505
- });
506
- }
507
- }
508
- }
509
- const children = Option2.getOrElse(getStaticChildren(node), () => []);
510
- if (children.length > 0) visit(children);
511
- }
512
- };
513
- visit(nodes);
514
- return Array.from(byName.values());
515
- }
516
- var extractLocation = (node, filePath, includeLocations) => {
517
- if (!includeLocations) {
518
- return void 0;
519
- }
520
- const sourceFile = node.getSourceFile();
521
- const pos = node.getStart();
522
- const { line, column } = sourceFile.getLineAndColumnAtPos(pos);
523
- const endPos = node.getEnd();
524
- const end = sourceFile.getLineAndColumnAtPos(endPos);
525
- return {
526
- filePath,
527
- line,
528
- column,
529
- endLine: end.line,
530
- endColumn: end.column
531
- };
498
+ // src/analysis-patterns.ts
499
+ var ERROR_HANDLER_PATTERNS = [
500
+ ".catchAll",
501
+ ".catchTag",
502
+ ".catchAllCause",
503
+ ".catchIf",
504
+ ".catchSome",
505
+ ".catchSomeCause",
506
+ ".catchSomeDefect",
507
+ ".catchAllDefect",
508
+ ".catchTags",
509
+ ".orElse",
510
+ ".orElseFail",
511
+ ".orElseSucceed",
512
+ ".orDie",
513
+ ".orDieWith",
514
+ ".flip",
515
+ ".mapError",
516
+ ".mapErrorCause",
517
+ ".mapBoth",
518
+ ".sandbox",
519
+ ".unsandbox",
520
+ ".parallelErrors",
521
+ ".filterOrDie",
522
+ ".filterOrDieMessage",
523
+ ".filterOrElse",
524
+ ".filterOrFail",
525
+ ".match",
526
+ ".matchCause",
527
+ ".matchEffect",
528
+ ".matchCauseEffect",
529
+ ".firstSuccessOf",
530
+ ".ignore",
531
+ ".ignoreLogged",
532
+ ".eventually"
533
+ ];
534
+ var CONDITIONAL_PATTERNS = [
535
+ ".if",
536
+ ".when",
537
+ ".whenEffect",
538
+ ".whenFiberRef",
539
+ ".whenRef",
540
+ ".unless",
541
+ ".unlessEffect",
542
+ ".option",
543
+ ".either",
544
+ ".exit",
545
+ ".liftPredicate"
546
+ ];
547
+ var RESOURCE_PATTERNS = [
548
+ ".acquireRelease",
549
+ ".acquireUseRelease",
550
+ ".ensuring",
551
+ ".addFinalizer",
552
+ ".onExit",
553
+ ".onError",
554
+ ".parallelFinalizers",
555
+ ".sequentialFinalizers",
556
+ ".finalizersMask",
557
+ ".using",
558
+ ".withEarlyRelease"
559
+ ];
560
+ var COLLECTION_PATTERNS = [
561
+ ".forEach",
562
+ ".loop",
563
+ ".filter",
564
+ ".filterMap",
565
+ ".partition",
566
+ ".reduce",
567
+ ".reduceRight",
568
+ ".reduceWhile",
569
+ ".reduceEffect",
570
+ ".dropUntil",
571
+ ".dropWhile",
572
+ ".takeUntil",
573
+ ".takeWhile",
574
+ ".every",
575
+ ".exists",
576
+ ".findFirst",
577
+ ".head",
578
+ ".mergeAll",
579
+ ".replicate",
580
+ ".replicateEffect",
581
+ ".validateAll",
582
+ ".validateFirst",
583
+ ".validate",
584
+ ".validateWith"
585
+ ];
586
+ var FIBER_PATTERNS = [
587
+ "Effect.fork",
588
+ ".fork",
589
+ ".forkAll",
590
+ ".forkIn",
591
+ ".forkWithErrorHandler",
592
+ "Fiber."
593
+ ];
594
+ var TRANSFORM_OPS = {
595
+ "Effect.map": "map",
596
+ "Effect.flatMap": "flatMap",
597
+ "Effect.andThen": "andThen",
598
+ "Effect.tap": "tap",
599
+ "Effect.tapBoth": "tapBoth",
600
+ "Effect.tapError": "tapError",
601
+ "Effect.tapErrorTag": "tapErrorTag",
602
+ "Effect.tapErrorCause": "tapErrorCause",
603
+ "Effect.tapDefect": "tapDefect",
604
+ "Effect.zipLeft": "zipLeft",
605
+ "Effect.zipRight": "zipRight",
606
+ "Effect.zipWith": "zipWith",
607
+ "Effect.zip": "zip",
608
+ "Effect.as": "as",
609
+ "Effect.asVoid": "asVoid",
610
+ "Effect.asSome": "asSome",
611
+ "Effect.asSomeError": "asSomeError",
612
+ "Effect.flatten": "flatten",
613
+ "Effect.ap": "ap",
614
+ "Effect.negate": "negate",
615
+ "Effect.merge": "merge"
532
616
  };
533
- var extractJSDocDescription = (node) => {
534
- const jsDocs = node.getJsDocs?.();
535
- if (jsDocs && jsDocs.length > 0) {
536
- const firstJsDoc = jsDocs[0];
537
- if (!firstJsDoc) return void 0;
538
- const comment = firstJsDoc.getComment?.();
539
- if (comment) {
540
- let description;
541
- if (typeof comment === "string") {
542
- description = comment;
543
- } else if (Array.isArray(comment)) {
544
- description = comment.map((c) => c.text).join("\n");
545
- } else {
546
- return void 0;
547
- }
548
- const tagIndex = description.search(/\n\s*@/);
549
- if (tagIndex !== -1) {
550
- description = description.substring(0, tagIndex);
551
- }
552
- return description.trim() || void 0;
553
- }
554
- const rawText = firstJsDoc.getText();
555
- const descriptionMatch = /\/\*\*\s*\n?\s*\*\s*([^@]*?)(?=\n\s*\*\s*@|\*\/)/.exec(rawText);
556
- if (descriptionMatch?.[1]) {
557
- return descriptionMatch[1].replace(/\n\s*\*\s*/g, " ").trim() || void 0;
558
- }
559
- }
560
- const leadingComments = node.getLeadingCommentRanges();
561
- if (leadingComments.length > 0) {
562
- const lastComment = leadingComments[leadingComments.length - 1];
563
- if (!lastComment) return void 0;
564
- const commentText = lastComment.getText();
565
- if (commentText.startsWith("/**")) {
566
- const cleaned = commentText.replace(/^\/\*\*\s*/, "").replace(/\s*\*\/\s*$/, "").replace(/^\s*\*\s?/gm, "").trim();
567
- const tagIndex = cleaned.search(/\n@/);
568
- if (tagIndex !== -1) {
569
- return cleaned.substring(0, tagIndex).trim() || void 0;
570
- }
571
- return cleaned || void 0;
572
- }
573
- }
574
- return void 0;
617
+ var EFFECTFUL_TRANSFORMS = /* @__PURE__ */ new Set(["flatMap", "andThen", "tapBoth", "tapError", "tapErrorTag", "tapErrorCause", "tapDefect", "zipWith", "zipLeft", "zipRight", "zip", "ap", "flatten"]);
618
+ var isTransformCall = (callee) => callee in TRANSFORM_OPS;
619
+ var MATCH_OP_MAP = {
620
+ "Match.type": "type",
621
+ "Match.tag": "tag",
622
+ "Match.value": "value",
623
+ "Match.when": "when",
624
+ "Match.whenOr": "whenOr",
625
+ "Match.whenAnd": "whenAnd",
626
+ "Match.not": "not",
627
+ "Match.is": "is",
628
+ "Match.exhaustive": "exhaustive",
629
+ "Match.orElse": "orElse",
630
+ "Match.option": "option",
631
+ "Match.either": "either",
632
+ "Match.discriminator": "discriminator",
633
+ "Match.discriminatorsExhaustive": "discriminatorsExhaustive",
634
+ "Match.tags": "tags",
635
+ "Match.tagsExhaustive": "tagsExhaustive",
636
+ "Match.withReturnType": "withReturnType",
637
+ "Match.run": "run"
575
638
  };
576
- var extractJSDocTags = (node) => {
577
- const tryGetJsDocText = (n) => {
578
- const jsDocs = n.getJsDocs?.();
579
- if (jsDocs && jsDocs.length > 0) {
580
- return jsDocs[0].getText();
581
- }
582
- const leadingComments = n.getLeadingCommentRanges();
583
- if (leadingComments.length > 0) {
584
- const lastComment = leadingComments[leadingComments.length - 1];
585
- if (lastComment) {
586
- const commentText = lastComment.getText();
587
- if (commentText.startsWith("/**")) return commentText;
588
- }
589
- }
590
- return void 0;
591
- };
592
- let text = tryGetJsDocText(node);
593
- if (!text) {
594
- const { SyntaxKind } = loadTsMorph();
595
- let current = node.getParent();
596
- while (current && !text) {
597
- const kind = current.getKind();
598
- if (kind === SyntaxKind.VariableStatement) {
599
- text = tryGetJsDocText(current);
600
- break;
601
- }
602
- if (kind === SyntaxKind.VariableDeclarationList) {
603
- const grandparent = current.getParent();
604
- if (grandparent) {
605
- text = tryGetJsDocText(grandparent);
606
- }
607
- break;
608
- }
609
- if (kind === SyntaxKind.CallExpression || kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.VariableDeclaration || kind === SyntaxKind.ParenthesizedExpression) {
610
- current = current.getParent();
611
- } else {
612
- break;
613
- }
614
- }
615
- }
616
- if (!text) return void 0;
617
- return parseJSDocTags(text);
639
+ var EXHAUSTIVE_OPS = /* @__PURE__ */ new Set(["exhaustive", "discriminatorsExhaustive", "tagsExhaustive"]);
640
+ var isMatchCall = (callee) => callee.startsWith("Match.") && callee in MATCH_OP_MAP;
641
+ var CAUSE_OP_MAP = {
642
+ "Cause.fail": "fail",
643
+ "Cause.die": "die",
644
+ "Cause.interrupt": "interrupt",
645
+ "Cause.parallel": "parallel",
646
+ "Cause.sequential": "sequential",
647
+ "Cause.empty": "empty",
648
+ "Cause.failures": "failures",
649
+ "Cause.defects": "defects",
650
+ "Cause.interruptors": "interruptors",
651
+ "Cause.squash": "squash",
652
+ "Cause.squashWith": "squashWith",
653
+ "Cause.pretty": "pretty",
654
+ "Cause.flatten": "flatten",
655
+ "Cause.isDie": "isDie",
656
+ "Cause.isFailure": "isFailure",
657
+ "Cause.isInterrupted": "isInterrupted",
658
+ "Cause.isEmpty": "isEmpty",
659
+ "Cause.map": "map",
660
+ "Cause.filter": "filter"
618
661
  };
619
- function parseJSDocTags(rawText) {
620
- const cleaned = rawText.replace(/^\/\*\*/, "").replace(/\*\/$/, "").split("\n").map((line) => line.replace(/^\s*\*\s?/, "")).join("\n");
621
- const params = [];
622
- let returns;
623
- const throws = [];
624
- let example;
625
- const tagPattern = /@(param|returns?|throws?|exception|example)\s*(.*)/gi;
626
- let match;
627
- while ((match = tagPattern.exec(cleaned)) !== null) {
628
- const tag = match[1].toLowerCase();
629
- const rest = match[2].trim();
630
- if (tag === "param") {
631
- const paramMatch = /^(?:\{[^}]*\}\s*)?(\[?\w+(?:=[^\]]*)?]?)\s*(?:-\s*(.*))?$/.exec(rest);
632
- if (paramMatch) {
633
- const name = paramMatch[1].replace(/^\[|\]$/g, "").replace(/=.*/, "");
634
- const description = paramMatch[2]?.trim();
635
- params.push(description ? { name, description } : { name });
636
- }
637
- } else if (tag === "returns" || tag === "return") {
638
- returns = rest.replace(/^\{[^}]*\}\s*/, "").trim() || void 0;
639
- } else if (tag === "throws" || tag === "throw" || tag === "exception") {
640
- const value = rest.replace(/^\{[^}]*\}\s*/, "").trim();
641
- if (value) throws.push(value);
642
- } else if (tag === "example") {
643
- const exampleStart = match.index + match[0].length;
644
- const nextTagMatch = /\n\s*@\w/.exec(cleaned.slice(exampleStart));
645
- if (nextTagMatch) {
646
- const block = cleaned.slice(match.index + match[0].length - rest.length, exampleStart + nextTagMatch.index);
647
- example = block.trim() || void 0;
648
- } else {
649
- const block = cleaned.slice(match.index + match[0].length - rest.length);
650
- example = block.trim() || void 0;
651
- }
652
- }
653
- }
654
- if (params.length === 0 && !returns && throws.length === 0 && !example) {
655
- return void 0;
656
- }
657
- return { params, returns, throws, example };
658
- }
659
- var getJSDocFromParentVariable = (node) => {
660
- const parent = node.getParent();
661
- const { SyntaxKind } = loadTsMorph();
662
- if (parent) {
663
- const parentKind = parent.getKind();
664
- if (parentKind === SyntaxKind.VariableDeclaration) {
665
- return extractJSDocDescription(parent);
666
- }
667
- if (parentKind === SyntaxKind.ArrowFunction) {
668
- const grandparent = parent.getParent();
669
- if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
670
- return extractJSDocDescription(grandparent);
671
- }
672
- }
673
- }
674
- return void 0;
662
+ var CAUSE_CONSTRUCTORS = /* @__PURE__ */ new Set(["fail", "die", "interrupt", "parallel", "sequential", "empty"]);
663
+ var isCauseCall = (callee) => callee.startsWith("Cause.") && callee in CAUSE_OP_MAP;
664
+ var EXIT_OP_MAP = {
665
+ "Exit.succeed": "succeed",
666
+ "Exit.fail": "fail",
667
+ "Exit.die": "die",
668
+ "Exit.interrupt": "interrupt",
669
+ "Exit.void": "void",
670
+ "Exit.unit": "unit",
671
+ "Exit.match": "match",
672
+ "Exit.isSuccess": "isSuccess",
673
+ "Exit.isFailure": "isFailure",
674
+ "Exit.isInterrupted": "isInterrupted",
675
+ "Exit.when": "when",
676
+ "Exit.whenEffect": "whenEffect",
677
+ "Exit.exists": "exists",
678
+ "Exit.contains": "contains",
679
+ "Exit.flatten": "flatten",
680
+ "Exit.map": "map",
681
+ "Exit.mapBoth": "mapBoth",
682
+ "Exit.mapError": "mapError",
683
+ "Exit.flatMap": "flatMap",
684
+ "Exit.zipWith": "zipWith",
685
+ "Exit.tap": "tap",
686
+ "Exit.tapBoth": "tapBoth",
687
+ "Exit.tapError": "tapError"
675
688
  };
676
- var extractYieldVariableName = (yieldNode) => {
677
- const parent = yieldNode.getParent();
678
- const { SyntaxKind } = loadTsMorph();
679
- if (parent?.getKind() === SyntaxKind.VariableDeclaration) {
680
- return parent.getName();
681
- }
682
- return void 0;
689
+ var EXIT_CONSTRUCTORS = /* @__PURE__ */ new Set(["succeed", "fail", "die", "interrupt", "void", "unit"]);
690
+ var isExitCall = (callee) => callee.startsWith("Exit.") && (callee in EXIT_OP_MAP || /^Exit\.\w+$/.test(callee));
691
+ var SCHEDULE_OP_MAP = {
692
+ "Schedule.exponential": "exponential",
693
+ "Schedule.fibonacci": "fibonacci",
694
+ "Schedule.spaced": "spaced",
695
+ "Schedule.fixed": "fixed",
696
+ "Schedule.linear": "linear",
697
+ "Schedule.cron": "cron",
698
+ "Schedule.windowed": "windowed",
699
+ "Schedule.duration": "duration",
700
+ "Schedule.elapsed": "elapsed",
701
+ "Schedule.delays": "delays",
702
+ "Schedule.once": "once",
703
+ "Schedule.stop": "stop",
704
+ "Schedule.count": "count",
705
+ "Schedule.forever": "forever",
706
+ "Schedule.jittered": "jittered",
707
+ "Schedule.andThen": "andThen",
708
+ "Schedule.intersect": "intersect",
709
+ "Schedule.union": "union",
710
+ "Schedule.compose": "compose",
711
+ "Schedule.zipWith": "zipWith",
712
+ "Schedule.addDelay": "addDelay",
713
+ "Schedule.modifyDelay": "modifyDelay",
714
+ "Schedule.check": "check",
715
+ "Schedule.resetAfter": "resetAfter",
716
+ "Schedule.resetWhen": "resetWhen",
717
+ "Schedule.ensure": "ensure",
718
+ "Schedule.driver": "driver",
719
+ "Schedule.mapInput": "mapInput"
683
720
  };
684
- var extractProgramName = (node) => {
685
- const { SyntaxKind } = loadTsMorph();
686
- const getEnclosingVariableName = (start) => {
687
- let current = start;
688
- while (current !== void 0) {
689
- if (current.getKind() === SyntaxKind.VariableDeclaration) {
690
- return current.getName();
691
- }
692
- current = current.getParent();
693
- }
694
- return void 0;
695
- };
696
- const parent = node.getParent();
697
- if (parent) {
698
- const parentKind = parent.getKind();
699
- if (parentKind === SyntaxKind.VariableDeclaration) {
700
- return parent.getName();
701
- }
702
- if (parentKind === SyntaxKind.AwaitExpression) {
703
- const grandparent = parent.getParent();
704
- if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
705
- return grandparent.getName();
706
- }
707
- }
708
- if (parentKind === SyntaxKind.PropertyAssignment) {
709
- const property = parent;
710
- const propertyName = property.getName();
711
- const containerName = getEnclosingVariableName(parent);
712
- return containerName ? `${containerName}.${propertyName}` : propertyName;
713
- }
714
- if (parentKind === SyntaxKind.ArrowFunction) {
715
- const grandparent = parent.getParent();
716
- if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
717
- return grandparent.getName();
718
- }
719
- if (grandparent?.getKind() === SyntaxKind.PropertyAssignment) {
720
- const property = grandparent;
721
- const propertyName = property.getName();
722
- const containerName = getEnclosingVariableName(grandparent);
723
- return containerName ? `${containerName}.${propertyName}` : propertyName;
724
- }
725
- }
726
- }
727
- let ancestor = node;
728
- for (let depth = 0; ancestor && depth < 6; depth++) {
729
- ancestor = ancestor.getParent();
730
- if (!ancestor) break;
731
- const kind = ancestor.getKind();
732
- if (kind === SyntaxKind.VariableDeclaration) {
733
- return ancestor.getName();
734
- }
735
- if (kind === SyntaxKind.PropertyAssignment) {
736
- const property = ancestor;
737
- const propertyName = property.getName();
738
- const containerName = getEnclosingVariableName(ancestor);
739
- return containerName ? `${containerName}.${propertyName}` : propertyName;
740
- }
741
- if (kind === SyntaxKind.Block || kind === SyntaxKind.SourceFile) break;
742
- }
743
- return void 0;
744
- };
745
- var extractEnclosingEffectFnName = (node) => {
746
- const { SyntaxKind } = loadTsMorph();
747
- let current = node.getParent();
748
- for (let depth = 0; current && depth < 10; depth++) {
749
- if (current.getKind() === SyntaxKind.CallExpression) {
750
- const callExpr = current;
751
- const exprText = callExpr.getExpression().getText();
752
- if (exprText === "Effect.fn" || exprText.endsWith(".fn")) {
753
- const args = callExpr.getArguments();
754
- if (args.length > 0) {
755
- const firstArg = args[0].getText();
756
- const match = /^["'](.+)["']$/.exec(firstArg);
757
- if (match?.[1]) return match[1];
758
- }
759
- }
760
- }
761
- current = current.getParent();
762
- }
763
- return void 0;
764
- };
765
- var createEmptyStats = () => ({
766
- totalEffects: 0,
767
- parallelCount: 0,
768
- raceCount: 0,
769
- errorHandlerCount: 0,
770
- retryCount: 0,
771
- timeoutCount: 0,
772
- resourceCount: 0,
773
- loopCount: 0,
774
- conditionalCount: 0,
775
- layerCount: 0,
776
- interruptionCount: 0,
777
- unknownCount: 0,
778
- decisionCount: 0,
779
- switchCount: 0,
780
- tryCatchCount: 0,
781
- terminalCount: 0,
782
- opaqueCount: 0
783
- });
784
- var truncate = (s, max) => s.length <= max ? s : `${s.slice(0, max)}\u2026`;
785
- function computeDisplayName(node, variableName) {
786
- switch (node.type) {
787
- case "effect": {
788
- const prefix = variableName ?? node.name;
789
- return prefix ? `${prefix} <- ${node.callee}` : node.callee;
790
- }
791
- case "generator":
792
- return `Generator (${node.yields.length} yields)`;
793
- case "pipe":
794
- return `Pipe (${node.transformations.length} steps)`;
795
- case "parallel":
796
- return `${node.callee} (${node.children.length})`;
797
- case "race":
798
- return `${node.callee} (${node.children.length} racing)`;
799
- case "error-handler":
800
- return node.name ? `${node.name}: ${node.handlerType}` : node.handlerType;
801
- case "retry":
802
- return node.schedule ? `retry: ${node.schedule}` : "retry";
803
- case "timeout":
804
- return node.duration ? `timeout: ${node.duration}` : "timeout";
805
- case "resource":
806
- return "Resource";
807
- case "conditional":
808
- return truncate(node.condition, 30);
809
- case "loop":
810
- return node.iterSource ? `${node.loopType}(${node.iterSource})` : node.loopType;
811
- case "layer":
812
- return node.isMerged ? "Layer (merged)" : "Layer";
813
- case "stream": {
814
- const ops = node.pipeline.map((op) => op.operation);
815
- const parts = ["Stream", ...ops];
816
- if (node.sink) parts.push(node.sink);
817
- return parts.join(" \u2192 ");
818
- }
819
- case "concurrency-primitive":
820
- return `${node.primitive}.${node.operation}`;
821
- case "fiber": {
822
- const op = node.operation;
823
- if (node.isDaemon) return `${op} (daemon)`;
824
- if (node.isScoped) return `${op} (scoped)`;
825
- return op;
826
- }
827
- case "transform":
828
- return node.transformType;
829
- case "match":
830
- return `Match.${node.matchOp}`;
831
- case "cause":
832
- return `Cause.${node.causeOp}`;
833
- case "exit":
834
- return `Exit.${node.exitOp}`;
835
- case "schedule":
836
- return `Schedule.${node.scheduleOp}`;
837
- case "interruption":
838
- return node.interruptionType;
839
- case "channel": {
840
- const channelOps = node.pipeline.map((op) => op.operation);
841
- return channelOps.length > 0 ? `Channel: ${channelOps.join(" \u2192 ")}` : "Channel";
842
- }
843
- case "sink": {
844
- const sinkOps = node.pipeline.map((op) => op.operation);
845
- return sinkOps.length > 0 ? `Sink: ${sinkOps.join(" \u2192 ")}` : "Sink";
846
- }
847
- case "decision":
848
- return truncate(node.condition, 30);
849
- case "switch":
850
- return `switch(${truncate(node.expression, 25)})`;
851
- case "try-catch":
852
- return "try/catch";
853
- case "terminal":
854
- return node.label ? `${node.terminalKind} ${node.label}` : node.terminalKind;
855
- case "opaque":
856
- return `Opaque: ${truncate(node.reason, 25)}`;
857
- case "unknown":
858
- return `Unknown: ${truncate(node.reason, 30)}`;
859
- }
860
- }
861
- function computeSemanticRole(node) {
862
- switch (node.type) {
863
- case "effect": {
864
- if (node.serviceCall || node.serviceMethod) return "service-call";
865
- const desc = node.description?.toLowerCase() ?? "";
866
- if (desc.includes("service")) return "service-call";
867
- if (desc.includes("layer") || node.provideKind === "layer") return "layer";
868
- const callee = node.callee.toLowerCase();
869
- if (/^[A-Z][A-Za-z0-9_]*$/.test(node.callee) && !node.constructorKind) {
870
- return "environment";
871
- }
872
- if (callee.includes("sync") || callee.includes("promise") || callee.includes("async") || callee.includes("log") || callee.includes("console")) {
873
- return "side-effect";
874
- }
875
- if (callee.includes("succeed") || callee.includes("fail") || callee.includes("die") || callee.includes("void") || callee.includes("never") || callee.includes("gen") || callee.includes("make") || node.constructorKind) {
876
- return "constructor";
877
- }
878
- return "side-effect";
879
- }
880
- case "generator":
881
- case "pipe":
882
- return "constructor";
883
- case "parallel":
884
- case "race":
885
- case "concurrency-primitive":
886
- return "concurrency";
887
- case "error-handler":
888
- case "cause":
889
- case "exit":
890
- return "error-handler";
891
- case "retry":
892
- case "timeout":
893
- case "schedule":
894
- return "scheduling";
895
- case "resource":
896
- return "resource";
897
- case "conditional":
898
- case "loop":
899
- case "match":
900
- case "decision":
901
- case "switch":
902
- case "terminal":
903
- return "control-flow";
904
- case "try-catch":
905
- return "error-handler";
906
- case "opaque":
907
- return "unknown";
908
- case "layer":
909
- return "layer";
910
- case "stream":
911
- case "channel":
912
- case "sink":
913
- return "stream";
914
- case "fiber":
915
- case "interruption":
916
- return "fiber";
917
- case "transform":
918
- return "transform";
919
- case "unknown":
920
- return "unknown";
921
- }
922
- }
923
-
924
- // src/analysis-patterns.ts
925
- var ERROR_HANDLER_PATTERNS = [
926
- ".catchAll",
927
- ".catchTag",
928
- ".catchAllCause",
929
- ".catchIf",
930
- ".catchSome",
931
- ".catchSomeCause",
932
- ".catchSomeDefect",
933
- ".catchAllDefect",
934
- ".catchTags",
935
- ".orElse",
936
- ".orElseFail",
937
- ".orElseSucceed",
938
- ".orDie",
939
- ".orDieWith",
940
- ".flip",
941
- ".mapError",
942
- ".mapErrorCause",
943
- ".mapBoth",
944
- ".sandbox",
945
- ".unsandbox",
946
- ".parallelErrors",
947
- ".filterOrDie",
948
- ".filterOrDieMessage",
949
- ".filterOrElse",
950
- ".filterOrFail",
951
- ".match",
952
- ".matchCause",
953
- ".matchEffect",
954
- ".matchCauseEffect",
955
- ".firstSuccessOf",
956
- ".ignore",
957
- ".ignoreLogged",
958
- ".eventually"
959
- ];
960
- var CONDITIONAL_PATTERNS = [
961
- ".if",
962
- ".when",
963
- ".whenEffect",
964
- ".whenFiberRef",
965
- ".whenRef",
966
- ".unless",
967
- ".unlessEffect",
968
- ".option",
969
- ".either",
970
- ".exit",
971
- ".liftPredicate"
721
+ var isScheduleCall = (callee) => callee.startsWith("Schedule.") && (callee in SCHEDULE_OP_MAP || /^Schedule\.\w+$/.test(callee));
722
+ var INTERRUPTION_PATTERNS = [
723
+ ".interruptible",
724
+ ".uninterruptible",
725
+ ".interruptibleMask",
726
+ ".uninterruptibleMask",
727
+ ".onInterrupt",
728
+ ".disconnect",
729
+ ".allowInterrupt",
730
+ "Effect.interrupt",
731
+ ".interruptWith"
972
732
  ];
973
- var RESOURCE_PATTERNS = [
974
- ".acquireRelease",
975
- ".acquireUseRelease",
976
- ".ensuring",
977
- ".addFinalizer",
978
- ".onExit",
979
- ".onError",
980
- ".parallelFinalizers",
981
- ".sequentialFinalizers",
982
- ".finalizersMask",
983
- ".using",
984
- ".withEarlyRelease"
733
+ var DO_NOTATION_PATTERNS = [
734
+ ".Do",
735
+ ".bind",
736
+ ".bindAll",
737
+ ".bindTo"
985
738
  ];
986
- var COLLECTION_PATTERNS = [
987
- ".forEach",
988
- ".loop",
989
- ".filter",
990
- ".filterMap",
991
- ".partition",
992
- ".reduce",
993
- ".reduceRight",
994
- ".reduceWhile",
995
- ".reduceEffect",
996
- ".dropUntil",
997
- ".dropWhile",
998
- ".takeUntil",
999
- ".takeWhile",
1000
- ".every",
1001
- ".exists",
1002
- ".findFirst",
1003
- ".head",
1004
- ".mergeAll",
1005
- ".replicate",
1006
- ".replicateEffect",
1007
- ".validateAll",
1008
- ".validateFirst",
1009
- ".validate",
1010
- ".validateWith"
739
+ var CACHING_PATTERNS = [
740
+ ".cached",
741
+ ".cachedWithTTL",
742
+ ".cachedInvalidateWithTTL",
743
+ ".cachedFunction",
744
+ ".once",
745
+ "Cache.",
746
+ "ScopedCache."
1011
747
  ];
1012
- var FIBER_PATTERNS = [
1013
- "Effect.fork",
1014
- ".fork",
1015
- ".forkAll",
1016
- ".forkIn",
1017
- ".forkWithErrorHandler",
1018
- "Fiber."
748
+ var API_PREFIXES = [
749
+ "Effect.",
750
+ "Layer.",
751
+ "Schedule.",
752
+ "Stream.",
753
+ "Queue.",
754
+ "PubSub.",
755
+ "Deferred.",
756
+ "Semaphore.",
757
+ "Mailbox.",
758
+ "SubscriptionRef.",
759
+ "Scope.",
760
+ "Fiber.",
761
+ "Runtime.",
762
+ "ManagedRuntime.",
763
+ "NodeRuntime.",
764
+ "BunRuntime.",
765
+ "DenoRuntime.",
766
+ "Cause.",
767
+ "Exit.",
768
+ "Data.",
769
+ "Option.",
770
+ "Either.",
771
+ "Chunk.",
772
+ "HashMap.",
773
+ "HashSet.",
774
+ "List.",
775
+ "SortedMap.",
776
+ "SortedSet.",
777
+ "RedBlackTree.",
778
+ "Trie.",
779
+ "Graph.",
780
+ "Match.",
781
+ "Config.",
782
+ "Schema.",
783
+ "Cache.",
784
+ "ScopedCache.",
785
+ "RcRef.",
786
+ "RcMap.",
787
+ "Reloadable.",
788
+ "Cache.",
789
+ "ScopedCache.",
790
+ "RateLimiter.",
791
+ "PartitionedSemaphore.",
792
+ "FiberSet.",
793
+ "FiberMap.",
794
+ "FiberHandle.",
795
+ "Metric.",
796
+ "Logger.",
797
+ "Tracer.",
798
+ "Context.",
799
+ "HttpClient.",
800
+ "HttpRouter.",
801
+ "HttpApi.",
802
+ "FileSystem.",
803
+ "Command.",
804
+ "Socket.",
805
+ "SocketServer.",
806
+ "Worker.",
807
+ "Terminal.",
808
+ "KeyValueStore.",
809
+ "Multipart.",
810
+ "Ndjson.",
811
+ "MsgPack.",
812
+ "OpenApi.",
813
+ "OpenApiJsonSchema.",
814
+ "Brand.",
815
+ "Encoding.",
816
+ "Predicate.",
817
+ "DateTime.",
818
+ "Cron.",
819
+ "BigDecimal.",
820
+ "HashRing.",
821
+ "Redacted.",
822
+ "GlobalValue.",
823
+ "Channel.",
824
+ "Sink.",
825
+ "CliApp.",
826
+ "Args.",
827
+ "Options.",
828
+ "AiModel.",
829
+ "AiToolkit.",
830
+ "Completions.",
831
+ "AiInput.",
832
+ "AiResponse.",
833
+ "NodeSdk.",
834
+ "WebSdk.",
835
+ "Entity.",
836
+ "ClusterSchema.",
837
+ "MessageState.",
838
+ "Sharding.",
839
+ "RpcGroup.",
840
+ "RpcApi.",
841
+ "RpcClient.",
842
+ "RpcRouter.",
843
+ "SqlResolver.",
844
+ "SqlMigrator.",
845
+ "Printer.",
846
+ "Doc.",
847
+ "DocTree.",
848
+ "PageWidth.",
849
+ "Optimize."
1019
850
  ];
1020
- var TRANSFORM_OPS = {
1021
- "Effect.map": "map",
1022
- "Effect.flatMap": "flatMap",
1023
- "Effect.andThen": "andThen",
1024
- "Effect.tap": "tap",
1025
- "Effect.tapBoth": "tapBoth",
1026
- "Effect.tapError": "tapError",
1027
- "Effect.tapErrorTag": "tapErrorTag",
1028
- "Effect.tapErrorCause": "tapErrorCause",
1029
- "Effect.tapDefect": "tapDefect",
1030
- "Effect.zipLeft": "zipLeft",
1031
- "Effect.zipRight": "zipRight",
1032
- "Effect.zipWith": "zipWith",
1033
- "Effect.zip": "zip",
1034
- "Effect.as": "as",
1035
- "Effect.asVoid": "asVoid",
1036
- "Effect.asSome": "asSome",
1037
- "Effect.asSomeError": "asSomeError",
1038
- "Effect.flatten": "flatten",
1039
- "Effect.ap": "ap",
1040
- "Effect.negate": "negate",
1041
- "Effect.merge": "merge"
1042
- };
1043
- var EFFECTFUL_TRANSFORMS = /* @__PURE__ */ new Set(["flatMap", "andThen", "tapBoth", "tapError", "tapErrorTag", "tapErrorCause", "tapDefect", "zipWith", "zipLeft", "zipRight", "zip", "ap", "flatten"]);
1044
- var isTransformCall = (callee) => callee in TRANSFORM_OPS;
1045
- var MATCH_OP_MAP = {
1046
- "Match.type": "type",
1047
- "Match.tag": "tag",
1048
- "Match.value": "value",
1049
- "Match.when": "when",
1050
- "Match.whenOr": "whenOr",
1051
- "Match.whenAnd": "whenAnd",
1052
- "Match.not": "not",
1053
- "Match.is": "is",
1054
- "Match.exhaustive": "exhaustive",
1055
- "Match.orElse": "orElse",
1056
- "Match.option": "option",
1057
- "Match.either": "either",
1058
- "Match.discriminator": "discriminator",
1059
- "Match.discriminatorsExhaustive": "discriminatorsExhaustive",
1060
- "Match.tags": "tags",
1061
- "Match.tagsExhaustive": "tagsExhaustive",
1062
- "Match.withReturnType": "withReturnType",
1063
- "Match.run": "run"
851
+ var BUILT_IN_TYPE_NAMES = /* @__PURE__ */ new Set([
852
+ "Array",
853
+ "ReadonlyArray",
854
+ "String",
855
+ "Number",
856
+ "Boolean",
857
+ "Object",
858
+ "Function",
859
+ "Promise",
860
+ "Math",
861
+ "Date",
862
+ "RegExp",
863
+ "Error",
864
+ "Map",
865
+ "Set",
866
+ "WeakMap",
867
+ "WeakSet",
868
+ "Symbol",
869
+ "BigInt",
870
+ "JSON",
871
+ "Console",
872
+ "process",
873
+ "Buffer",
874
+ "EventEmitter",
875
+ "Window",
876
+ "Document",
877
+ "AbortController"
878
+ ]);
879
+ var KNOWN_EFFECT_NAMESPACES = /* @__PURE__ */ new Set([
880
+ "Effect",
881
+ "Layer",
882
+ "Stream",
883
+ "Queue",
884
+ "PubSub",
885
+ "Deferred",
886
+ "Semaphore",
887
+ "Mailbox",
888
+ "SubscriptionRef",
889
+ "Scope",
890
+ "Fiber",
891
+ "Runtime",
892
+ "ManagedRuntime",
893
+ "Cause",
894
+ "Exit",
895
+ "Data",
896
+ "Option",
897
+ "Either",
898
+ "Chunk",
899
+ "HashMap",
900
+ "HashSet",
901
+ "List",
902
+ "SortedMap",
903
+ "SortedSet",
904
+ "Match",
905
+ "Config",
906
+ "Schema",
907
+ "Schedule",
908
+ "Metric",
909
+ "Tracer",
910
+ "Logger",
911
+ "FiberRef",
912
+ "FiberHandle",
913
+ "FiberSet",
914
+ "FiberMap",
915
+ "Cache",
916
+ "ScopedCache",
917
+ "RateLimiter",
918
+ "Supervisor"
919
+ ]);
920
+ var isServiceTagCallee = (callee) => {
921
+ if (callee.includes(".")) return false;
922
+ if (KNOWN_EFFECT_NAMESPACES.has(callee)) return false;
923
+ return /^[A-Z][A-Za-z0-9]*$/.test(callee);
1064
924
  };
1065
- var EXHAUSTIVE_OPS = /* @__PURE__ */ new Set(["exhaustive", "discriminatorsExhaustive", "tagsExhaustive"]);
1066
- var isMatchCall = (callee) => callee.startsWith("Match.") && callee in MATCH_OP_MAP;
1067
- var CAUSE_OP_MAP = {
1068
- "Cause.fail": "fail",
1069
- "Cause.die": "die",
1070
- "Cause.interrupt": "interrupt",
1071
- "Cause.parallel": "parallel",
1072
- "Cause.sequential": "sequential",
1073
- "Cause.empty": "empty",
1074
- "Cause.failures": "failures",
1075
- "Cause.defects": "defects",
1076
- "Cause.interruptors": "interruptors",
1077
- "Cause.squash": "squash",
1078
- "Cause.squashWith": "squashWith",
1079
- "Cause.pretty": "pretty",
1080
- "Cause.flatten": "flatten",
1081
- "Cause.isDie": "isDie",
1082
- "Cause.isFailure": "isFailure",
1083
- "Cause.isInterrupted": "isInterrupted",
1084
- "Cause.isEmpty": "isEmpty",
1085
- "Cause.map": "map",
1086
- "Cause.filter": "filter"
925
+ var getSemanticDescription = (callee) => {
926
+ if (callee.startsWith("Channel.")) return "channel";
927
+ if (callee.startsWith("Sink.")) return "sink";
928
+ if (callee.endsWith(".never")) return "never";
929
+ if (callee.endsWith(".void")) return "void-effect";
930
+ if (callee.endsWith(".fromNullable")) return "null-coalescing";
931
+ if (callee.endsWith(".fn")) return "function-lift";
932
+ if (callee.endsWith(".fnUntraced")) return "function-lift";
933
+ if (callee.includes(".async") || callee.includes(".asyncEffect") || callee.includes(".promise") || callee.includes(".sync") || callee.includes(".suspend") || callee.includes(".succeed") || callee.includes(".fail") || callee.includes(".try")) return "constructor";
934
+ if (INTERRUPTION_PATTERNS.some((p) => callee.includes(p))) return "interruption";
935
+ if (DO_NOTATION_PATTERNS.some((p) => callee.includes(p))) return "do-notation";
936
+ if (CACHING_PATTERNS.some((p) => callee.includes(p) || callee.startsWith(p))) return "caching";
937
+ if (ERROR_HANDLER_PATTERNS.some((p) => callee.includes(p))) return "error-handler";
938
+ if (CONDITIONAL_PATTERNS.some((p) => callee.includes(p))) return "conditional";
939
+ if (RESOURCE_PATTERNS.some((p) => callee.includes(p))) return "resource";
940
+ if (COLLECTION_PATTERNS.some((p) => callee.includes(p))) return "collection";
941
+ if (FIBER_PATTERNS.some((p) => callee.includes(p))) return "fiber";
942
+ if (callee.startsWith("Stream.")) return "stream";
943
+ if (callee.startsWith("Layer.")) return "layer";
944
+ if (callee.startsWith("Schema.")) return "schema";
945
+ if (callee.startsWith("Config.")) return "config";
946
+ if (callee.startsWith("Cause.")) return "cause";
947
+ if (callee.startsWith("Exit.")) return "exit";
948
+ if (callee === "Data.tagged" || callee === "Data.taggedEnum") return "tagged-enum";
949
+ if (callee.startsWith("Data.")) return "data";
950
+ if (callee.startsWith("Option.")) return "option";
951
+ if (callee.startsWith("Either.")) return "either";
952
+ if (callee.startsWith("Match.")) return "match";
953
+ if (callee.startsWith("ManagedRuntime.")) return "runtime";
954
+ if (callee.startsWith("Runtime.")) return "runtime";
955
+ if (callee.startsWith("NodeRuntime.") || callee.startsWith("BunRuntime.") || callee.startsWith("DenoRuntime.")) return "runtime";
956
+ if (callee.startsWith("Scope.")) return "scope";
957
+ if (callee.startsWith("ScopedRef.") || callee.startsWith("RcRef.") || callee.startsWith("RcMap.")) return "resource-ref";
958
+ if (callee.startsWith("Reloadable.") || callee.startsWith("Resource.")) return "reloadable";
959
+ if (callee.startsWith("Micro.")) return "micro";
960
+ if (callee.startsWith("Brand.")) return "brand";
961
+ if (callee.startsWith("Encoding.")) return "encoding";
962
+ if (callee.startsWith("Predicate.")) return "predicate";
963
+ if (callee.startsWith("DateTime.")) return "datetime";
964
+ if (callee.startsWith("Cron.")) return "cron";
965
+ if (callee.startsWith("Redacted.")) return "redacted";
966
+ if (callee.startsWith("GlobalValue.")) return "global-value";
967
+ if (callee.startsWith("Supervisor.")) return "supervisor";
968
+ if (callee.includes(".locally") || callee.includes(".locallyWith") || callee.includes(".locallyScoped") || callee.includes(".getFiberRefs") || callee.includes(".setFiberRefs") || callee.includes(".inheritFiberRefs") || callee.includes("FiberRef.")) return "fiberref";
969
+ if (callee.includes(".withConcurrency") || callee.includes(".withScheduler") || callee.includes(".withSchedulingPriority") || callee.includes(".daemonChildren") || callee.includes(".awaitAllChildren") || callee.includes(".supervised")) return "structured-concurrency";
970
+ if (callee.startsWith("Context.pick") || callee.startsWith("Context.omit")) return "context";
971
+ if (callee === "Effect.provide" || callee.startsWith("Effect.") && callee.includes(".provide") && !callee.includes("provideService")) return "context";
972
+ if (callee.includes(".serviceOption") || callee.includes(".serviceOptional") || callee.includes(".serviceFunction") || callee.includes(".serviceFunctionEffect") || callee.includes(".serviceFunctions") || callee.includes(".serviceConstants") || callee.includes(".serviceMembers") || callee.includes(".updateService")) return "service";
973
+ if (callee.startsWith("CliApp.") || callee.startsWith("Args.") || callee.startsWith("Options.")) return "cli";
974
+ if (callee.startsWith("AiModel.") || callee.startsWith("AiToolkit.") || callee.startsWith("Completions.") || callee.startsWith("AiInput.") || callee.startsWith("AiResponse.")) return "ai";
975
+ if (callee.startsWith("NodeSdk.") || callee.startsWith("WebSdk.") || callee.startsWith("OtelMetrics.")) return "opentelemetry";
976
+ if (callee.startsWith("Entity.") || callee.startsWith("ClusterSchema.") || callee.startsWith("MessageState.") || callee.startsWith("Sharding.")) return "cluster";
977
+ if (callee.startsWith("RpcGroup.") || callee.startsWith("RpcApi.") || callee.startsWith("RpcClient.") || callee.startsWith("RpcRouter.")) return "rpc";
978
+ if (callee.startsWith("SqlResolver.") || callee.startsWith("SqlMigrator.")) return "sql";
979
+ if (callee.startsWith("DevTools.") || callee.startsWith("Server.")) return "devtools";
980
+ if (callee.startsWith("BigDecimal.")) return "big-decimal";
981
+ if (callee.startsWith("Graph.")) return "graph";
982
+ if (callee.startsWith("HashRing.")) return "hash-ring";
983
+ if (callee.startsWith("Chunk.")) return "chunk";
984
+ if (callee.startsWith("HashMap.") || callee.startsWith("HashSet.")) return "immutable-collection";
985
+ if (callee.startsWith("List.") || callee.startsWith("SortedMap.") || callee.startsWith("SortedSet.") || callee.startsWith("RedBlackTree.") || callee.startsWith("Trie.")) return "immutable-collection";
986
+ if (callee.includes(".map") || callee.includes(".flatMap") || callee.includes(".andThen") || callee.includes(".tap") || callee.includes(".tapBoth") || callee.includes(".tapError") || callee.includes(".tapErrorTag") || callee.includes(".tapErrorCause") || callee.includes(".tapDefect") || callee.includes(".zip") || callee.includes(".zipLeft") || callee.includes(".zipRight") || callee.includes(".zipWith") || callee.includes(".as") || callee.includes(".asVoid") || callee.includes(".flatten") || callee.includes(".merge") || callee.includes(".ap") || callee.includes(".validate") || callee.includes(".negate")) return "transformation";
987
+ if (callee.startsWith("Printer.") || callee.startsWith("Doc.") || callee.startsWith("DocTree.") || callee.startsWith("PageWidth.") || callee.startsWith("Optimize.")) return "printer";
988
+ if (callee.startsWith("Http") || callee.startsWith("FileSystem.") || callee.startsWith("Command.") || callee.startsWith("Socket.") || callee.startsWith("Worker.")) return "platform";
989
+ if (callee.includes("channel.") && !callee.includes("Channel")) return "channel";
990
+ return void 0;
1087
991
  };
1088
- var CAUSE_CONSTRUCTORS = /* @__PURE__ */ new Set(["fail", "die", "interrupt", "parallel", "sequential", "empty"]);
1089
- var isCauseCall = (callee) => callee.startsWith("Cause.") && callee in CAUSE_OP_MAP;
1090
- var EXIT_OP_MAP = {
1091
- "Exit.succeed": "succeed",
1092
- "Exit.fail": "fail",
1093
- "Exit.die": "die",
1094
- "Exit.interrupt": "interrupt",
1095
- "Exit.void": "void",
1096
- "Exit.unit": "unit",
1097
- "Exit.match": "match",
1098
- "Exit.isSuccess": "isSuccess",
1099
- "Exit.isFailure": "isFailure",
1100
- "Exit.isInterrupted": "isInterrupted",
1101
- "Exit.when": "when",
1102
- "Exit.whenEffect": "whenEffect",
1103
- "Exit.exists": "exists",
1104
- "Exit.contains": "contains",
1105
- "Exit.flatten": "flatten",
1106
- "Exit.map": "map",
1107
- "Exit.mapBoth": "mapBoth",
1108
- "Exit.mapError": "mapError",
1109
- "Exit.flatMap": "flatMap",
1110
- "Exit.zipWith": "zipWith",
1111
- "Exit.tap": "tap",
1112
- "Exit.tapBoth": "tapBoth",
1113
- "Exit.tapError": "tapError"
992
+ var getSemanticDescriptionWithAliases = (callee, effectAliases) => {
993
+ const direct = getSemanticDescription(callee);
994
+ if (direct) return direct;
995
+ if (effectAliases) {
996
+ const dotIndex = callee.indexOf(".");
997
+ if (dotIndex > 0) {
998
+ const prefix = callee.substring(0, dotIndex);
999
+ if (effectAliases.has(prefix)) {
1000
+ const method = callee.substring(dotIndex + 1);
1001
+ return getSemanticDescription(`Effect.${method}`);
1002
+ }
1003
+ }
1004
+ }
1005
+ return void 0;
1114
1006
  };
1115
- var EXIT_CONSTRUCTORS = /* @__PURE__ */ new Set(["succeed", "fail", "die", "interrupt", "void", "unit"]);
1116
- var isExitCall = (callee) => callee.startsWith("Exit.") && (callee in EXIT_OP_MAP || /^Exit\.\w+$/.test(callee));
1117
- var SCHEDULE_OP_MAP = {
1118
- "Schedule.exponential": "exponential",
1119
- "Schedule.fibonacci": "fibonacci",
1120
- "Schedule.spaced": "spaced",
1121
- "Schedule.fixed": "fixed",
1122
- "Schedule.linear": "linear",
1123
- "Schedule.cron": "cron",
1124
- "Schedule.windowed": "windowed",
1125
- "Schedule.duration": "duration",
1126
- "Schedule.elapsed": "elapsed",
1127
- "Schedule.delays": "delays",
1128
- "Schedule.once": "once",
1129
- "Schedule.stop": "stop",
1130
- "Schedule.count": "count",
1131
- "Schedule.forever": "forever",
1132
- "Schedule.jittered": "jittered",
1133
- "Schedule.andThen": "andThen",
1134
- "Schedule.intersect": "intersect",
1135
- "Schedule.union": "union",
1136
- "Schedule.compose": "compose",
1137
- "Schedule.zipWith": "zipWith",
1138
- "Schedule.addDelay": "addDelay",
1139
- "Schedule.modifyDelay": "modifyDelay",
1140
- "Schedule.check": "check",
1141
- "Schedule.resetAfter": "resetAfter",
1142
- "Schedule.resetWhen": "resetWhen",
1143
- "Schedule.ensure": "ensure",
1144
- "Schedule.driver": "driver",
1145
- "Schedule.mapInput": "mapInput"
1007
+ var isLikelyDirectEffectInitializer = (initializer, effectImportNames, nonProgramEffectImportNames = /* @__PURE__ */ new Set()) => {
1008
+ const { SyntaxKind } = loadTsMorph();
1009
+ const isNonProgramName = (name) => nonProgramEffectImportNames.has(name);
1010
+ const isRunEntrypointCalleeText = (exprText) => /\.run(?:Promise(?:Exit)?|Sync(?:Exit)?|Fork|Callback|Main)$/.test(exprText) || /^Runtime\.run(?:Promise|Sync|Fork)$/.test(exprText);
1011
+ const isDirectEffectCalleeText = (exprText) => {
1012
+ if (isRunEntrypointCalleeText(exprText)) {
1013
+ return false;
1014
+ }
1015
+ const isPipeCall = exprText === "pipe" || exprText.endsWith(".pipe");
1016
+ const dotIndex = exprText.indexOf(".");
1017
+ if (dotIndex > 0 && isNonProgramName(exprText.slice(0, dotIndex))) {
1018
+ return false;
1019
+ }
1020
+ return isPipeCall || [...effectImportNames].some((alias) => exprText.startsWith(`${alias}.`));
1021
+ };
1022
+ const isLikelyEffectCall = (call) => {
1023
+ const callee = call.getExpression();
1024
+ const exprText = callee.getText();
1025
+ if (isRunEntrypointCalleeText(exprText)) {
1026
+ return false;
1027
+ }
1028
+ const isPipeCall = exprText === "pipe";
1029
+ const isMethodPipeCall = callee.getKind() === SyntaxKind.PropertyAccessExpression && callee.getName() === "pipe";
1030
+ if (isPipeCall || isMethodPipeCall) {
1031
+ const argsContainEffect = call.getArguments().some(
1032
+ (arg) => isLikelyDirectEffectInitializer(arg, effectImportNames, nonProgramEffectImportNames)
1033
+ );
1034
+ if (argsContainEffect) {
1035
+ return true;
1036
+ }
1037
+ if (isMethodPipeCall) {
1038
+ const base = callee.getExpression();
1039
+ return isLikelyDirectEffectInitializer(
1040
+ base,
1041
+ effectImportNames,
1042
+ nonProgramEffectImportNames
1043
+ );
1044
+ }
1045
+ return false;
1046
+ }
1047
+ if (callee.getKind() === SyntaxKind.Identifier && effectImportNames.has(exprText) && !isNonProgramName(exprText)) {
1048
+ return true;
1049
+ }
1050
+ if (isDirectEffectCalleeText(exprText)) {
1051
+ return true;
1052
+ }
1053
+ if (callee.getKind() === SyntaxKind.PropertyAccessExpression && isLikelyDirectEffectInitializer(
1054
+ callee.getExpression(),
1055
+ effectImportNames,
1056
+ nonProgramEffectImportNames
1057
+ )) {
1058
+ return true;
1059
+ }
1060
+ return call.getArguments().some(
1061
+ (arg) => isLikelyDirectEffectInitializer(arg, effectImportNames, nonProgramEffectImportNames)
1062
+ );
1063
+ };
1064
+ const isInSameScope = (node, scope) => {
1065
+ let current = node.getParent();
1066
+ while (current && current !== scope) {
1067
+ const k = current.getKind();
1068
+ if (k === SyntaxKind.FunctionDeclaration || k === SyntaxKind.FunctionExpression || k === SyntaxKind.ArrowFunction || k === SyntaxKind.MethodDeclaration || k === SyntaxKind.GetAccessor || k === SyntaxKind.SetAccessor || k === SyntaxKind.ClassDeclaration || k === SyntaxKind.ClassExpression || k === SyntaxKind.Constructor || k === SyntaxKind.ClassStaticBlockDeclaration) {
1069
+ return false;
1070
+ }
1071
+ current = current.getParent();
1072
+ }
1073
+ return true;
1074
+ };
1075
+ const blockContainsEffectLikeUsage = (block) => {
1076
+ const callExprs = block.getDescendantsOfKind(SyntaxKind.CallExpression);
1077
+ if (callExprs.some((call) => isInSameScope(call, block) && isLikelyEffectCall(call))) {
1078
+ return true;
1079
+ }
1080
+ const awaitedExprs = block.getDescendantsOfKind(SyntaxKind.AwaitExpression);
1081
+ if (awaitedExprs.some(
1082
+ (awaitExpr) => isInSameScope(awaitExpr, block) && isLikelyDirectEffectInitializer(awaitExpr, effectImportNames, nonProgramEffectImportNames)
1083
+ )) {
1084
+ return true;
1085
+ }
1086
+ const propertyAccessExprs = block.getDescendantsOfKind(
1087
+ SyntaxKind.PropertyAccessExpression
1088
+ );
1089
+ return propertyAccessExprs.some(
1090
+ (expr) => isInSameScope(expr, block) && isLikelyDirectEffectInitializer(expr, effectImportNames, nonProgramEffectImportNames)
1091
+ );
1092
+ };
1093
+ const blockContainsRunEntrypointUsage = (block) => block.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => isInSameScope(call, block) && isRunEntrypointCalleeText(call.getExpression().getText()));
1094
+ if (initializer.getKind() === SyntaxKind.ObjectLiteralExpression) {
1095
+ const obj = initializer;
1096
+ return obj.getProperties().some((prop) => {
1097
+ if (prop.getKind() === SyntaxKind.PropertyAssignment || prop.getKind() === SyntaxKind.ShorthandPropertyAssignment) {
1098
+ const init = prop.getKind() === SyntaxKind.PropertyAssignment ? prop.getInitializer() : void 0;
1099
+ return init ? isLikelyDirectEffectInitializer(init, effectImportNames, nonProgramEffectImportNames) : false;
1100
+ }
1101
+ if (prop.getKind() === SyntaxKind.MethodDeclaration || prop.getKind() === SyntaxKind.GetAccessor || prop.getKind() === SyntaxKind.SetAccessor) {
1102
+ const body = prop.getBody();
1103
+ return body ? blockContainsEffectLikeUsage(body) : false;
1104
+ }
1105
+ return false;
1106
+ });
1107
+ }
1108
+ if (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression) {
1109
+ const fn = initializer;
1110
+ const body = fn.getBody();
1111
+ if (body.getKind() === SyntaxKind.Block) {
1112
+ const bodyBlock = body;
1113
+ const returnStmts = bodyBlock.getDescendantsOfKind(SyntaxKind.ReturnStatement);
1114
+ const hasEffectReturn = returnStmts.some((ret) => {
1115
+ if (!isInSameScope(ret, bodyBlock)) return false;
1116
+ const expr = ret.getExpression();
1117
+ return expr !== void 0 && isLikelyDirectEffectInitializer(
1118
+ expr,
1119
+ effectImportNames,
1120
+ nonProgramEffectImportNames
1121
+ );
1122
+ });
1123
+ if (hasEffectReturn) {
1124
+ return true;
1125
+ }
1126
+ if (blockContainsRunEntrypointUsage(bodyBlock)) {
1127
+ return false;
1128
+ }
1129
+ return blockContainsEffectLikeUsage(bodyBlock);
1130
+ }
1131
+ return isLikelyDirectEffectInitializer(body, effectImportNames, nonProgramEffectImportNames);
1132
+ }
1133
+ if (initializer.getKind() === SyntaxKind.CallExpression) {
1134
+ return isLikelyEffectCall(initializer);
1135
+ }
1136
+ if (initializer.getKind() === SyntaxKind.AwaitExpression) {
1137
+ const awaited = initializer.getExpression();
1138
+ if (awaited.getKind() !== SyntaxKind.CallExpression) {
1139
+ return false;
1140
+ }
1141
+ return isLikelyEffectCall(awaited);
1142
+ }
1143
+ if (initializer.getKind() === SyntaxKind.ConditionalExpression) {
1144
+ const conditional = initializer;
1145
+ return isLikelyDirectEffectInitializer(
1146
+ conditional.getWhenTrue(),
1147
+ effectImportNames,
1148
+ nonProgramEffectImportNames
1149
+ ) || isLikelyDirectEffectInitializer(
1150
+ conditional.getWhenFalse(),
1151
+ effectImportNames,
1152
+ nonProgramEffectImportNames
1153
+ );
1154
+ }
1155
+ if (initializer.getKind() === SyntaxKind.PropertyAccessExpression) {
1156
+ const text = initializer.getText();
1157
+ const dotIndex = text.indexOf(".");
1158
+ if (dotIndex > 0 && isNonProgramName(text.slice(0, dotIndex))) {
1159
+ return false;
1160
+ }
1161
+ return [...effectImportNames].some((alias) => text.startsWith(`${alias}.`));
1162
+ }
1163
+ return false;
1146
1164
  };
1147
- var isScheduleCall = (callee) => callee.startsWith("Schedule.") && (callee in SCHEDULE_OP_MAP || /^Schedule\.\w+$/.test(callee));
1148
- var INTERRUPTION_PATTERNS = [
1149
- ".interruptible",
1150
- ".uninterruptible",
1151
- ".interruptibleMask",
1152
- ".uninterruptibleMask",
1153
- ".onInterrupt",
1154
- ".disconnect",
1155
- ".allowInterrupt",
1156
- "Effect.interrupt",
1157
- ".interruptWith"
1158
- ];
1159
- var DO_NOTATION_PATTERNS = [
1160
- ".Do",
1161
- ".bind",
1162
- ".bindAll",
1163
- ".bindTo"
1164
- ];
1165
- var CACHING_PATTERNS = [
1166
- ".cached",
1167
- ".cachedWithTTL",
1168
- ".cachedInvalidateWithTTL",
1169
- ".cachedFunction",
1170
- ".once",
1171
- "Cache.",
1172
- "ScopedCache."
1173
- ];
1174
- var API_PREFIXES = [
1175
- "Effect.",
1176
- "Layer.",
1177
- "Schedule.",
1178
- "Stream.",
1179
- "Queue.",
1180
- "PubSub.",
1181
- "Deferred.",
1182
- "Semaphore.",
1183
- "Mailbox.",
1184
- "SubscriptionRef.",
1185
- "Scope.",
1186
- "Fiber.",
1187
- "Runtime.",
1188
- "ManagedRuntime.",
1189
- "NodeRuntime.",
1190
- "BunRuntime.",
1191
- "DenoRuntime.",
1192
- "Cause.",
1193
- "Exit.",
1194
- "Data.",
1195
- "Option.",
1196
- "Either.",
1197
- "Chunk.",
1198
- "HashMap.",
1199
- "HashSet.",
1200
- "List.",
1201
- "SortedMap.",
1202
- "SortedSet.",
1203
- "RedBlackTree.",
1204
- "Trie.",
1205
- "Graph.",
1206
- "Match.",
1207
- "Config.",
1208
- "Schema.",
1209
- "Cache.",
1210
- "ScopedCache.",
1211
- "RcRef.",
1212
- "RcMap.",
1213
- "Reloadable.",
1214
- "Cache.",
1215
- "ScopedCache.",
1216
- "RateLimiter.",
1217
- "PartitionedSemaphore.",
1218
- "FiberSet.",
1219
- "FiberMap.",
1220
- "FiberHandle.",
1221
- "Metric.",
1222
- "Logger.",
1223
- "Tracer.",
1224
- "Context.",
1225
- "HttpClient.",
1226
- "HttpRouter.",
1227
- "HttpApi.",
1228
- "FileSystem.",
1229
- "Command.",
1230
- "Socket.",
1231
- "SocketServer.",
1232
- "Worker.",
1233
- "Terminal.",
1234
- "KeyValueStore.",
1235
- "Multipart.",
1236
- "Ndjson.",
1237
- "MsgPack.",
1238
- "OpenApi.",
1239
- "OpenApiJsonSchema.",
1240
- "Brand.",
1241
- "Encoding.",
1242
- "Predicate.",
1243
- "DateTime.",
1244
- "Cron.",
1245
- "BigDecimal.",
1246
- "HashRing.",
1247
- "Redacted.",
1248
- "GlobalValue.",
1249
- "Channel.",
1250
- "Sink.",
1251
- "CliApp.",
1252
- "Args.",
1253
- "Options.",
1254
- "AiModel.",
1255
- "AiToolkit.",
1256
- "Completions.",
1257
- "AiInput.",
1258
- "AiResponse.",
1259
- "NodeSdk.",
1260
- "WebSdk.",
1261
- "Entity.",
1262
- "ClusterSchema.",
1263
- "MessageState.",
1264
- "Sharding.",
1265
- "RpcGroup.",
1266
- "RpcApi.",
1267
- "RpcClient.",
1268
- "RpcRouter.",
1269
- "SqlResolver.",
1270
- "SqlMigrator.",
1271
- "Printer.",
1272
- "Doc.",
1273
- "DocTree.",
1274
- "PageWidth.",
1275
- "Optimize."
1276
- ];
1277
- var BUILT_IN_TYPE_NAMES = /* @__PURE__ */ new Set([
1278
- "Array",
1279
- "ReadonlyArray",
1280
- "String",
1281
- "Number",
1282
- "Boolean",
1283
- "Object",
1284
- "Function",
1285
- "Promise",
1286
- "Math",
1287
- "Date",
1288
- "RegExp",
1289
- "Error",
1290
- "Map",
1291
- "Set",
1292
- "WeakMap",
1293
- "WeakSet",
1294
- "Symbol",
1295
- "BigInt",
1296
- "JSON",
1297
- "Console",
1298
- "process",
1299
- "Buffer",
1300
- "EventEmitter",
1301
- "Window",
1302
- "Document",
1303
- "AbortController"
1304
- ]);
1305
- var KNOWN_EFFECT_NAMESPACES = /* @__PURE__ */ new Set([
1165
+ function isEffectPackageSpecifier(specifier) {
1166
+ return specifier === "effect" || specifier.startsWith("effect/") || specifier.startsWith("@effect/");
1167
+ }
1168
+ var EFFECT_NAMESPACE_NAMES = /* @__PURE__ */ new Set([
1306
1169
  "Effect",
1307
1170
  "Layer",
1171
+ "Schedule",
1308
1172
  "Stream",
1309
1173
  "Queue",
1310
1174
  "PubSub",
@@ -1324,358 +1188,575 @@ var KNOWN_EFFECT_NAMESPACES = /* @__PURE__ */ new Set([
1324
1188
  "Chunk",
1325
1189
  "HashMap",
1326
1190
  "HashSet",
1327
- "List",
1328
- "SortedMap",
1329
- "SortedSet",
1330
1191
  "Match",
1331
1192
  "Config",
1332
1193
  "Schema",
1333
- "Schedule",
1334
- "Metric",
1335
- "Tracer",
1336
- "Logger",
1337
- "FiberRef",
1338
- "FiberHandle",
1339
- "FiberSet",
1340
- "FiberMap",
1341
1194
  "Cache",
1342
1195
  "ScopedCache",
1343
- "RateLimiter",
1344
- "Supervisor"
1196
+ "Metric",
1197
+ "Logger",
1198
+ "Tracer",
1199
+ "Context",
1200
+ "Brand",
1201
+ "Encoding",
1202
+ "Predicate",
1203
+ "DateTime",
1204
+ "Cron",
1205
+ "BigDecimal",
1206
+ "Graph",
1207
+ "HashRing",
1208
+ "Redacted",
1209
+ "GlobalValue",
1210
+ "NodeRuntime",
1211
+ "BunRuntime",
1212
+ "DenoRuntime",
1213
+ "Channel",
1214
+ "Sink"
1345
1215
  ]);
1346
- var isServiceTagCallee = (callee) => {
1347
- if (callee.includes(".")) return false;
1348
- if (KNOWN_EFFECT_NAMESPACES.has(callee)) return false;
1349
- return /^[A-Z][A-Za-z0-9]*$/.test(callee);
1216
+ var KNOWN_INTERNAL_MODULES = /* @__PURE__ */ new Set([
1217
+ "core",
1218
+ "core-effect",
1219
+ "core-stream",
1220
+ "fiberRuntime",
1221
+ "effectable",
1222
+ "channel",
1223
+ "sink",
1224
+ "layer",
1225
+ "schedule",
1226
+ "mailbox",
1227
+ "pubsub"
1228
+ ]);
1229
+ function parseServiceIdsFromContextType(requiredType) {
1230
+ const skip = /* @__PURE__ */ new Set(["never", "unknown", "any", "{}", "object"]);
1231
+ const normalized = requiredType.trim();
1232
+ if (!normalized || skip.has(normalized)) return [];
1233
+ const parts = normalized.split(/[\s|&]+/).map((s) => s.trim().split("<")[0]?.trim() ?? "");
1234
+ return parts.filter((s) => s.length > 0 && !skip.has(s));
1235
+ }
1236
+ function getNumericLiteralFromNode(node) {
1237
+ const { SyntaxKind } = loadTsMorph();
1238
+ const kind = node.getKind();
1239
+ if (kind === SyntaxKind.NumericLiteral) {
1240
+ const text = node.getText();
1241
+ const n = Number(text);
1242
+ return Number.isFinite(n) ? n : void 0;
1243
+ }
1244
+ if (kind === SyntaxKind.PrefixUnaryExpression) {
1245
+ const unary = node;
1246
+ if (unary.getOperatorToken() === SyntaxKind.MinusToken) {
1247
+ const operand = unary.getOperand();
1248
+ const v = getNumericLiteralFromNode(operand);
1249
+ return v !== void 0 ? -v : void 0;
1250
+ }
1251
+ }
1252
+ return void 0;
1253
+ }
1254
+
1255
+ // src/analysis-utils.ts
1256
+ var DEFAULT_OPTIONS = {
1257
+ tsConfigPath: "./tsconfig.json",
1258
+ resolveReferences: true,
1259
+ maxReferenceDepth: 5,
1260
+ includeLocations: true,
1261
+ assumeImported: false,
1262
+ enableEffectWorkflow: false,
1263
+ knownEffectInternalsRoot: void 0,
1264
+ minDiscoveryConfidence: "low",
1265
+ onlyExportedPrograms: false,
1266
+ enableEffectFlow: false
1267
+ };
1268
+ var idCounter = 0;
1269
+ var generateId = () => `effect-${++idCounter}`;
1270
+ var nodeTextCache = /* @__PURE__ */ new WeakMap();
1271
+ function getNodeText(node) {
1272
+ let text = nodeTextCache.get(node);
1273
+ if (text === void 0) {
1274
+ text = node.getText();
1275
+ nodeTextCache.set(node, text);
1276
+ }
1277
+ return text;
1278
+ }
1279
+ function collectErrorTypes(nodes) {
1280
+ const set = /* @__PURE__ */ new Set();
1281
+ const visit = (list) => {
1282
+ for (const node of list) {
1283
+ if (node.type === "effect") {
1284
+ const err = node.typeSignature?.errorType?.trim();
1285
+ if (err && err !== "never") {
1286
+ for (const part of splitTopLevelUnion(err)) {
1287
+ set.add(part);
1288
+ }
1289
+ }
1290
+ }
1291
+ const children = Option2.getOrElse(getStaticChildren(node), () => []);
1292
+ if (children.length > 0) visit(children);
1293
+ }
1294
+ };
1295
+ visit(nodes);
1296
+ return Array.from(set).sort();
1297
+ }
1298
+ function collectDependencies(nodes) {
1299
+ const byName = /* @__PURE__ */ new Map();
1300
+ const visit = (list) => {
1301
+ for (const node of list) {
1302
+ if (node.type === "effect") {
1303
+ const reqs = node.requiredServices;
1304
+ if (reqs) {
1305
+ for (const r of reqs) {
1306
+ if (!byName.has(r.serviceId)) {
1307
+ byName.set(r.serviceId, {
1308
+ name: r.serviceId,
1309
+ typeSignature: r.serviceType,
1310
+ isLayer: false
1311
+ });
1312
+ }
1313
+ }
1314
+ }
1315
+ if ((node.semanticRole === "environment" || node.semanticRole === "side-effect") && node.callee) {
1316
+ const callee = node.callee;
1317
+ const looksLikeService = /^[A-Z]/.test(callee) && !callee.startsWith("Effect.") && !callee.startsWith("Schema.") && !callee.startsWith("Data.") && !callee.startsWith("Config.") && !callee.startsWith("Command.") && !callee.startsWith("Stream.") && !callee.startsWith("Option.") && !callee.startsWith("Either.") && !callee.startsWith("Cause.") && !callee.startsWith("Exit.");
1318
+ if (looksLikeService && !byName.has(callee)) {
1319
+ byName.set(callee, {
1320
+ name: callee,
1321
+ typeSignature: node.typeSignature?.requirementsType,
1322
+ isLayer: false
1323
+ });
1324
+ }
1325
+ }
1326
+ }
1327
+ const children = Option2.getOrElse(getStaticChildren(node), () => []);
1328
+ if (children.length > 0) visit(children);
1329
+ }
1330
+ };
1331
+ visit(nodes);
1332
+ return Array.from(byName.values());
1333
+ }
1334
+ var extractLocation = (node, filePath, includeLocations) => {
1335
+ if (!includeLocations) {
1336
+ return void 0;
1337
+ }
1338
+ const sourceFile = node.getSourceFile();
1339
+ const pos = node.getStart();
1340
+ const { line, column } = sourceFile.getLineAndColumnAtPos(pos);
1341
+ const endPos = node.getEnd();
1342
+ const end = sourceFile.getLineAndColumnAtPos(endPos);
1343
+ return {
1344
+ filePath,
1345
+ line,
1346
+ column,
1347
+ endLine: end.line,
1348
+ endColumn: end.column
1349
+ };
1350
1350
  };
1351
- var getSemanticDescription = (callee) => {
1352
- if (callee.startsWith("Channel.")) return "channel";
1353
- if (callee.startsWith("Sink.")) return "sink";
1354
- if (callee.endsWith(".never")) return "never";
1355
- if (callee.endsWith(".void")) return "void-effect";
1356
- if (callee.endsWith(".fromNullable")) return "null-coalescing";
1357
- if (callee.endsWith(".fn")) return "function-lift";
1358
- if (callee.endsWith(".fnUntraced")) return "function-lift";
1359
- if (callee.includes(".async") || callee.includes(".asyncEffect") || callee.includes(".promise") || callee.includes(".sync") || callee.includes(".suspend") || callee.includes(".succeed") || callee.includes(".fail") || callee.includes(".try")) return "constructor";
1360
- if (INTERRUPTION_PATTERNS.some((p) => callee.includes(p))) return "interruption";
1361
- if (DO_NOTATION_PATTERNS.some((p) => callee.includes(p))) return "do-notation";
1362
- if (CACHING_PATTERNS.some((p) => callee.includes(p) || callee.startsWith(p))) return "caching";
1363
- if (ERROR_HANDLER_PATTERNS.some((p) => callee.includes(p))) return "error-handler";
1364
- if (CONDITIONAL_PATTERNS.some((p) => callee.includes(p))) return "conditional";
1365
- if (RESOURCE_PATTERNS.some((p) => callee.includes(p))) return "resource";
1366
- if (COLLECTION_PATTERNS.some((p) => callee.includes(p))) return "collection";
1367
- if (FIBER_PATTERNS.some((p) => callee.includes(p))) return "fiber";
1368
- if (callee.startsWith("Stream.")) return "stream";
1369
- if (callee.startsWith("Layer.")) return "layer";
1370
- if (callee.startsWith("Schema.")) return "schema";
1371
- if (callee.startsWith("Config.")) return "config";
1372
- if (callee.startsWith("Cause.")) return "cause";
1373
- if (callee.startsWith("Exit.")) return "exit";
1374
- if (callee === "Data.tagged" || callee === "Data.taggedEnum") return "tagged-enum";
1375
- if (callee.startsWith("Data.")) return "data";
1376
- if (callee.startsWith("Option.")) return "option";
1377
- if (callee.startsWith("Either.")) return "either";
1378
- if (callee.startsWith("Match.")) return "match";
1379
- if (callee.startsWith("ManagedRuntime.")) return "runtime";
1380
- if (callee.startsWith("Runtime.")) return "runtime";
1381
- if (callee.startsWith("NodeRuntime.") || callee.startsWith("BunRuntime.") || callee.startsWith("DenoRuntime.")) return "runtime";
1382
- if (callee.startsWith("Scope.")) return "scope";
1383
- if (callee.startsWith("ScopedRef.") || callee.startsWith("RcRef.") || callee.startsWith("RcMap.")) return "resource-ref";
1384
- if (callee.startsWith("Reloadable.") || callee.startsWith("Resource.")) return "reloadable";
1385
- if (callee.startsWith("Micro.")) return "micro";
1386
- if (callee.startsWith("Brand.")) return "brand";
1387
- if (callee.startsWith("Encoding.")) return "encoding";
1388
- if (callee.startsWith("Predicate.")) return "predicate";
1389
- if (callee.startsWith("DateTime.")) return "datetime";
1390
- if (callee.startsWith("Cron.")) return "cron";
1391
- if (callee.startsWith("Redacted.")) return "redacted";
1392
- if (callee.startsWith("GlobalValue.")) return "global-value";
1393
- if (callee.startsWith("Supervisor.")) return "supervisor";
1394
- if (callee.includes(".locally") || callee.includes(".locallyWith") || callee.includes(".locallyScoped") || callee.includes(".getFiberRefs") || callee.includes(".setFiberRefs") || callee.includes(".inheritFiberRefs") || callee.includes("FiberRef.")) return "fiberref";
1395
- if (callee.includes(".withConcurrency") || callee.includes(".withScheduler") || callee.includes(".withSchedulingPriority") || callee.includes(".daemonChildren") || callee.includes(".awaitAllChildren") || callee.includes(".supervised")) return "structured-concurrency";
1396
- if (callee.startsWith("Context.pick") || callee.startsWith("Context.omit")) return "context";
1397
- if (callee === "Effect.provide" || callee.startsWith("Effect.") && callee.includes(".provide") && !callee.includes("provideService")) return "context";
1398
- if (callee.includes(".serviceOption") || callee.includes(".serviceOptional") || callee.includes(".serviceFunction") || callee.includes(".serviceFunctionEffect") || callee.includes(".serviceFunctions") || callee.includes(".serviceConstants") || callee.includes(".serviceMembers") || callee.includes(".updateService")) return "service";
1399
- if (callee.startsWith("CliApp.") || callee.startsWith("Args.") || callee.startsWith("Options.")) return "cli";
1400
- if (callee.startsWith("AiModel.") || callee.startsWith("AiToolkit.") || callee.startsWith("Completions.") || callee.startsWith("AiInput.") || callee.startsWith("AiResponse.")) return "ai";
1401
- if (callee.startsWith("NodeSdk.") || callee.startsWith("WebSdk.") || callee.startsWith("OtelMetrics.")) return "opentelemetry";
1402
- if (callee.startsWith("Entity.") || callee.startsWith("ClusterSchema.") || callee.startsWith("MessageState.") || callee.startsWith("Sharding.")) return "cluster";
1403
- if (callee.startsWith("RpcGroup.") || callee.startsWith("RpcApi.") || callee.startsWith("RpcClient.") || callee.startsWith("RpcRouter.")) return "rpc";
1404
- if (callee.startsWith("SqlResolver.") || callee.startsWith("SqlMigrator.")) return "sql";
1405
- if (callee.startsWith("DevTools.") || callee.startsWith("Server.")) return "devtools";
1406
- if (callee.startsWith("BigDecimal.")) return "big-decimal";
1407
- if (callee.startsWith("Graph.")) return "graph";
1408
- if (callee.startsWith("HashRing.")) return "hash-ring";
1409
- if (callee.startsWith("Chunk.")) return "chunk";
1410
- if (callee.startsWith("HashMap.") || callee.startsWith("HashSet.")) return "immutable-collection";
1411
- if (callee.startsWith("List.") || callee.startsWith("SortedMap.") || callee.startsWith("SortedSet.") || callee.startsWith("RedBlackTree.") || callee.startsWith("Trie.")) return "immutable-collection";
1412
- if (callee.includes(".map") || callee.includes(".flatMap") || callee.includes(".andThen") || callee.includes(".tap") || callee.includes(".tapBoth") || callee.includes(".tapError") || callee.includes(".tapErrorTag") || callee.includes(".tapErrorCause") || callee.includes(".tapDefect") || callee.includes(".zip") || callee.includes(".zipLeft") || callee.includes(".zipRight") || callee.includes(".zipWith") || callee.includes(".as") || callee.includes(".asVoid") || callee.includes(".flatten") || callee.includes(".merge") || callee.includes(".ap") || callee.includes(".validate") || callee.includes(".negate")) return "transformation";
1413
- if (callee.startsWith("Printer.") || callee.startsWith("Doc.") || callee.startsWith("DocTree.") || callee.startsWith("PageWidth.") || callee.startsWith("Optimize.")) return "printer";
1414
- if (callee.startsWith("Http") || callee.startsWith("FileSystem.") || callee.startsWith("Command.") || callee.startsWith("Socket.") || callee.startsWith("Worker.")) return "platform";
1415
- if (callee.includes("channel.") && !callee.includes("Channel")) return "channel";
1351
+ var extractJSDocDescription = (node) => {
1352
+ const jsDocs = node.getJsDocs?.();
1353
+ if (jsDocs && jsDocs.length > 0) {
1354
+ const firstJsDoc = jsDocs[0];
1355
+ if (!firstJsDoc) return void 0;
1356
+ const comment = firstJsDoc.getComment?.();
1357
+ if (comment) {
1358
+ let description;
1359
+ if (typeof comment === "string") {
1360
+ description = comment;
1361
+ } else if (Array.isArray(comment)) {
1362
+ description = comment.map((c) => c.text).join("\n");
1363
+ } else {
1364
+ return void 0;
1365
+ }
1366
+ const tagIndex = description.search(/\n\s*@/);
1367
+ if (tagIndex !== -1) {
1368
+ description = description.substring(0, tagIndex);
1369
+ }
1370
+ return description.trim() || void 0;
1371
+ }
1372
+ const rawText = firstJsDoc.getText();
1373
+ const descriptionMatch = /\/\*\*\s*\n?\s*\*\s*([^@]*?)(?=\n\s*\*\s*@|\*\/)/.exec(rawText);
1374
+ if (descriptionMatch?.[1]) {
1375
+ return descriptionMatch[1].replace(/\n\s*\*\s*/g, " ").trim() || void 0;
1376
+ }
1377
+ }
1378
+ const leadingComments = node.getLeadingCommentRanges();
1379
+ if (leadingComments.length > 0) {
1380
+ const lastComment = leadingComments[leadingComments.length - 1];
1381
+ if (!lastComment) return void 0;
1382
+ const commentText = lastComment.getText();
1383
+ if (commentText.startsWith("/**")) {
1384
+ const cleaned = commentText.replace(/^\/\*\*\s*/, "").replace(/\s*\*\/\s*$/, "").replace(/^\s*\*\s?/gm, "").trim();
1385
+ const tagIndex = cleaned.search(/\n@/);
1386
+ if (tagIndex !== -1) {
1387
+ return cleaned.substring(0, tagIndex).trim() || void 0;
1388
+ }
1389
+ return cleaned || void 0;
1390
+ }
1391
+ }
1416
1392
  return void 0;
1417
1393
  };
1418
- var getSemanticDescriptionWithAliases = (callee, effectAliases) => {
1419
- const direct = getSemanticDescription(callee);
1420
- if (direct) return direct;
1421
- if (effectAliases) {
1422
- const dotIndex = callee.indexOf(".");
1423
- if (dotIndex > 0) {
1424
- const prefix = callee.substring(0, dotIndex);
1425
- if (effectAliases.has(prefix)) {
1426
- const method = callee.substring(dotIndex + 1);
1427
- return getSemanticDescription(`Effect.${method}`);
1394
+ var extractJSDocTags = (node) => {
1395
+ const tryGetJsDocText = (n) => {
1396
+ const jsDocs = n.getJsDocs?.();
1397
+ if (jsDocs && jsDocs.length > 0) {
1398
+ return jsDocs[0].getText();
1399
+ }
1400
+ const leadingComments = n.getLeadingCommentRanges();
1401
+ if (leadingComments.length > 0) {
1402
+ const lastComment = leadingComments[leadingComments.length - 1];
1403
+ if (lastComment) {
1404
+ const commentText = lastComment.getText();
1405
+ if (commentText.startsWith("/**")) return commentText;
1406
+ }
1407
+ }
1408
+ return void 0;
1409
+ };
1410
+ let text = tryGetJsDocText(node);
1411
+ if (!text) {
1412
+ const { SyntaxKind } = loadTsMorph();
1413
+ let current = node.getParent();
1414
+ while (current && !text) {
1415
+ const kind = current.getKind();
1416
+ if (kind === SyntaxKind.VariableStatement) {
1417
+ text = tryGetJsDocText(current);
1418
+ break;
1419
+ }
1420
+ if (kind === SyntaxKind.VariableDeclarationList) {
1421
+ const grandparent = current.getParent();
1422
+ if (grandparent) {
1423
+ text = tryGetJsDocText(grandparent);
1424
+ }
1425
+ break;
1426
+ }
1427
+ if (kind === SyntaxKind.CallExpression || kind === SyntaxKind.ArrowFunction || kind === SyntaxKind.VariableDeclaration || kind === SyntaxKind.ParenthesizedExpression) {
1428
+ current = current.getParent();
1429
+ } else {
1430
+ break;
1431
+ }
1432
+ }
1433
+ }
1434
+ if (!text) return void 0;
1435
+ return parseJSDocTags(text);
1436
+ };
1437
+ function parseJSDocTags(rawText) {
1438
+ const cleaned = rawText.replace(/^\/\*\*/, "").replace(/\*\/$/, "").split("\n").map((line) => line.replace(/^\s*\*\s?/, "")).join("\n");
1439
+ const params = [];
1440
+ let returns;
1441
+ const throws = [];
1442
+ let example;
1443
+ const tagPattern = /@(param|returns?|throws?|exception|example)\s*(.*)/gi;
1444
+ let match;
1445
+ while ((match = tagPattern.exec(cleaned)) !== null) {
1446
+ const tag = match[1].toLowerCase();
1447
+ const rest = match[2].trim();
1448
+ if (tag === "param") {
1449
+ const paramMatch = /^(?:\{[^}]*\}\s*)?(\[?\w+(?:=[^\]]*)?]?)\s*(?:-\s*(.*))?$/.exec(rest);
1450
+ if (paramMatch) {
1451
+ const name = paramMatch[1].replace(/^\[|\]$/g, "").replace(/=.*/, "");
1452
+ const description = paramMatch[2]?.trim();
1453
+ params.push(description ? { name, description } : { name });
1454
+ }
1455
+ } else if (tag === "returns" || tag === "return") {
1456
+ returns = rest.replace(/^\{[^}]*\}\s*/, "").trim() || void 0;
1457
+ } else if (tag === "throws" || tag === "throw" || tag === "exception") {
1458
+ const value = rest.replace(/^\{[^}]*\}\s*/, "").trim();
1459
+ if (value) throws.push(value);
1460
+ } else if (tag === "example") {
1461
+ const exampleStart = match.index + match[0].length;
1462
+ const nextTagMatch = /\n\s*@\w/.exec(cleaned.slice(exampleStart));
1463
+ if (nextTagMatch) {
1464
+ const block = cleaned.slice(match.index + match[0].length - rest.length, exampleStart + nextTagMatch.index);
1465
+ example = block.trim() || void 0;
1466
+ } else {
1467
+ const block = cleaned.slice(match.index + match[0].length - rest.length);
1468
+ example = block.trim() || void 0;
1469
+ }
1470
+ }
1471
+ }
1472
+ if (params.length === 0 && !returns && throws.length === 0 && !example) {
1473
+ return void 0;
1474
+ }
1475
+ return { params, returns, throws, example };
1476
+ }
1477
+ var getJSDocFromParentVariable = (node) => {
1478
+ const parent = node.getParent();
1479
+ const { SyntaxKind } = loadTsMorph();
1480
+ if (parent) {
1481
+ const parentKind = parent.getKind();
1482
+ if (parentKind === SyntaxKind.VariableDeclaration) {
1483
+ return extractJSDocDescription(parent);
1484
+ }
1485
+ if (parentKind === SyntaxKind.ArrowFunction) {
1486
+ const grandparent = parent.getParent();
1487
+ if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
1488
+ return extractJSDocDescription(grandparent);
1428
1489
  }
1429
1490
  }
1430
1491
  }
1431
1492
  return void 0;
1432
1493
  };
1433
- var isLikelyDirectEffectInitializer = (initializer, effectImportNames, nonProgramEffectImportNames = /* @__PURE__ */ new Set()) => {
1494
+ var extractYieldVariableName = (yieldNode) => {
1495
+ const parent = yieldNode.getParent();
1434
1496
  const { SyntaxKind } = loadTsMorph();
1435
- const isNonProgramName = (name) => nonProgramEffectImportNames.has(name);
1436
- const isRunEntrypointCalleeText = (exprText) => /\.run(?:Promise(?:Exit)?|Sync(?:Exit)?|Fork|Callback|Main)$/.test(exprText) || /^Runtime\.run(?:Promise|Sync|Fork)$/.test(exprText);
1437
- const isDirectEffectCalleeText = (exprText) => {
1438
- if (isRunEntrypointCalleeText(exprText)) {
1439
- return false;
1440
- }
1441
- const isPipeCall = exprText === "pipe" || exprText.endsWith(".pipe");
1442
- const dotIndex = exprText.indexOf(".");
1443
- if (dotIndex > 0 && isNonProgramName(exprText.slice(0, dotIndex))) {
1444
- return false;
1497
+ if (parent?.getKind() === SyntaxKind.VariableDeclaration) {
1498
+ return parent.getName();
1499
+ }
1500
+ return void 0;
1501
+ };
1502
+ var extractProgramName = (node) => {
1503
+ const { SyntaxKind } = loadTsMorph();
1504
+ const getEnclosingVariableName = (start) => {
1505
+ let current = start;
1506
+ while (current !== void 0) {
1507
+ if (current.getKind() === SyntaxKind.VariableDeclaration) {
1508
+ return current.getName();
1509
+ }
1510
+ current = current.getParent();
1445
1511
  }
1446
- return isPipeCall || [...effectImportNames].some((alias) => exprText.startsWith(`${alias}.`));
1512
+ return void 0;
1447
1513
  };
1448
- const isLikelyEffectCall = (call) => {
1449
- const callee = call.getExpression();
1450
- const exprText = callee.getText();
1451
- if (isRunEntrypointCalleeText(exprText)) {
1452
- return false;
1514
+ const parent = node.getParent();
1515
+ if (parent) {
1516
+ const parentKind = parent.getKind();
1517
+ if (parentKind === SyntaxKind.VariableDeclaration) {
1518
+ return parent.getName();
1453
1519
  }
1454
- const isPipeCall = exprText === "pipe";
1455
- const isMethodPipeCall = callee.getKind() === SyntaxKind.PropertyAccessExpression && callee.getName() === "pipe";
1456
- if (isPipeCall || isMethodPipeCall) {
1457
- const argsContainEffect = call.getArguments().some(
1458
- (arg) => isLikelyDirectEffectInitializer(arg, effectImportNames, nonProgramEffectImportNames)
1459
- );
1460
- if (argsContainEffect) {
1461
- return true;
1462
- }
1463
- if (isMethodPipeCall) {
1464
- const base = callee.getExpression();
1465
- return isLikelyDirectEffectInitializer(
1466
- base,
1467
- effectImportNames,
1468
- nonProgramEffectImportNames
1469
- );
1520
+ if (parentKind === SyntaxKind.AwaitExpression) {
1521
+ const grandparent = parent.getParent();
1522
+ if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
1523
+ return grandparent.getName();
1470
1524
  }
1471
- return false;
1472
- }
1473
- if (callee.getKind() === SyntaxKind.Identifier && effectImportNames.has(exprText) && !isNonProgramName(exprText)) {
1474
- return true;
1475
- }
1476
- if (isDirectEffectCalleeText(exprText)) {
1477
- return true;
1478
1525
  }
1479
- if (callee.getKind() === SyntaxKind.PropertyAccessExpression && isLikelyDirectEffectInitializer(
1480
- callee.getExpression(),
1481
- effectImportNames,
1482
- nonProgramEffectImportNames
1483
- )) {
1484
- return true;
1526
+ if (parentKind === SyntaxKind.PropertyAssignment) {
1527
+ const property = parent;
1528
+ const propertyName = property.getName();
1529
+ const containerName = getEnclosingVariableName(parent);
1530
+ return containerName ? `${containerName}.${propertyName}` : propertyName;
1485
1531
  }
1486
- return call.getArguments().some(
1487
- (arg) => isLikelyDirectEffectInitializer(arg, effectImportNames, nonProgramEffectImportNames)
1488
- );
1489
- };
1490
- const isInSameScope = (node, scope) => {
1491
- let current = node.getParent();
1492
- while (current && current !== scope) {
1493
- const k = current.getKind();
1494
- if (k === SyntaxKind.FunctionDeclaration || k === SyntaxKind.FunctionExpression || k === SyntaxKind.ArrowFunction || k === SyntaxKind.MethodDeclaration || k === SyntaxKind.GetAccessor || k === SyntaxKind.SetAccessor || k === SyntaxKind.ClassDeclaration || k === SyntaxKind.ClassExpression || k === SyntaxKind.Constructor || k === SyntaxKind.ClassStaticBlockDeclaration) {
1495
- return false;
1532
+ if (parentKind === SyntaxKind.ArrowFunction) {
1533
+ const grandparent = parent.getParent();
1534
+ if (grandparent?.getKind() === SyntaxKind.VariableDeclaration) {
1535
+ return grandparent.getName();
1536
+ }
1537
+ if (grandparent?.getKind() === SyntaxKind.PropertyAssignment) {
1538
+ const property = grandparent;
1539
+ const propertyName = property.getName();
1540
+ const containerName = getEnclosingVariableName(grandparent);
1541
+ return containerName ? `${containerName}.${propertyName}` : propertyName;
1496
1542
  }
1497
- current = current.getParent();
1498
1543
  }
1499
- return true;
1500
- };
1501
- const blockContainsEffectLikeUsage = (block) => {
1502
- const callExprs = block.getDescendantsOfKind(SyntaxKind.CallExpression);
1503
- if (callExprs.some((call) => isInSameScope(call, block) && isLikelyEffectCall(call))) {
1504
- return true;
1544
+ }
1545
+ let ancestor = node;
1546
+ for (let depth = 0; ancestor && depth < 6; depth++) {
1547
+ ancestor = ancestor.getParent();
1548
+ if (!ancestor) break;
1549
+ const kind = ancestor.getKind();
1550
+ if (kind === SyntaxKind.VariableDeclaration) {
1551
+ return ancestor.getName();
1505
1552
  }
1506
- const awaitedExprs = block.getDescendantsOfKind(SyntaxKind.AwaitExpression);
1507
- if (awaitedExprs.some(
1508
- (awaitExpr) => isInSameScope(awaitExpr, block) && isLikelyDirectEffectInitializer(awaitExpr, effectImportNames, nonProgramEffectImportNames)
1509
- )) {
1510
- return true;
1553
+ if (kind === SyntaxKind.PropertyAssignment) {
1554
+ const property = ancestor;
1555
+ const propertyName = property.getName();
1556
+ const containerName = getEnclosingVariableName(ancestor);
1557
+ return containerName ? `${containerName}.${propertyName}` : propertyName;
1511
1558
  }
1512
- const propertyAccessExprs = block.getDescendantsOfKind(
1513
- SyntaxKind.PropertyAccessExpression
1514
- );
1515
- return propertyAccessExprs.some(
1516
- (expr) => isInSameScope(expr, block) && isLikelyDirectEffectInitializer(expr, effectImportNames, nonProgramEffectImportNames)
1517
- );
1518
- };
1519
- const blockContainsRunEntrypointUsage = (block) => block.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => isInSameScope(call, block) && isRunEntrypointCalleeText(call.getExpression().getText()));
1520
- if (initializer.getKind() === SyntaxKind.ObjectLiteralExpression) {
1521
- const obj = initializer;
1522
- return obj.getProperties().some((prop) => {
1523
- if (prop.getKind() === SyntaxKind.PropertyAssignment || prop.getKind() === SyntaxKind.ShorthandPropertyAssignment) {
1524
- const init = prop.getKind() === SyntaxKind.PropertyAssignment ? prop.getInitializer() : void 0;
1525
- return init ? isLikelyDirectEffectInitializer(init, effectImportNames, nonProgramEffectImportNames) : false;
1526
- }
1527
- if (prop.getKind() === SyntaxKind.MethodDeclaration || prop.getKind() === SyntaxKind.GetAccessor || prop.getKind() === SyntaxKind.SetAccessor) {
1528
- const body = prop.getBody();
1529
- return body ? blockContainsEffectLikeUsage(body) : false;
1559
+ if (kind === SyntaxKind.Block || kind === SyntaxKind.SourceFile) break;
1560
+ }
1561
+ return void 0;
1562
+ };
1563
+ var extractEnclosingEffectFnName = (node) => {
1564
+ const { SyntaxKind } = loadTsMorph();
1565
+ let current = node.getParent();
1566
+ for (let depth = 0; current && depth < 10; depth++) {
1567
+ if (current.getKind() === SyntaxKind.CallExpression) {
1568
+ const callExpr = current;
1569
+ const exprText = callExpr.getExpression().getText();
1570
+ if (exprText === "Effect.fn" || exprText.endsWith(".fn")) {
1571
+ const args = callExpr.getArguments();
1572
+ if (args.length > 0) {
1573
+ const firstArg = args[0].getText();
1574
+ const match = /^["'](.+)["']$/.exec(firstArg);
1575
+ if (match?.[1]) return match[1];
1576
+ }
1530
1577
  }
1531
- return false;
1532
- });
1578
+ }
1579
+ current = current.getParent();
1533
1580
  }
1534
- if (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression) {
1535
- const fn = initializer;
1536
- const body = fn.getBody();
1537
- if (body.getKind() === SyntaxKind.Block) {
1538
- const bodyBlock = body;
1539
- const returnStmts = bodyBlock.getDescendantsOfKind(SyntaxKind.ReturnStatement);
1540
- const hasEffectReturn = returnStmts.some((ret) => {
1541
- if (!isInSameScope(ret, bodyBlock)) return false;
1542
- const expr = ret.getExpression();
1543
- return expr !== void 0 && isLikelyDirectEffectInitializer(
1544
- expr,
1545
- effectImportNames,
1546
- nonProgramEffectImportNames
1547
- );
1548
- });
1549
- if (hasEffectReturn) {
1550
- return true;
1581
+ return void 0;
1582
+ };
1583
+ var createEmptyStats = () => ({
1584
+ totalEffects: 0,
1585
+ parallelCount: 0,
1586
+ raceCount: 0,
1587
+ errorHandlerCount: 0,
1588
+ retryCount: 0,
1589
+ timeoutCount: 0,
1590
+ resourceCount: 0,
1591
+ loopCount: 0,
1592
+ conditionalCount: 0,
1593
+ layerCount: 0,
1594
+ interruptionCount: 0,
1595
+ unknownCount: 0,
1596
+ decisionCount: 0,
1597
+ switchCount: 0,
1598
+ tryCatchCount: 0,
1599
+ terminalCount: 0,
1600
+ opaqueCount: 0
1601
+ });
1602
+ var DEFAULT_LABEL_MAX = 60;
1603
+ function truncateDisplayText(s, max = DEFAULT_LABEL_MAX) {
1604
+ return s.length <= max ? s : `${s.slice(0, max)}\u2026`;
1605
+ }
1606
+ var truncate = truncateDisplayText;
1607
+ function extractFunctionName(callee) {
1608
+ const withoutArgs = callee.replace(/\(.*$/, "");
1609
+ const parts = withoutArgs.split(".");
1610
+ if (parts.length <= 1) return withoutArgs;
1611
+ const receiver = parts[0] ?? "";
1612
+ if (KNOWN_EFFECT_NAMESPACES.has(receiver) || BUILT_IN_TYPE_NAMES.has(receiver)) {
1613
+ return parts[parts.length - 1] ?? withoutArgs;
1614
+ }
1615
+ return withoutArgs;
1616
+ }
1617
+ function computeDisplayName(node, variableName) {
1618
+ switch (node.type) {
1619
+ case "effect": {
1620
+ const fnName = extractFunctionName(node.callee);
1621
+ if (variableName) {
1622
+ return truncate(`${variableName} <- ${fnName}`, 60);
1551
1623
  }
1552
- if (blockContainsRunEntrypointUsage(bodyBlock)) {
1553
- return false;
1624
+ if (node.name) {
1625
+ return truncate(`${node.name} <- ${fnName}`, 60);
1554
1626
  }
1555
- return blockContainsEffectLikeUsage(bodyBlock);
1627
+ return truncate(fnName, 60);
1628
+ }
1629
+ case "generator":
1630
+ return `Generator (${node.yields.length} yields)`;
1631
+ case "pipe":
1632
+ return `Pipe (${node.transformations.length} steps)`;
1633
+ case "parallel":
1634
+ return `${node.callee} (${node.children.length})`;
1635
+ case "race":
1636
+ return `${node.callee} (${node.children.length} racing)`;
1637
+ case "error-handler":
1638
+ return node.name ? `${node.name}: ${node.handlerType}` : node.handlerType;
1639
+ case "retry":
1640
+ return node.schedule ? `retry: ${node.schedule}` : "retry";
1641
+ case "timeout":
1642
+ return node.duration ? `timeout: ${node.duration}` : "timeout";
1643
+ case "resource":
1644
+ return "Resource";
1645
+ case "conditional":
1646
+ return truncate(node.condition, 30);
1647
+ case "loop":
1648
+ return node.iterSource ? truncate(`${node.loopType}(${node.iterSource})`, 60) : node.loopType;
1649
+ case "layer":
1650
+ return node.isMerged ? "Layer (merged)" : "Layer";
1651
+ case "stream": {
1652
+ const ops = node.pipeline.map((op) => op.operation);
1653
+ const parts = ["Stream", ...ops];
1654
+ if (node.sink) parts.push(node.sink);
1655
+ return truncate(parts.join(" \u2192 "), 60);
1556
1656
  }
1557
- return isLikelyDirectEffectInitializer(body, effectImportNames, nonProgramEffectImportNames);
1558
- }
1559
- if (initializer.getKind() === SyntaxKind.CallExpression) {
1560
- return isLikelyEffectCall(initializer);
1561
- }
1562
- if (initializer.getKind() === SyntaxKind.AwaitExpression) {
1563
- const awaited = initializer.getExpression();
1564
- if (awaited.getKind() !== SyntaxKind.CallExpression) {
1565
- return false;
1657
+ case "concurrency-primitive":
1658
+ return `${node.primitive}.${node.operation}`;
1659
+ case "fiber": {
1660
+ const op = node.operation;
1661
+ if (node.isDaemon) return `${op} (daemon)`;
1662
+ if (node.isScoped) return `${op} (scoped)`;
1663
+ return op;
1566
1664
  }
1567
- return isLikelyEffectCall(awaited);
1568
- }
1569
- if (initializer.getKind() === SyntaxKind.ConditionalExpression) {
1570
- const conditional = initializer;
1571
- return isLikelyDirectEffectInitializer(
1572
- conditional.getWhenTrue(),
1573
- effectImportNames,
1574
- nonProgramEffectImportNames
1575
- ) || isLikelyDirectEffectInitializer(
1576
- conditional.getWhenFalse(),
1577
- effectImportNames,
1578
- nonProgramEffectImportNames
1579
- );
1580
- }
1581
- if (initializer.getKind() === SyntaxKind.PropertyAccessExpression) {
1582
- const text = initializer.getText();
1583
- const dotIndex = text.indexOf(".");
1584
- if (dotIndex > 0 && isNonProgramName(text.slice(0, dotIndex))) {
1585
- return false;
1665
+ case "transform":
1666
+ return node.transformType;
1667
+ case "match":
1668
+ return `Match.${node.matchOp}`;
1669
+ case "cause":
1670
+ return `Cause.${node.causeOp}`;
1671
+ case "exit":
1672
+ return `Exit.${node.exitOp}`;
1673
+ case "schedule":
1674
+ return `Schedule.${node.scheduleOp}`;
1675
+ case "interruption":
1676
+ return node.interruptionType;
1677
+ case "channel": {
1678
+ const channelOps = node.pipeline.map((op) => op.operation);
1679
+ return channelOps.length > 0 ? `Channel: ${channelOps.join(" \u2192 ")}` : "Channel";
1586
1680
  }
1587
- return [...effectImportNames].some((alias) => text.startsWith(`${alias}.`));
1681
+ case "sink": {
1682
+ const sinkOps = node.pipeline.map((op) => op.operation);
1683
+ return sinkOps.length > 0 ? `Sink: ${sinkOps.join(" \u2192 ")}` : "Sink";
1684
+ }
1685
+ case "decision":
1686
+ return truncate(node.condition, 30);
1687
+ case "switch":
1688
+ return `switch(${truncate(node.expression, 25)})`;
1689
+ case "try-catch":
1690
+ return "try/catch";
1691
+ case "terminal":
1692
+ return node.label ? `${node.terminalKind} ${node.label}` : node.terminalKind;
1693
+ case "opaque":
1694
+ return `Opaque: ${truncate(node.reason, 25)}`;
1695
+ case "unknown":
1696
+ return `Unknown: ${truncate(node.reason, 30)}`;
1588
1697
  }
1589
- return false;
1590
- };
1591
- function isEffectPackageSpecifier(specifier) {
1592
- return specifier === "effect" || specifier.startsWith("effect/") || specifier.startsWith("@effect/");
1593
- }
1594
- var EFFECT_NAMESPACE_NAMES = /* @__PURE__ */ new Set([
1595
- "Effect",
1596
- "Layer",
1597
- "Schedule",
1598
- "Stream",
1599
- "Queue",
1600
- "PubSub",
1601
- "Deferred",
1602
- "Semaphore",
1603
- "Mailbox",
1604
- "SubscriptionRef",
1605
- "Scope",
1606
- "Fiber",
1607
- "Runtime",
1608
- "ManagedRuntime",
1609
- "Cause",
1610
- "Exit",
1611
- "Data",
1612
- "Option",
1613
- "Either",
1614
- "Chunk",
1615
- "HashMap",
1616
- "HashSet",
1617
- "Match",
1618
- "Config",
1619
- "Schema",
1620
- "Cache",
1621
- "ScopedCache",
1622
- "Metric",
1623
- "Logger",
1624
- "Tracer",
1625
- "Context",
1626
- "Brand",
1627
- "Encoding",
1628
- "Predicate",
1629
- "DateTime",
1630
- "Cron",
1631
- "BigDecimal",
1632
- "Graph",
1633
- "HashRing",
1634
- "Redacted",
1635
- "GlobalValue",
1636
- "NodeRuntime",
1637
- "BunRuntime",
1638
- "DenoRuntime",
1639
- "Channel",
1640
- "Sink"
1641
- ]);
1642
- var KNOWN_INTERNAL_MODULES = /* @__PURE__ */ new Set([
1643
- "core",
1644
- "core-effect",
1645
- "core-stream",
1646
- "fiberRuntime",
1647
- "effectable",
1648
- "channel",
1649
- "sink",
1650
- "layer",
1651
- "schedule",
1652
- "mailbox",
1653
- "pubsub"
1654
- ]);
1655
- function parseServiceIdsFromContextType(requiredType) {
1656
- const skip = /* @__PURE__ */ new Set(["never", "unknown", "any", "{}", "object"]);
1657
- const normalized = requiredType.trim();
1658
- if (!normalized || skip.has(normalized)) return [];
1659
- const parts = normalized.split(/[\s|&]+/).map((s) => s.trim().split("<")[0]?.trim() ?? "");
1660
- return parts.filter((s) => s.length > 0 && !skip.has(s));
1661
1698
  }
1662
- function getNumericLiteralFromNode(node) {
1663
- const { SyntaxKind } = loadTsMorph();
1664
- const kind = node.getKind();
1665
- if (kind === SyntaxKind.NumericLiteral) {
1666
- const text = node.getText();
1667
- const n = Number(text);
1668
- return Number.isFinite(n) ? n : void 0;
1669
- }
1670
- if (kind === SyntaxKind.PrefixUnaryExpression) {
1671
- const unary = node;
1672
- if (unary.getOperatorToken() === SyntaxKind.MinusToken) {
1673
- const operand = unary.getOperand();
1674
- const v = getNumericLiteralFromNode(operand);
1675
- return v !== void 0 ? -v : void 0;
1699
+ function computeSemanticRole(node) {
1700
+ switch (node.type) {
1701
+ case "effect": {
1702
+ if (node.serviceCall || node.serviceMethod) return "service-call";
1703
+ const desc = node.description?.toLowerCase() ?? "";
1704
+ if (desc.includes("service")) return "service-call";
1705
+ if (desc.includes("layer") || node.provideKind === "layer") return "layer";
1706
+ const callee = node.callee.toLowerCase();
1707
+ if (/^[A-Z][A-Za-z0-9_]*$/.test(node.callee) && !node.constructorKind) {
1708
+ return "environment";
1709
+ }
1710
+ if (callee.includes("sync") || callee.includes("promise") || callee.includes("async") || callee.includes("log") || callee.includes("console")) {
1711
+ return "side-effect";
1712
+ }
1713
+ if (callee.includes("succeed") || callee.includes("fail") || callee.includes("die") || callee.includes("void") || callee.includes("never") || callee.includes("gen") || callee.includes("make") || node.constructorKind) {
1714
+ return "constructor";
1715
+ }
1716
+ return "side-effect";
1676
1717
  }
1718
+ case "generator":
1719
+ case "pipe":
1720
+ return "constructor";
1721
+ case "parallel":
1722
+ case "race":
1723
+ case "concurrency-primitive":
1724
+ return "concurrency";
1725
+ case "error-handler":
1726
+ case "cause":
1727
+ case "exit":
1728
+ return "error-handler";
1729
+ case "retry":
1730
+ case "timeout":
1731
+ case "schedule":
1732
+ return "scheduling";
1733
+ case "resource":
1734
+ return "resource";
1735
+ case "conditional":
1736
+ case "loop":
1737
+ case "match":
1738
+ case "decision":
1739
+ case "switch":
1740
+ case "terminal":
1741
+ return "control-flow";
1742
+ case "try-catch":
1743
+ return "error-handler";
1744
+ case "opaque":
1745
+ return "unknown";
1746
+ case "layer":
1747
+ return "layer";
1748
+ case "stream":
1749
+ case "channel":
1750
+ case "sink":
1751
+ return "stream";
1752
+ case "fiber":
1753
+ case "interruption":
1754
+ return "fiber";
1755
+ case "transform":
1756
+ return "transform";
1757
+ case "unknown":
1758
+ return "unknown";
1677
1759
  }
1678
- return void 0;
1679
1760
  }
1680
1761
 
1681
1762
  // src/alias-resolution.ts
@@ -1774,20 +1855,36 @@ function getEffectImportNames(sourceFile) {
1774
1855
  const barrelFile = resolveBarrelSourceFile(project, currentPath, specifier);
1775
1856
  if (!barrelFile) continue;
1776
1857
  const reExported = getNamesReExportedFromEffect(barrelFile);
1777
- if (reExported.size === 0) continue;
1858
+ const toCheck = [];
1778
1859
  const def = decl.getDefaultImport();
1779
1860
  if (def) {
1780
1861
  const text = def.getText();
1781
- if (reExported.has(text)) names.add(text);
1862
+ toCheck.push({ name: text, localName: text });
1782
1863
  }
1783
1864
  const ns = decl.getNamespaceImport();
1784
1865
  if (ns) {
1785
1866
  const text = ns.getText();
1786
- if (reExported.has(text)) names.add(text);
1867
+ toCheck.push({ name: text, localName: text });
1787
1868
  }
1788
1869
  for (const named of decl.getNamedImports()) {
1789
- if (reExported.has(named.getName())) {
1790
- names.add(named.getAliasNode()?.getText() ?? named.getName());
1870
+ toCheck.push({
1871
+ name: named.getName(),
1872
+ localName: named.getAliasNode()?.getText() ?? named.getName()
1873
+ });
1874
+ }
1875
+ let needsDeepTrace = false;
1876
+ for (const entry of toCheck) {
1877
+ if (reExported.has(entry.name)) {
1878
+ names.add(entry.localName);
1879
+ } else {
1880
+ needsDeepTrace = true;
1881
+ }
1882
+ }
1883
+ if (needsDeepTrace) {
1884
+ for (const entry of toCheck) {
1885
+ if (!reExported.has(entry.name) && traceReExportChain(barrelFile, entry.name, project, 3)) {
1886
+ names.add(entry.localName);
1887
+ }
1791
1888
  }
1792
1889
  }
1793
1890
  }
@@ -1893,6 +1990,40 @@ function normalizeEffectCallee(callee, sourceFile) {
1893
1990
  if (!canonical) return callee;
1894
1991
  return `${canonical}.${rest}`;
1895
1992
  }
1993
+ function traceReExportChain(barrelFile, name, project, maxDepth) {
1994
+ if (maxDepth <= 0) return false;
1995
+ for (const exportDecl of barrelFile.getExportDeclarations()) {
1996
+ const specifier = exportDecl.getModuleSpecifierValue();
1997
+ if (!specifier) continue;
1998
+ let originalName;
1999
+ if (exportDecl.isNamespaceExport()) {
2000
+ originalName = name;
2001
+ } else {
2002
+ for (const namedExport of exportDecl.getNamedExports()) {
2003
+ const alias = namedExport.getAliasNode()?.getText();
2004
+ if (alias === name) {
2005
+ originalName = namedExport.getName();
2006
+ break;
2007
+ }
2008
+ if (namedExport.getName() === name) {
2009
+ originalName = name;
2010
+ break;
2011
+ }
2012
+ }
2013
+ }
2014
+ if (originalName === void 0) continue;
2015
+ if (isEffectPackageSpecifier(specifier)) return true;
2016
+ if (specifier.startsWith(".")) {
2017
+ const nextBarrel = resolveBarrelSourceFile(project, barrelFile.getFilePath(), specifier);
2018
+ if (nextBarrel) {
2019
+ const fromEffect = getNamesReExportedFromEffect(nextBarrel);
2020
+ if (fromEffect.has(originalName)) return true;
2021
+ if (traceReExportChain(nextBarrel, originalName, project, maxDepth - 1)) return true;
2022
+ }
2023
+ }
2024
+ }
2025
+ return false;
2026
+ }
1896
2027
  function resolveCalleeModuleOrigin(calleeText, sourceFile) {
1897
2028
  let cache = symbolResolutionCache.get(sourceFile);
1898
2029
  if (!cache) {
@@ -1931,7 +2062,11 @@ function resolveCalleeModuleOrigin(calleeText, sourceFile) {
1931
2062
  );
1932
2063
  if (barrelFile) {
1933
2064
  const reExported = getNamesReExportedFromEffect(barrelFile);
1934
- result = reExported.has(named.getName());
2065
+ if (reExported.has(named.getName())) {
2066
+ result = true;
2067
+ } else {
2068
+ result = traceReExportChain(barrelFile, named.getName(), sourceFile.getProject(), 3);
2069
+ }
1935
2070
  }
1936
2071
  }
1937
2072
  break;
@@ -2534,7 +2669,7 @@ var findEffectPrograms = (sourceFile, _opts) => {
2534
2669
  continue;
2535
2670
  }
2536
2671
  }
2537
- if ((exprText === "gen" || exprText.includes(".gen") && isEffectLikeCallExpression(call, sourceFile, effectImportNames, _opts.knownEffectInternalsRoot)) && !seenCallStarts.has(callStart)) {
2672
+ if ((exprText === "gen" || exprText.endsWith(".gen") && isEffectLikeCallExpression(call, sourceFile, effectImportNames, _opts.knownEffectInternalsRoot)) && !seenCallStarts.has(callStart)) {
2538
2673
  const name = extractProgramName(call) ?? extractEnclosingEffectFnName(call) ?? `program-${programs.length + 1}`;
2539
2674
  programs.push({
2540
2675
  name,
@@ -2856,6 +2991,23 @@ import { Effect as Effect3, Option as Option4 } from "effect";
2856
2991
 
2857
2992
  // src/effect-analysis.ts
2858
2993
  import { Effect as Effect2, Option as Option3 } from "effect";
2994
+ var SCHEMA_OPS = [
2995
+ "Schema.decode",
2996
+ "Schema.decodeUnknown",
2997
+ "Schema.encode",
2998
+ "Schema.validate",
2999
+ "Schema.decodeOption",
3000
+ "Schema.decodeEither",
3001
+ "Schema.encodeUnknown",
3002
+ "Schema.decodeSync",
3003
+ "Schema.encodeSync",
3004
+ "Schema.decodeUnknownSync",
3005
+ "Schema.decodeUnknownOption",
3006
+ "Schema.decodeUnknownEither",
3007
+ "Schema.decodePromise",
3008
+ "Schema.encodePromise",
3009
+ "Schema.decodeUnknownPromise"
3010
+ ];
2859
3011
  var analyzePipeChain = (node, sourceFile, filePath, opts, warnings, stats) => Effect2.gen(function* () {
2860
3012
  const { SyntaxKind } = loadTsMorph();
2861
3013
  const args = node.getArguments();
@@ -2897,6 +3049,26 @@ var analyzePipeChain = (node, sourceFile, filePath, opts, warnings, stats) => Ef
2897
3049
  transformations.push(analyzed);
2898
3050
  }
2899
3051
  }
3052
+ let spanName;
3053
+ const filteredTransformations = transformations.filter((t) => {
3054
+ if (t.type === "effect" && t.callee.includes("withSpan")) {
3055
+ return false;
3056
+ }
3057
+ return true;
3058
+ });
3059
+ if (!spanName) {
3060
+ for (const arg of transformArgs) {
3061
+ if (arg) {
3062
+ const argText = arg.getText();
3063
+ if (argText.includes("withSpan")) {
3064
+ const match = /withSpan\s*\(\s*["']([^"']+)["']/.exec(argText);
3065
+ if (match?.[1]) {
3066
+ spanName = match[1];
3067
+ }
3068
+ }
3069
+ }
3070
+ }
3071
+ }
2900
3072
  let typeFlow;
2901
3073
  try {
2902
3074
  const typeChecker = sourceFile.getProject().getTypeChecker();
@@ -2916,8 +3088,9 @@ var analyzePipeChain = (node, sourceFile, filePath, opts, warnings, stats) => Ef
2916
3088
  id: generateId(),
2917
3089
  type: "pipe",
2918
3090
  initial,
2919
- transformations,
2920
- ...typeFlow ? { typeFlow } : {}
3091
+ transformations: filteredTransformations,
3092
+ ...typeFlow ? { typeFlow } : {},
3093
+ ...spanName ? { spanName } : {}
2921
3094
  };
2922
3095
  const enrichedPipeNode = {
2923
3096
  ...pipeNode,
@@ -3098,7 +3271,8 @@ var analyzeEffectCall = (call, sourceFile, filePath, opts, warnings, stats, serv
3098
3271
  filePath,
3099
3272
  opts.includeLocations ?? false
3100
3273
  );
3101
- if (callee === "pipe" && call.getArguments().length >= 1) {
3274
+ const isEffectMethodPipe = callee.endsWith(".pipe") && callee !== "pipe" && callee.startsWith("Effect.");
3275
+ if ((callee === "pipe" || isEffectMethodPipe) && call.getArguments().length >= 1) {
3102
3276
  const nodes = yield* analyzePipeChain(
3103
3277
  call,
3104
3278
  sourceFile,
@@ -3301,7 +3475,8 @@ var analyzeEffectCall = (call, sourceFile, filePath, opts, warnings, stats, serv
3301
3475
  stats
3302
3476
  );
3303
3477
  }
3304
- if (CONDITIONAL_PATTERNS.some((pattern) => callee.includes(pattern))) {
3478
+ const conditionalOp = `.${calleeOperation}`;
3479
+ if (CONDITIONAL_PATTERNS.some((pattern) => conditionalOp === pattern || callee.endsWith(pattern))) {
3305
3480
  return yield* analyzeConditionalCall(
3306
3481
  call,
3307
3482
  callee,
@@ -3312,7 +3487,9 @@ var analyzeEffectCall = (call, sourceFile, filePath, opts, warnings, stats, serv
3312
3487
  stats
3313
3488
  );
3314
3489
  }
3315
- if (COLLECTION_PATTERNS.some((pattern) => callee.includes(pattern))) {
3490
+ const isSchemaOp = SCHEMA_OPS.some((op) => callee.startsWith(op) || normalizedCallee.startsWith(op));
3491
+ const collectionOp = `.${calleeOperation}`;
3492
+ if (!isSchemaOp && COLLECTION_PATTERNS.some((pattern) => collectionOp === pattern || callee.endsWith(pattern))) {
3316
3493
  return yield* analyzeLoopCall(
3317
3494
  call,
3318
3495
  callee,
@@ -5164,7 +5341,8 @@ var analyzeLoopCall = (call, callee, sourceFile, filePath, opts, warnings, stats
5164
5341
  let iterSource;
5165
5342
  let body;
5166
5343
  if (args.length > 0 && args[0]) {
5167
- iterSource = args[0].getText();
5344
+ const rawSource = args[0].getText();
5345
+ iterSource = rawSource.length > 30 ? rawSource.slice(0, 30) + "\u2026" : rawSource;
5168
5346
  }
5169
5347
  if (args.length > bodyArgIndex && args[bodyArgIndex]) {
5170
5348
  body = yield* analyzeEffectExpression(
@@ -6616,6 +6794,8 @@ var analyzeGeneratorFunction = (node, sourceFile, filePath, opts, warnings, stat
6616
6794
  }
6617
6795
  const calls = body.getDescendantsOfKind(SyntaxKind.CallExpression);
6618
6796
  for (const call of calls) {
6797
+ const callCallee = call.getExpression().getText();
6798
+ if (callCallee.includes("withSpan")) continue;
6619
6799
  const aliases = getAliasesForFile(sourceFile);
6620
6800
  if (isEffectLikeCallExpression(call, sourceFile, aliases, opts.knownEffectInternalsRoot)) {
6621
6801
  const analyzed = yield* analyzeEffectCall(