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.
- package/dist/{analyze-a8PswlPG.d.cts → analyze-BXCwo5MU.d.cts} +2 -0
- package/dist/{analyze-a8PswlPG.d.ts → analyze-BXCwo5MU.d.ts} +2 -0
- package/dist/cli.js +76 -76
- package/dist/effect-workflow.cjs +3 -3
- package/dist/effect-workflow.cjs.map +1 -1
- package/dist/effect-workflow.d.cts +2 -2
- package/dist/effect-workflow.d.ts +2 -2
- package/dist/effect-workflow.js +3 -3
- package/dist/effect-workflow.js.map +1 -1
- package/dist/index.cjs +79 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +80 -75
- package/dist/index.js.map +1 -1
- package/dist/lsp/server.js +1367 -1187
- package/package.json +37 -18
package/dist/lsp/server.js
CHANGED
|
@@ -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:
|
|
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)
|
|
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-
|
|
438
|
-
var
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
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
|
|
974
|
-
".
|
|
975
|
-
".
|
|
976
|
-
".
|
|
977
|
-
".
|
|
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
|
|
987
|
-
".
|
|
988
|
-
".
|
|
989
|
-
".
|
|
990
|
-
".
|
|
991
|
-
".
|
|
992
|
-
".
|
|
993
|
-
".
|
|
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
|
|
1013
|
-
"Effect.
|
|
1014
|
-
".
|
|
1015
|
-
".
|
|
1016
|
-
".
|
|
1017
|
-
".
|
|
1018
|
-
"
|
|
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
|
|
1021
|
-
"
|
|
1022
|
-
"
|
|
1023
|
-
"
|
|
1024
|
-
"
|
|
1025
|
-
"
|
|
1026
|
-
"
|
|
1027
|
-
"
|
|
1028
|
-
"
|
|
1029
|
-
"
|
|
1030
|
-
"
|
|
1031
|
-
"
|
|
1032
|
-
"
|
|
1033
|
-
"
|
|
1034
|
-
"
|
|
1035
|
-
"
|
|
1036
|
-
"
|
|
1037
|
-
"
|
|
1038
|
-
"
|
|
1039
|
-
"
|
|
1040
|
-
"
|
|
1041
|
-
"
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
"
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
"
|
|
1050
|
-
"
|
|
1051
|
-
"
|
|
1052
|
-
"
|
|
1053
|
-
"
|
|
1054
|
-
"
|
|
1055
|
-
"
|
|
1056
|
-
"
|
|
1057
|
-
"
|
|
1058
|
-
"
|
|
1059
|
-
"
|
|
1060
|
-
"
|
|
1061
|
-
"
|
|
1062
|
-
"
|
|
1063
|
-
"
|
|
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
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
"
|
|
1069
|
-
"
|
|
1070
|
-
"
|
|
1071
|
-
"
|
|
1072
|
-
"
|
|
1073
|
-
"
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
"
|
|
1083
|
-
"
|
|
1084
|
-
"
|
|
1085
|
-
"
|
|
1086
|
-
"Cause.
|
|
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
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
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
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
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
|
-
"
|
|
1344
|
-
"
|
|
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
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
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
|
|
1352
|
-
|
|
1353
|
-
if (
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
if (
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
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
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
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
|
|
1494
|
+
var extractYieldVariableName = (yieldNode) => {
|
|
1495
|
+
const parent = yieldNode.getParent();
|
|
1434
1496
|
const { SyntaxKind } = loadTsMorph();
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
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
|
|
1512
|
+
return void 0;
|
|
1447
1513
|
};
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
const
|
|
1451
|
-
if (
|
|
1452
|
-
return
|
|
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
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
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 (
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
return
|
|
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
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
if (
|
|
1504
|
-
|
|
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
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
return
|
|
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
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
if (
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
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
|
-
|
|
1532
|
-
|
|
1578
|
+
}
|
|
1579
|
+
current = current.getParent();
|
|
1533
1580
|
}
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
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 (
|
|
1553
|
-
return
|
|
1624
|
+
if (node.name) {
|
|
1625
|
+
return truncate(`${node.name} <- ${fnName}`, 60);
|
|
1554
1626
|
}
|
|
1555
|
-
return
|
|
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
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
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
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
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
|
-
|
|
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
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
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
|
-
|
|
1858
|
+
const toCheck = [];
|
|
1778
1859
|
const def = decl.getDefaultImport();
|
|
1779
1860
|
if (def) {
|
|
1780
1861
|
const text = def.getText();
|
|
1781
|
-
|
|
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
|
-
|
|
1867
|
+
toCheck.push({ name: text, localName: text });
|
|
1787
1868
|
}
|
|
1788
1869
|
for (const named of decl.getNamedImports()) {
|
|
1789
|
-
|
|
1790
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|