effect-analyzer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -0
- package/dist/analyze-a8PswlPG.d.cts +1152 -0
- package/dist/analyze-a8PswlPG.d.ts +1152 -0
- package/dist/cli.js +198 -0
- package/dist/effect-workflow.cjs +5 -0
- package/dist/effect-workflow.cjs.map +1 -0
- package/dist/effect-workflow.d.cts +31 -0
- package/dist/effect-workflow.d.ts +31 -0
- package/dist/effect-workflow.js +5 -0
- package/dist/effect-workflow.js.map +1 -0
- package/dist/index.cjs +548 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1895 -0
- package/dist/index.d.ts +1895 -0
- package/dist/index.js +548 -0
- package/dist/index.js.map +1 -0
- package/dist/lsp/server.js +8827 -0
- package/package.json +76 -0
- package/scripts/analyze-public-repos.ts +130 -0
- package/scripts/audit-ci.ts +213 -0
- package/scripts/audit-public-effect-modules.ts +111 -0
- package/scripts/baselines/effect-audit-baseline.json +14 -0
- package/scripts/benchmark.ts +107 -0
- package/scripts/diff-effect-scans.ts +87 -0
- package/scripts/effect-scan-utils.ts +275 -0
- package/scripts/eslint-rules/no-inline-type-import.js +39 -0
- package/scripts/fetch-effect-repo.ts +52 -0
- package/scripts/openapi-runtime-runner.mjs +66 -0
- package/scripts/scan-effect-internals.ts +53 -0
- package/scripts/scan-effect-top-level.ts +52 -0
- package/scripts/summarize-scan.ts +47 -0
- package/scripts/triage-effect-scan.ts +85 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1895 @@
|
|
|
1
|
+
import { S as StaticEffectIR, P as ProjectServiceMap, A as AnalyzerOptions, a as AnalysisError, M as MermaidOptions, E as EffectPath, D as DiagramQualityWithFile, b as DiagramTopOffendersReport, c as DiagramQuality, J as JSONRenderOptions, d as ShowcaseEntry, e as ServiceRequirement, f as SourceLocation, g as StaticEffectNode, C as ComplexityThresholds, h as ComplexityMetrics, T as TestMatrix, i as StaticFiberNode, j as CauseTypeSignature, k as EffectTypeSignature, L as LayerTypeSignature, l as ScheduleTypeSignature, m as StreamTypeSignature } from './analyze-a8PswlPG.cjs';
|
|
2
|
+
export { n as AnalysisStats, o as AnalysisWarning, p as AnalyzeResult, q as DependencyInfo, r as DiagramQualityMetrics, s as DiagramReadabilityBand, t as DiagramTopOffenderEntry, u as JSDocTags, v as LayerImplementation, w as MermaidDetailLevel, x as MermaidStyles, y as PathCondition, z as PathStepRef, B as ScheduleInfo, F as SemanticRole, G as ServiceArtifact, G as ServiceArtifactType, H as ServiceConsumerRef, I as ServiceDefinition, K as ShowcaseStepDetail, N as StaticAnalysisMetadata, O as StaticBaseNode, Q as StaticCauseNode, R as StaticConcurrencyPrimitiveNode, U as StaticConditionalNode, V as StaticEffectProgram, W as StaticErrorHandlerNode, X as StaticExitNode, Y as StaticFlowNode, Z as StaticGeneratorNode, _ as StaticLayerNode, $ as StaticLoopNode, a0 as StaticMatchNode, a1 as StaticParallelNode, a2 as StaticPipeNode, a3 as StaticRaceNode, a4 as StaticResourceNode, a5 as StaticRetryNode, a6 as StaticScheduleNode, a7 as StaticStreamNode, a8 as StaticTimeoutNode, a9 as StaticTransformNode, aa as StaticUnknownNode, ab as StreamOperatorInfo, ac as TestCondition, ad as TestMatrixSummary, ae as TestPath, af as analyze, ag as getStaticChildren, ah as isStaticCauseNode, ai as isStaticConcurrencyPrimitiveNode, aj as isStaticConditionalNode, ak as isStaticEffectNode, al as isStaticErrorHandlerNode, am as isStaticExitNode, an as isStaticFiberNode, ao as isStaticGeneratorNode, ap as isStaticLayerNode, aq as isStaticLoopNode, ar as isStaticMatchNode, as as isStaticParallelNode, at as isStaticPipeNode, au as isStaticRaceNode, av as isStaticResourceNode, aw as isStaticRetryNode, ax as isStaticScheduleNode, ay as isStaticStreamNode, az as isStaticTimeoutNode, aA as isStaticTransformNode, aB as isStaticUnknownNode } from './analyze-a8PswlPG.cjs';
|
|
3
|
+
import { Effect } from 'effect';
|
|
4
|
+
import { Node, SourceFile, Project, TypeChecker, Type } from 'ts-morph';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Project-wide / Cross-file Analysis (GAP 17)
|
|
8
|
+
*
|
|
9
|
+
* Analyzes a directory of TypeScript files and aggregates results.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Per-file failure for project analysis (Gap 3: no silent drops). */
|
|
13
|
+
interface ProjectFileFailure {
|
|
14
|
+
readonly file: string;
|
|
15
|
+
readonly error: string;
|
|
16
|
+
}
|
|
17
|
+
interface ProjectAnalysisResult {
|
|
18
|
+
/** File path -> list of program IRs in that file */
|
|
19
|
+
readonly byFile: Map<string, readonly StaticEffectIR[]>;
|
|
20
|
+
/** All programs across the project */
|
|
21
|
+
readonly allPrograms: readonly StaticEffectIR[];
|
|
22
|
+
/** Entry points (files that run Effect.runPromise / runSync / NodeRuntime.runMain) - heuristic + package.json */
|
|
23
|
+
readonly entryPointFiles: string[];
|
|
24
|
+
/** Total file count discovered */
|
|
25
|
+
readonly fileCount: number;
|
|
26
|
+
/** Files that failed to analyze (error message included) - Gap 3 */
|
|
27
|
+
readonly failedFiles: readonly ProjectFileFailure[];
|
|
28
|
+
/** Files that were analyzed but had zero Effect programs */
|
|
29
|
+
readonly zeroProgramFiles: readonly string[];
|
|
30
|
+
/** Project-level deduplicated service map (when --service-map is enabled) */
|
|
31
|
+
readonly serviceMap?: ProjectServiceMap | undefined;
|
|
32
|
+
}
|
|
33
|
+
interface AnalyzeProjectOptions {
|
|
34
|
+
readonly tsconfig?: string | undefined;
|
|
35
|
+
/** File extensions to discover; default ['.ts', '.tsx']. Include '.js'/.jsx' for best-effort JS (Gap 6). */
|
|
36
|
+
readonly extensions?: readonly string[] | undefined;
|
|
37
|
+
readonly maxDepth?: number | undefined;
|
|
38
|
+
/** When true, include per-file durationMs in outcomes (improve.md §7 optional timing). */
|
|
39
|
+
readonly includePerFileTiming?: boolean | undefined;
|
|
40
|
+
/** Optional false-positive review: paths matching any of these (substring or path segment) are excluded from suspiciousZeros (improve.md §5). */
|
|
41
|
+
readonly excludeFromSuspiciousZeros?: readonly string[] | undefined;
|
|
42
|
+
/** Optional path to known Effect internals root for per-file analysis (improve.md §1). */
|
|
43
|
+
readonly knownEffectInternalsRoot?: string | undefined;
|
|
44
|
+
/** When true, build the deduplicated project-level service map (--service-map). */
|
|
45
|
+
readonly buildServiceMap?: boolean | undefined;
|
|
46
|
+
}
|
|
47
|
+
/** Per-file outcome for coverage audit. */
|
|
48
|
+
interface FileOutcome {
|
|
49
|
+
readonly file: string;
|
|
50
|
+
readonly status: 'ok' | 'fail' | 'zero';
|
|
51
|
+
readonly programCount?: number;
|
|
52
|
+
readonly error?: string;
|
|
53
|
+
/** When includePerFileTiming: analysis time in ms (improve.md §7). */
|
|
54
|
+
readonly durationMs?: number;
|
|
55
|
+
}
|
|
56
|
+
type ZeroProgramCategory = 'barrel_or_index' | 'config_or_build' | 'test_or_dtslint' | 'type_only' | 'suspicious' | 'other';
|
|
57
|
+
interface ZeroProgramClassification {
|
|
58
|
+
readonly file: string;
|
|
59
|
+
readonly category: ZeroProgramCategory;
|
|
60
|
+
readonly importsEffect: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** Coverage audit: discovered vs analyzed vs failed/zero, with per-file outcomes. */
|
|
63
|
+
interface CoverageAuditResult {
|
|
64
|
+
readonly discovered: number;
|
|
65
|
+
readonly analyzed: number;
|
|
66
|
+
readonly zeroPrograms: number;
|
|
67
|
+
readonly failed: number;
|
|
68
|
+
readonly outcomes: readonly FileOutcome[];
|
|
69
|
+
readonly percentage: number;
|
|
70
|
+
/** analyzed / (analyzed + failed) * 100 — excludes zero-program files (correct classification). */
|
|
71
|
+
readonly analyzableCoverage: number;
|
|
72
|
+
/** unknownCount / totalNodes across all analyzed files (0–1). */
|
|
73
|
+
readonly unknownNodeRate: number;
|
|
74
|
+
/** Repo-level aggregate: total node count across all analyzed programs (improve.md §5). */
|
|
75
|
+
readonly totalNodes: number;
|
|
76
|
+
/** Repo-level aggregate: unknown node count across all analyzed programs (improve.md §5). */
|
|
77
|
+
readonly unknownNodes: number;
|
|
78
|
+
/** Files that import from effect/@effect but produced zero programs. */
|
|
79
|
+
readonly suspiciousZeros: readonly string[];
|
|
80
|
+
/** Per-category zero-program counts for triage. */
|
|
81
|
+
readonly zeroProgramCategoryCounts: Readonly<Record<ZeroProgramCategory, number>>;
|
|
82
|
+
/** Per-file category for zero-program outcomes. */
|
|
83
|
+
readonly zeroProgramClassifications: readonly ZeroProgramClassification[];
|
|
84
|
+
/** Top N files by unknown node rate (highest first), for --show-top-unknown. */
|
|
85
|
+
readonly topUnknownFiles?: readonly string[];
|
|
86
|
+
/** Unknown node counts by reason. */
|
|
87
|
+
readonly unknownReasonCounts?: Readonly<Record<string, number>>;
|
|
88
|
+
/** Top unknown reasons by count (highest first), for --show-top-unknown-reasons. */
|
|
89
|
+
readonly topUnknownReasons?: readonly {
|
|
90
|
+
reason: string;
|
|
91
|
+
count: number;
|
|
92
|
+
}[];
|
|
93
|
+
/** Audit execution time in ms (improve.md §7 performance validation). */
|
|
94
|
+
readonly durationMs?: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Analyze all TypeScript files in a directory and return aggregated IRs.
|
|
98
|
+
*/
|
|
99
|
+
declare function analyzeProject(dirPath: string, options?: AnalyzeProjectOptions): Effect.Effect<ProjectAnalysisResult>;
|
|
100
|
+
/**
|
|
101
|
+
* Run a coverage audit over a directory: discover all .ts/.tsx files, analyze each,
|
|
102
|
+
* and return counts plus per-file outcomes (ok / zero programs / failed with reason).
|
|
103
|
+
* Does not swallow failures; every file gets an outcome.
|
|
104
|
+
*/
|
|
105
|
+
declare function runCoverageAudit(dirPath: string, options?: AnalyzeProjectOptions): Effect.Effect<CoverageAuditResult>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Migration Assistant (GAP 29)
|
|
109
|
+
*
|
|
110
|
+
* Detects patterns that could be migrated to Effect (try/catch, Promise.all, etc.).
|
|
111
|
+
*/
|
|
112
|
+
interface MigrationOpportunity {
|
|
113
|
+
readonly filePath: string;
|
|
114
|
+
readonly line: number;
|
|
115
|
+
readonly column: number;
|
|
116
|
+
readonly pattern: string;
|
|
117
|
+
readonly suggestion: string;
|
|
118
|
+
readonly codeSnippet?: string | undefined;
|
|
119
|
+
}
|
|
120
|
+
interface MigrationReport {
|
|
121
|
+
readonly opportunities: readonly MigrationOpportunity[];
|
|
122
|
+
readonly fileCount: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Scan a file for migration opportunities.
|
|
126
|
+
*/
|
|
127
|
+
declare function findMigrationOpportunities(filePath: string, source?: string): MigrationOpportunity[];
|
|
128
|
+
/**
|
|
129
|
+
* Scan a directory for migration opportunities.
|
|
130
|
+
*/
|
|
131
|
+
declare function findMigrationOpportunitiesInProject(dirPath: string, options?: {
|
|
132
|
+
extensions?: readonly string[];
|
|
133
|
+
}): Promise<MigrationReport>;
|
|
134
|
+
/**
|
|
135
|
+
* Format migration report as text.
|
|
136
|
+
*/
|
|
137
|
+
declare function formatMigrationReport(report: MigrationReport): string;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Shared utilities for static Effect analysis: options, ID generation,
|
|
141
|
+
* location/JSDoc extraction, dependency/error aggregation, program naming.
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
declare const resetIdCounter: () => void;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Static Effect Analyzer
|
|
148
|
+
*
|
|
149
|
+
* Uses ts-morph to walk the TypeScript AST and extract Effect structure
|
|
150
|
+
* without executing the code. Built entirely with Effect for composability.
|
|
151
|
+
*
|
|
152
|
+
* Public API: analyzeEffectFile, analyzeEffectSource, resetIdCounter.
|
|
153
|
+
* Implementation is split across analysis-utils, analysis-patterns, alias-resolution,
|
|
154
|
+
* program-discovery, effect-analysis, and core-analysis.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
declare const analyzeEffectFile: (filePath: string, options?: AnalyzerOptions) => Effect.Effect<readonly StaticEffectIR[], AnalysisError>;
|
|
158
|
+
declare const analyzeEffectSource: (code: string, filePath?: string, options?: AnalyzerOptions) => Effect.Effect<readonly StaticEffectIR[], AnalysisError>;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Mermaid diagram generation for Effect IR
|
|
162
|
+
*
|
|
163
|
+
* Aligned with awaitly-analyze: Start/End nodes, explicit edges,
|
|
164
|
+
* optional subgraphs for parallel/race, sequential flow for pipe/generator.
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Generate a Mermaid flowchart from static Effect IR (sync).
|
|
169
|
+
* Includes Start/End nodes, optional subgraphs, sequential flow.
|
|
170
|
+
*/
|
|
171
|
+
declare function renderStaticMermaid(ir: StaticEffectIR, options?: Partial<MermaidOptions>): string;
|
|
172
|
+
/**
|
|
173
|
+
* Render Effect IR as Mermaid flowchart (Effect).
|
|
174
|
+
* Same as renderStaticMermaid but returns Effect.Effect<string>.
|
|
175
|
+
*/
|
|
176
|
+
declare const renderMermaid: (ir: StaticEffectIR, options?: Partial<MermaidOptions>) => Effect.Effect<string>;
|
|
177
|
+
interface PathsMermaidOptions {
|
|
178
|
+
direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
179
|
+
/** Collapse consecutive log-like steps into one summary node (default: true). */
|
|
180
|
+
collapseRepeatedLogs?: boolean;
|
|
181
|
+
/** Collapse consecutive pure-transform-like steps into one summary node (default: true). */
|
|
182
|
+
collapsePureTransforms?: boolean;
|
|
183
|
+
/** Collapse consecutive environment-acquisition-like steps (default: false, true in style-guide mode). */
|
|
184
|
+
collapseEnvironmentRuns?: boolean;
|
|
185
|
+
/** Apply summary-only readability heuristics (environment grouping + service boundary prefixes). */
|
|
186
|
+
styleGuide?: boolean;
|
|
187
|
+
/** Prefix the first service-like calls with "svc:" (default: false, true in style-guide mode). */
|
|
188
|
+
prefixServiceBoundaries?: boolean;
|
|
189
|
+
}
|
|
190
|
+
interface DisplayPathStep {
|
|
191
|
+
key: string;
|
|
192
|
+
name: string;
|
|
193
|
+
}
|
|
194
|
+
interface PathSummaryResult {
|
|
195
|
+
steps: readonly DisplayPathStep[];
|
|
196
|
+
collapsedGroups: number;
|
|
197
|
+
}
|
|
198
|
+
declare function summarizePathSteps(path: EffectPath, options: PathsMermaidOptions): PathSummaryResult;
|
|
199
|
+
/**
|
|
200
|
+
* Generate a simplified Mermaid diagram from execution paths.
|
|
201
|
+
* Start -> step1 -> step2 -> ... -> End; nodes merged by nodeId.
|
|
202
|
+
*/
|
|
203
|
+
declare function renderPathsMermaid(paths: readonly EffectPath[], options?: PathsMermaidOptions): string;
|
|
204
|
+
interface EnhancedMermaidOptions extends Partial<MermaidOptions> {
|
|
205
|
+
showTypeSignatures?: boolean;
|
|
206
|
+
showRequiredServices?: boolean;
|
|
207
|
+
showErrorNodes?: boolean;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate enhanced Mermaid with type signatures and/or required services on nodes.
|
|
211
|
+
*/
|
|
212
|
+
declare function renderEnhancedMermaid(ir: StaticEffectIR, options?: EnhancedMermaidOptions): string;
|
|
213
|
+
/**
|
|
214
|
+
* Render enhanced Mermaid as Effect.
|
|
215
|
+
*/
|
|
216
|
+
declare const renderEnhancedMermaidEffect: (ir: StaticEffectIR, options?: EnhancedMermaidOptions) => Effect.Effect<string>;
|
|
217
|
+
/**
|
|
218
|
+
* Generate a Mermaid sequence diagram for fiber fork/join (GAP 21).
|
|
219
|
+
*/
|
|
220
|
+
declare function renderSequenceMermaid(ir: StaticEffectIR): string;
|
|
221
|
+
/**
|
|
222
|
+
* Generate a Mermaid Gantt diagram for retry schedules (GAP 21).
|
|
223
|
+
*/
|
|
224
|
+
declare function renderRetryGanttMermaid(ir: StaticEffectIR): string;
|
|
225
|
+
/**
|
|
226
|
+
* Render a project-level service dependency graph as a Mermaid flowchart.
|
|
227
|
+
* Services are hexagon-shaped nodes, with edges showing layer requirements.
|
|
228
|
+
*/
|
|
229
|
+
declare function renderServiceGraphMermaid(serviceMap: ProjectServiceMap, options?: {
|
|
230
|
+
direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
231
|
+
}): string;
|
|
232
|
+
|
|
233
|
+
interface RailwayOptions {
|
|
234
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Render a railway-oriented Mermaid flowchart from an Effect IR.
|
|
238
|
+
*
|
|
239
|
+
* Happy path flows left-to-right with `-->|ok|` edges.
|
|
240
|
+
* Steps with typed errors get `-->|err|` branches to error nodes.
|
|
241
|
+
*/
|
|
242
|
+
declare function renderRailwayMermaid(ir: StaticEffectIR, options?: RailwayOptions): string;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Mermaid renderer for the R channel (service/dependency) graph.
|
|
246
|
+
*
|
|
247
|
+
* Two modes:
|
|
248
|
+
* - Single-file: `renderServicesMermaid(ir)` — shows required vs provided services for one program.
|
|
249
|
+
* - Project-wide: `renderServicesMermaidFromMap(serviceMap)` — shows the full service dependency graph.
|
|
250
|
+
*/
|
|
251
|
+
|
|
252
|
+
interface ServicesOptions {
|
|
253
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Render a Mermaid flowchart showing the R channel for a single IR.
|
|
257
|
+
*
|
|
258
|
+
* - Program node as a rectangle
|
|
259
|
+
* - Required services as blue hexagons with `requires` edges
|
|
260
|
+
* - Provided services as green hexagons with `provides` edges
|
|
261
|
+
*/
|
|
262
|
+
declare function renderServicesMermaid(ir: StaticEffectIR, options?: ServicesOptions): string;
|
|
263
|
+
/**
|
|
264
|
+
* Render a Mermaid flowchart for a project-wide service dependency graph.
|
|
265
|
+
*
|
|
266
|
+
* - Each service is a hexagon node
|
|
267
|
+
* - Edges show layer dependencies
|
|
268
|
+
* - Unresolved services are dashed
|
|
269
|
+
*/
|
|
270
|
+
declare function renderServicesMermaidFromMap(serviceMap: ProjectServiceMap, options?: ServicesOptions): string;
|
|
271
|
+
|
|
272
|
+
interface MermaidErrorsOptions {
|
|
273
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Render a Mermaid flowchart showing error propagation:
|
|
277
|
+
* - Steps (left): which steps produce errors
|
|
278
|
+
* - Error types (middle): the error type nodes
|
|
279
|
+
* - Handlers (right): which handlers catch which errors
|
|
280
|
+
* - Unhandled: errors that are never caught
|
|
281
|
+
*/
|
|
282
|
+
declare function renderErrorsMermaid(ir: StaticEffectIR, options?: MermaidErrorsOptions): string;
|
|
283
|
+
|
|
284
|
+
interface DecisionsOptions {
|
|
285
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Render a decision-tree Mermaid flowchart from an Effect IR.
|
|
289
|
+
*
|
|
290
|
+
* Decision nodes (conditional, decision, switch, match) are rendered as
|
|
291
|
+
* diamond-shaped nodes with labeled edges to their branches.
|
|
292
|
+
*/
|
|
293
|
+
declare function renderDecisionsMermaid(ir: StaticEffectIR, options?: DecisionsOptions): string;
|
|
294
|
+
|
|
295
|
+
interface CausesOptions {
|
|
296
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Render a Cause-tree Mermaid flowchart from an Effect IR.
|
|
300
|
+
*
|
|
301
|
+
* Shows how errors compose: parallel failures, sequential failures,
|
|
302
|
+
* defects vs expected errors.
|
|
303
|
+
*/
|
|
304
|
+
declare function renderCausesMermaid(ir: StaticEffectIR, options?: CausesOptions): string;
|
|
305
|
+
|
|
306
|
+
interface ConcurrencyOptions {
|
|
307
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Render a concurrency-focused Mermaid flowchart from an Effect IR.
|
|
311
|
+
*
|
|
312
|
+
* Shows parallel execution, races, fiber forks/joins, and concurrency primitives.
|
|
313
|
+
*/
|
|
314
|
+
declare function renderConcurrencyMermaid(ir: StaticEffectIR, options?: ConcurrencyOptions): string;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Render a Mermaid sequence diagram from an Effect IR showing
|
|
318
|
+
* execution order with service calls and timing info.
|
|
319
|
+
*/
|
|
320
|
+
declare function renderTimelineMermaid(ir: StaticEffectIR): string;
|
|
321
|
+
|
|
322
|
+
interface LayersOptions {
|
|
323
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Render a layered architecture Mermaid flowchart from an Effect IR.
|
|
327
|
+
*
|
|
328
|
+
* Shows which layers provide which services and their dependencies.
|
|
329
|
+
* - Layer nodes are rectangles with name and lifecycle info.
|
|
330
|
+
* - Service nodes are hexagons.
|
|
331
|
+
* - Provides edges are solid green arrows.
|
|
332
|
+
* - Requires edges are dashed blue arrows.
|
|
333
|
+
* - Merge edges are gray arrows.
|
|
334
|
+
*/
|
|
335
|
+
declare function renderLayersMermaid(ir: StaticEffectIR, options?: LayersOptions): string;
|
|
336
|
+
|
|
337
|
+
interface RetryOptions {
|
|
338
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Render a Mermaid flowchart showing retry and timeout resilience patterns.
|
|
342
|
+
*/
|
|
343
|
+
declare function renderRetryMermaid(ir: StaticEffectIR, options?: RetryOptions): string;
|
|
344
|
+
|
|
345
|
+
interface TestabilityOptions {
|
|
346
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Render a testability-focused Mermaid flowchart from an Effect IR.
|
|
350
|
+
*
|
|
351
|
+
* Shows what needs mocking for testing: required services, isolation boundaries,
|
|
352
|
+
* and mock complexity (easy leaf services vs hard infrastructure/layer services).
|
|
353
|
+
*/
|
|
354
|
+
declare function renderTestabilityMermaid(ir: StaticEffectIR, options?: TestabilityOptions): string;
|
|
355
|
+
|
|
356
|
+
interface DataflowOptions {
|
|
357
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Render a dataflow Mermaid flowchart from an Effect IR.
|
|
361
|
+
*
|
|
362
|
+
* Shows data transformation pipelines: how types evolve through pipe chains
|
|
363
|
+
* and generator yield sequences.
|
|
364
|
+
*/
|
|
365
|
+
declare function renderDataflowMermaid(ir: StaticEffectIR, options?: DataflowOptions): string;
|
|
366
|
+
|
|
367
|
+
type DiagramType = 'mermaid' | 'railway';
|
|
368
|
+
/**
|
|
369
|
+
* Infer the best diagram type for an Effect program.
|
|
370
|
+
*
|
|
371
|
+
* Decision order:
|
|
372
|
+
* 1. Hard rules: parallel/race/switch/loop/conditional/decision → mermaid
|
|
373
|
+
* 2. Soft heuristics: low complexity → railway, otherwise mermaid
|
|
374
|
+
*/
|
|
375
|
+
declare function inferBestDiagramType(ir: StaticEffectIR): DiagramType;
|
|
376
|
+
|
|
377
|
+
interface DiagramQualityHintInput {
|
|
378
|
+
readonly reasons?: readonly string[] | undefined;
|
|
379
|
+
readonly tips?: readonly string[] | undefined;
|
|
380
|
+
}
|
|
381
|
+
interface DiagramQualityOptions {
|
|
382
|
+
readonly styleGuideSummary?: boolean | undefined;
|
|
383
|
+
readonly hints?: DiagramQualityHintInput | undefined;
|
|
384
|
+
}
|
|
385
|
+
declare function computeProgramDiagramQuality(ir: StaticEffectIR, options?: DiagramQualityOptions): DiagramQuality;
|
|
386
|
+
declare function computeFileDiagramQuality(filePath: string, programs: readonly StaticEffectIR[], options?: DiagramQualityOptions): DiagramQualityWithFile;
|
|
387
|
+
declare function buildTopOffendersReport(fileQualities: readonly DiagramQualityWithFile[], topN?: number): DiagramTopOffendersReport;
|
|
388
|
+
|
|
389
|
+
declare function loadDiagramQualityHintsFromEslintJson(jsonPath: string): Promise<Map<string, DiagramQualityHintInput>>;
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Plain-English explanation renderer for Effect IR trees.
|
|
393
|
+
*
|
|
394
|
+
* Walks the static IR and produces a human-readable narrative
|
|
395
|
+
* describing what an Effect program does.
|
|
396
|
+
*/
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Renders a full plain-English explanation for a single Effect IR program.
|
|
400
|
+
*/
|
|
401
|
+
declare function renderExplanation(ir: StaticEffectIR): string;
|
|
402
|
+
/**
|
|
403
|
+
* Renders explanations for multiple programs, separated by `---`.
|
|
404
|
+
*/
|
|
405
|
+
declare function renderMultipleExplanations(irs: readonly StaticEffectIR[]): string;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Summary Output Module
|
|
409
|
+
*
|
|
410
|
+
* Produces ultra-compact one-liner-per-program output for quick overview
|
|
411
|
+
* of Effect program characteristics.
|
|
412
|
+
*/
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Render a one-line summary for a single Effect program IR.
|
|
416
|
+
*
|
|
417
|
+
* Format:
|
|
418
|
+
* programName | gen | 6 steps | 2 services | 0 errors | 1 handler | complexity: 2
|
|
419
|
+
*/
|
|
420
|
+
declare function renderSummary(ir: StaticEffectIR): string;
|
|
421
|
+
/**
|
|
422
|
+
* Render a formatted, column-aligned table summarizing multiple Effect program IRs.
|
|
423
|
+
*
|
|
424
|
+
* Example output:
|
|
425
|
+
* Program | Kind | Steps | Services | Errors | Handlers | Complexity
|
|
426
|
+
* -----------------+------+-------+----------+--------+----------+-----------
|
|
427
|
+
* serviceProgram | gen | 6 | 2 | 0 | 0 | 2
|
|
428
|
+
* databaseProgram | gen | 5 | 2 | 1 | 1 | 3
|
|
429
|
+
*/
|
|
430
|
+
declare function renderMultipleSummaries(irs: readonly StaticEffectIR[]): string;
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Build a program x service dependency matrix as a markdown table from IR dependencies.
|
|
434
|
+
*/
|
|
435
|
+
declare function renderDependencyMatrix(irs: readonly StaticEffectIR[]): string;
|
|
436
|
+
/**
|
|
437
|
+
* Build a program x service dependency matrix as a markdown table from the
|
|
438
|
+
* project-level service map (more accurate than IR-based).
|
|
439
|
+
*/
|
|
440
|
+
declare function renderDependencyMatrixFromServiceMap(serviceMap: ProjectServiceMap): string;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* JSON output generation for Effect IR
|
|
444
|
+
*/
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Render Effect IR as JSON string
|
|
448
|
+
*/
|
|
449
|
+
declare const renderJSON: (ir: StaticEffectIR, options?: Partial<JSONRenderOptions>) => Effect.Effect<string>;
|
|
450
|
+
/**
|
|
451
|
+
* Render multiple Effect IRs as JSON array
|
|
452
|
+
*/
|
|
453
|
+
declare const renderMultipleJSON: (irs: readonly StaticEffectIR[], options?: Partial<JSONRenderOptions>) => Effect.Effect<string>;
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Interactive HTML Output (GAP 22 v2)
|
|
457
|
+
*
|
|
458
|
+
* Generates a self-contained HTML file with:
|
|
459
|
+
* - Embedded IR and Mermaid diagram
|
|
460
|
+
* - Search/filter nodes by type, name, complexity
|
|
461
|
+
* - Click-to-navigate: click node to see source location, IR details
|
|
462
|
+
* - Path explorer: select a path and highlight it
|
|
463
|
+
* - Complexity heatmap: color nodes by complexity contribution
|
|
464
|
+
* - Error/data flow toggles
|
|
465
|
+
* - 6-theme system with system preference detection and localStorage persistence
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
type HtmlTheme = 'midnight' | 'ocean' | 'ember' | 'forest' | 'daylight' | 'paper';
|
|
469
|
+
interface HtmlOutputOptions {
|
|
470
|
+
readonly title?: string | undefined;
|
|
471
|
+
/** Named theme, or legacy 'light'/'dark' aliases (mapped to daylight/midnight). */
|
|
472
|
+
readonly theme?: HtmlTheme | 'light' | 'dark' | undefined;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Render IR as a self-contained HTML page with interactive features.
|
|
476
|
+
*/
|
|
477
|
+
declare function renderInteractiveHTML(ir: StaticEffectIR, options?: HtmlOutputOptions): string;
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Documentation Generation for Effect IR
|
|
481
|
+
*
|
|
482
|
+
* Generates comprehensive markdown documentation from analyzed Effect programs:
|
|
483
|
+
* workflow steps, service dependencies, complexity metrics, and embedded diagrams.
|
|
484
|
+
*/
|
|
485
|
+
|
|
486
|
+
interface DocSection {
|
|
487
|
+
title: string;
|
|
488
|
+
content: string;
|
|
489
|
+
}
|
|
490
|
+
interface DocumentationOptions {
|
|
491
|
+
/** Include Mermaid diagram in documentation */
|
|
492
|
+
includeDiagram?: boolean | undefined;
|
|
493
|
+
/** Include complexity metrics */
|
|
494
|
+
includeComplexity?: boolean | undefined;
|
|
495
|
+
/** Include service dependency table */
|
|
496
|
+
includeServiceDeps?: boolean | undefined;
|
|
497
|
+
/** Include error type documentation */
|
|
498
|
+
includeErrors?: boolean | undefined;
|
|
499
|
+
/** Include data flow information */
|
|
500
|
+
includeDataFlow?: boolean | undefined;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Generate comprehensive markdown documentation from an analyzed Effect IR.
|
|
504
|
+
*/
|
|
505
|
+
declare function renderDocumentation(ir: StaticEffectIR, options?: Partial<DocumentationOptions>): string;
|
|
506
|
+
/**
|
|
507
|
+
* Generate documentation for multiple programs.
|
|
508
|
+
*/
|
|
509
|
+
declare function renderMultiProgramDocs(irs: readonly StaticEffectIR[], options?: Partial<DocumentationOptions>): string;
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Showcase Output Generator
|
|
513
|
+
*
|
|
514
|
+
* Produces rich per-step detail from the Effect IR, matching the structure
|
|
515
|
+
* of awaitly-analyze's analyzer-showcase.data.json format.
|
|
516
|
+
*/
|
|
517
|
+
|
|
518
|
+
interface ShowcaseOptions {
|
|
519
|
+
/** Mermaid diagram direction */
|
|
520
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL' | undefined;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Generate a showcase entry from an analyzed Effect IR.
|
|
524
|
+
*/
|
|
525
|
+
declare function generateShowcase(ir: StaticEffectIR, options?: ShowcaseOptions, sourceCode?: string): ShowcaseEntry;
|
|
526
|
+
/**
|
|
527
|
+
* Generate showcase entries for multiple programs.
|
|
528
|
+
*/
|
|
529
|
+
declare function generateMultipleShowcase(irs: readonly StaticEffectIR[], options?: ShowcaseOptions, sourceCode?: string): ShowcaseEntry[];
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Cross-Program Composition Resolver for Effect IR
|
|
533
|
+
*
|
|
534
|
+
* Builds a graph of Effect programs that reference other programs
|
|
535
|
+
* (e.g. via identifier effects that match another program name).
|
|
536
|
+
*/
|
|
537
|
+
|
|
538
|
+
interface ProgramGraphNode {
|
|
539
|
+
name: string;
|
|
540
|
+
filePath: string;
|
|
541
|
+
ir: StaticEffectIR;
|
|
542
|
+
calls: ProgramCallEdge[];
|
|
543
|
+
calledBy: string[];
|
|
544
|
+
}
|
|
545
|
+
interface ProgramCallEdge {
|
|
546
|
+
targetProgram: string;
|
|
547
|
+
callSite?: {
|
|
548
|
+
line: number;
|
|
549
|
+
column: number;
|
|
550
|
+
};
|
|
551
|
+
resolved: boolean;
|
|
552
|
+
}
|
|
553
|
+
interface ProgramGraph {
|
|
554
|
+
programs: Map<string, ProgramGraphNode>;
|
|
555
|
+
entryProgram: string;
|
|
556
|
+
circularDependencies: string[][];
|
|
557
|
+
unresolvedReferences: UnresolvedProgramRef[];
|
|
558
|
+
}
|
|
559
|
+
interface UnresolvedProgramRef {
|
|
560
|
+
programName: string;
|
|
561
|
+
referencedFrom: string;
|
|
562
|
+
reason: string;
|
|
563
|
+
}
|
|
564
|
+
interface CompositionResolverOptions {
|
|
565
|
+
/** Entry program name when building from multiple IRs */
|
|
566
|
+
entryProgramName?: string | undefined;
|
|
567
|
+
}
|
|
568
|
+
interface YieldStarCall {
|
|
569
|
+
callee: string;
|
|
570
|
+
location?: {
|
|
571
|
+
line: number;
|
|
572
|
+
column: number;
|
|
573
|
+
} | undefined;
|
|
574
|
+
isYieldStar: boolean;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Build a program composition graph from a list of analyzed IRs (e.g. from one file).
|
|
578
|
+
*/
|
|
579
|
+
declare function analyzeProgramGraph(irs: readonly StaticEffectIR[], filePath: string, options?: CompositionResolverOptions): ProgramGraph;
|
|
580
|
+
declare function getTopologicalOrder(graph: ProgramGraph): string[];
|
|
581
|
+
declare function getDependencies(graph: ProgramGraph, programName: string): string[];
|
|
582
|
+
declare function getDependents(graph: ProgramGraph, programName: string): string[];
|
|
583
|
+
declare function calculateGraphComplexity(graph: ProgramGraph): {
|
|
584
|
+
totalCyclomaticComplexity: number;
|
|
585
|
+
totalPrograms: number;
|
|
586
|
+
maxDepth: number;
|
|
587
|
+
hasCircularDependencies: boolean;
|
|
588
|
+
};
|
|
589
|
+
declare function renderGraphMermaid(graph: ProgramGraph): string;
|
|
590
|
+
/**
|
|
591
|
+
* Render a composition Mermaid diagram showing generator call relationships
|
|
592
|
+
* with subgraphs grouping by file and yield* edge labels.
|
|
593
|
+
*/
|
|
594
|
+
declare function renderCompositionMermaid(graph: ProgramGraph): string;
|
|
595
|
+
interface ProjectCompositionOptions {
|
|
596
|
+
/** Entry program name */
|
|
597
|
+
entryProgramName?: string | undefined;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Build a composition graph from a project-wide analysis result (multi-file).
|
|
601
|
+
* Merges IRs across files into a unified program graph with cross-file edges.
|
|
602
|
+
*/
|
|
603
|
+
declare function analyzeProjectComposition(byFile: ReadonlyMap<string, readonly StaticEffectIR[]>, options?: ProjectCompositionOptions, serviceMap?: ProjectServiceMap): ProgramGraph;
|
|
604
|
+
/**
|
|
605
|
+
* Render a composition Mermaid diagram that includes service nodes from the service map.
|
|
606
|
+
* Programs are rectangular, services are hexagonal.
|
|
607
|
+
*/
|
|
608
|
+
declare function renderCompositionWithServicesMermaid(graph: ProgramGraph, projectServiceMap: ProjectServiceMap): string;
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Data Flow Analysis for Effect IR
|
|
612
|
+
*
|
|
613
|
+
* Builds a graph of value and service dependencies between effect nodes:
|
|
614
|
+
* - Value flow: sequential edges from one effect to the next in execution order
|
|
615
|
+
* - Service reads: effect nodes that require services from Context
|
|
616
|
+
*/
|
|
617
|
+
|
|
618
|
+
interface DataFlowNode {
|
|
619
|
+
id: string;
|
|
620
|
+
name?: string | undefined;
|
|
621
|
+
/** Success type this effect produces (writes) */
|
|
622
|
+
writes?: string | undefined;
|
|
623
|
+
/** Service IDs this effect reads from Context */
|
|
624
|
+
reads: string[];
|
|
625
|
+
location?: {
|
|
626
|
+
line: number;
|
|
627
|
+
column: number;
|
|
628
|
+
} | undefined;
|
|
629
|
+
}
|
|
630
|
+
interface DataFlowEdge {
|
|
631
|
+
from: string;
|
|
632
|
+
to: string;
|
|
633
|
+
key: string;
|
|
634
|
+
}
|
|
635
|
+
interface DataFlowGraph {
|
|
636
|
+
nodes: DataFlowNode[];
|
|
637
|
+
edges: DataFlowEdge[];
|
|
638
|
+
producedKeys: Set<string>;
|
|
639
|
+
undefinedReads: UndefinedRead[];
|
|
640
|
+
duplicateWrites: DuplicateWrite[];
|
|
641
|
+
}
|
|
642
|
+
interface UndefinedRead {
|
|
643
|
+
key: string;
|
|
644
|
+
readerId: string;
|
|
645
|
+
readerName?: string | undefined;
|
|
646
|
+
}
|
|
647
|
+
interface DuplicateWrite {
|
|
648
|
+
key: string;
|
|
649
|
+
writerIds: string[];
|
|
650
|
+
}
|
|
651
|
+
declare function buildDataFlowGraph(ir: StaticEffectIR): DataFlowGraph;
|
|
652
|
+
declare function getDataFlowOrder(graph: DataFlowGraph): string[] | undefined;
|
|
653
|
+
declare function getProducers(graph: DataFlowGraph, stepId: string): DataFlowNode[];
|
|
654
|
+
declare function getConsumers(graph: DataFlowGraph, stepId: string): DataFlowNode[];
|
|
655
|
+
declare function getTransitiveDependencies(graph: DataFlowGraph, stepId: string): string[];
|
|
656
|
+
declare function findCycles(graph: DataFlowGraph): string[][];
|
|
657
|
+
interface DataFlowValidation {
|
|
658
|
+
valid: boolean;
|
|
659
|
+
issues: DataFlowIssue[];
|
|
660
|
+
}
|
|
661
|
+
interface DataFlowIssue {
|
|
662
|
+
severity: 'error' | 'warning';
|
|
663
|
+
type: 'undefined-read' | 'duplicate-write' | 'cycle';
|
|
664
|
+
message: string;
|
|
665
|
+
stepIds: string[];
|
|
666
|
+
key?: string;
|
|
667
|
+
}
|
|
668
|
+
declare function validateDataFlow(graph: DataFlowGraph): DataFlowValidation;
|
|
669
|
+
declare function renderDataFlowMermaid(graph: DataFlowGraph): string;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Error Flow Analysis for Effect IR
|
|
673
|
+
*
|
|
674
|
+
* Aggregates error types from effect nodes (typeSignature.errorType) and
|
|
675
|
+
* error-handler nodes (catchTag, etc.) to build an error propagation view.
|
|
676
|
+
*/
|
|
677
|
+
|
|
678
|
+
interface StepErrorInfo {
|
|
679
|
+
stepId: string;
|
|
680
|
+
stepName?: string | undefined;
|
|
681
|
+
errors: string[];
|
|
682
|
+
location?: {
|
|
683
|
+
line: number;
|
|
684
|
+
column: number;
|
|
685
|
+
} | undefined;
|
|
686
|
+
}
|
|
687
|
+
/** Per-node error propagation: errors at this point and how handlers narrow (GAP 4) */
|
|
688
|
+
interface ErrorPropagation {
|
|
689
|
+
atNode: string;
|
|
690
|
+
possibleErrors: string[];
|
|
691
|
+
narrowedBy?: {
|
|
692
|
+
handler: string;
|
|
693
|
+
removedErrors: string[];
|
|
694
|
+
addedErrors: string[];
|
|
695
|
+
};
|
|
696
|
+
defects: string[];
|
|
697
|
+
interruptible: boolean;
|
|
698
|
+
}
|
|
699
|
+
interface ErrorPropagationAnalysis {
|
|
700
|
+
propagation: ErrorPropagation[];
|
|
701
|
+
byNodeId: Map<string, ErrorPropagation>;
|
|
702
|
+
}
|
|
703
|
+
interface ErrorFlowAnalysis {
|
|
704
|
+
allErrors: string[];
|
|
705
|
+
stepErrors: StepErrorInfo[];
|
|
706
|
+
errorToSteps: Map<string, string[]>;
|
|
707
|
+
stepsWithoutErrors: string[];
|
|
708
|
+
allStepsDeclareErrors: boolean;
|
|
709
|
+
}
|
|
710
|
+
interface ErrorFlowEdge {
|
|
711
|
+
stepId: string;
|
|
712
|
+
error: string;
|
|
713
|
+
}
|
|
714
|
+
interface ErrorValidation {
|
|
715
|
+
valid: boolean;
|
|
716
|
+
unusedDeclared: string[];
|
|
717
|
+
undeclaredErrors: string[];
|
|
718
|
+
computedErrors: string[];
|
|
719
|
+
}
|
|
720
|
+
declare function analyzeErrorFlow(ir: StaticEffectIR): ErrorFlowAnalysis;
|
|
721
|
+
declare function analyzeErrorPropagation(ir: StaticEffectIR): ErrorPropagationAnalysis;
|
|
722
|
+
declare function getErrorsAtPoint(analysis: ErrorFlowAnalysis, afterStepId: string): string[];
|
|
723
|
+
declare function getErrorProducers(analysis: ErrorFlowAnalysis, errorTag: string): StepErrorInfo[];
|
|
724
|
+
declare function validateWorkflowErrors(analysis: ErrorFlowAnalysis, declaredErrors: string[]): ErrorValidation;
|
|
725
|
+
declare function renderErrorFlowMermaid(analysis: ErrorFlowAnalysis): string;
|
|
726
|
+
declare function formatErrorSummary(analysis: ErrorFlowAnalysis): string;
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Layer Dependency Graph (GAP 2)
|
|
730
|
+
*
|
|
731
|
+
* Collects StaticLayerNode from IR and builds a dependency graph
|
|
732
|
+
* (provides, requires, merge/provide edges) for visualization.
|
|
733
|
+
*/
|
|
734
|
+
|
|
735
|
+
interface LayerNodeInfo {
|
|
736
|
+
id: string;
|
|
737
|
+
name?: string;
|
|
738
|
+
provides: string[];
|
|
739
|
+
requires: string[];
|
|
740
|
+
lifecycle: string;
|
|
741
|
+
isMerged: boolean;
|
|
742
|
+
operationLayerIds: string[];
|
|
743
|
+
}
|
|
744
|
+
interface LayerGraphEdge {
|
|
745
|
+
from: string;
|
|
746
|
+
to: string;
|
|
747
|
+
kind: 'provides' | 'requires' | 'merge';
|
|
748
|
+
}
|
|
749
|
+
interface LayerDependencyGraph {
|
|
750
|
+
layers: LayerNodeInfo[];
|
|
751
|
+
edges: LayerGraphEdge[];
|
|
752
|
+
serviceToLayers: Map<string, string[]>;
|
|
753
|
+
}
|
|
754
|
+
declare function buildLayerDependencyGraph(ir: StaticEffectIR): LayerDependencyGraph;
|
|
755
|
+
interface LayerCycle {
|
|
756
|
+
/** Layer IDs forming the cycle (first == last to close the loop) */
|
|
757
|
+
path: string[];
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Detect cycles in the layer provides→requires graph.
|
|
761
|
+
* Returns all unique cycles found with the full cycle path.
|
|
762
|
+
*/
|
|
763
|
+
declare function detectLayerCycles(graph: LayerDependencyGraph): LayerCycle[];
|
|
764
|
+
interface DiamondDependency {
|
|
765
|
+
serviceId: string;
|
|
766
|
+
providers: string[];
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Detect diamond dependencies: services reachable through multiple provide paths.
|
|
770
|
+
*/
|
|
771
|
+
declare function detectDiamondDependencies(graph: LayerDependencyGraph): DiamondDependency[];
|
|
772
|
+
interface UnsatisfiedService$1 {
|
|
773
|
+
serviceId: string;
|
|
774
|
+
requiredBy: string[];
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Find services required by layers but not provided by any layer.
|
|
778
|
+
*/
|
|
779
|
+
declare function findUnsatisfiedServices(graph: LayerDependencyGraph): UnsatisfiedService$1[];
|
|
780
|
+
declare function renderLayerGraphMermaid(graph: LayerDependencyGraph): string;
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Service (R) Flow Analysis (GAP 3)
|
|
784
|
+
*
|
|
785
|
+
* Tracks which services each effect requires, where they are provided,
|
|
786
|
+
* and where R is still unsatisfied.
|
|
787
|
+
*/
|
|
788
|
+
|
|
789
|
+
interface ServiceProvision {
|
|
790
|
+
nodeId: string;
|
|
791
|
+
serviceId: string;
|
|
792
|
+
location?: SourceLocation;
|
|
793
|
+
}
|
|
794
|
+
interface UnsatisfiedService {
|
|
795
|
+
nodeId: string;
|
|
796
|
+
serviceId: string;
|
|
797
|
+
serviceType?: string;
|
|
798
|
+
location?: SourceLocation;
|
|
799
|
+
}
|
|
800
|
+
interface ServiceLifecycleEntry {
|
|
801
|
+
createdAt: string;
|
|
802
|
+
consumedAt: string[];
|
|
803
|
+
releasedAt?: string;
|
|
804
|
+
}
|
|
805
|
+
interface ServiceFlowAnalysis {
|
|
806
|
+
requiredServices: ServiceRequirement[];
|
|
807
|
+
providedServices: ServiceProvision[];
|
|
808
|
+
unsatisfiedAt: UnsatisfiedService[];
|
|
809
|
+
serviceLifecycle: Map<string, ServiceLifecycleEntry>;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Build service flow analysis from IR.
|
|
813
|
+
* Tracks required vs provided services and unsatisfied requirements at each node.
|
|
814
|
+
*/
|
|
815
|
+
declare function analyzeServiceFlow(ir: StaticEffectIR, options?: {
|
|
816
|
+
/** Optional: resolve effect node to its AST to read first arg (for provideService). */
|
|
817
|
+
getFirstArgText?: (effectNode: StaticEffectNode) => string | undefined;
|
|
818
|
+
}): ServiceFlowAnalysis;
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Service Registry - builds a deduplicated service map for whole-codebase analysis.
|
|
822
|
+
*
|
|
823
|
+
* When the analyzer encounters `yield* SomeService`, this module creates a
|
|
824
|
+
* first-class ServiceArtifact for that service, including its tag definition,
|
|
825
|
+
* interface shape, layer implementations, consumers, and transitive dependencies.
|
|
826
|
+
*/
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Build a deduplicated project-level service map from analyzed program IRs.
|
|
830
|
+
*
|
|
831
|
+
* @param byFile Map of file path to analyzed programs in that file
|
|
832
|
+
* @param sourceFiles Optional map of file path to ts-morph SourceFile for AST-level extraction.
|
|
833
|
+
* When not provided, only IR-level data (requiredServices, StaticLayerNode) is used.
|
|
834
|
+
*/
|
|
835
|
+
declare function buildProjectServiceMap(byFile: ReadonlyMap<string, readonly StaticEffectIR[]>, sourceFiles?: ReadonlyMap<string, any>): ProjectServiceMap;
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Ref / State Management Analysis (GAP 7)
|
|
839
|
+
*
|
|
840
|
+
* Detects Ref, FiberRef, SynchronizedRef usage and potential race conditions.
|
|
841
|
+
*/
|
|
842
|
+
|
|
843
|
+
interface RefInfo {
|
|
844
|
+
refId: string;
|
|
845
|
+
operation: 'make' | 'get' | 'set' | 'update' | 'modify' | 'getAndSet' | 'getAndUpdate';
|
|
846
|
+
nodeId: string;
|
|
847
|
+
location?: {
|
|
848
|
+
line: number;
|
|
849
|
+
column: number;
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
interface RefMutation {
|
|
853
|
+
refId: string;
|
|
854
|
+
nodeId: string;
|
|
855
|
+
operation: 'set' | 'update' | 'modify' | 'getAndSet' | 'getAndUpdate';
|
|
856
|
+
}
|
|
857
|
+
interface RaceCondition {
|
|
858
|
+
refId: string;
|
|
859
|
+
readerIds: string[];
|
|
860
|
+
writerIds: string[];
|
|
861
|
+
message: string;
|
|
862
|
+
}
|
|
863
|
+
interface StateFlowAnalysis {
|
|
864
|
+
refs: RefInfo[];
|
|
865
|
+
mutations: RefMutation[];
|
|
866
|
+
potentialRaces: RaceCondition[];
|
|
867
|
+
stateGraph: {
|
|
868
|
+
refId: string;
|
|
869
|
+
readers: string[];
|
|
870
|
+
writers: string[];
|
|
871
|
+
}[];
|
|
872
|
+
}
|
|
873
|
+
declare function analyzeStateFlow(ir: StaticEffectIR): StateFlowAnalysis;
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Scope & Resource Lifecycle Analysis (GAP 10)
|
|
877
|
+
*
|
|
878
|
+
* Detects acquireRelease, Scope.*, Pool.*, Effect.scoped and tracks
|
|
879
|
+
* resource ordering and potential leaks.
|
|
880
|
+
*/
|
|
881
|
+
|
|
882
|
+
interface ResourceAcquisition {
|
|
883
|
+
nodeId: string;
|
|
884
|
+
type: 'acquireRelease' | 'acquireUseRelease' | 'scoped' | 'pool' | 'keyedPool';
|
|
885
|
+
acquireNodeId?: string;
|
|
886
|
+
releaseNodeId?: string;
|
|
887
|
+
location?: {
|
|
888
|
+
line: number;
|
|
889
|
+
column: number;
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
interface ScopeBoundary {
|
|
893
|
+
nodeId: string;
|
|
894
|
+
type: 'scoped' | 'scopeMake' | 'scopeUse' | 'scopeFork' | 'scopeAddFinalizer' | 'scopeExtend';
|
|
895
|
+
location?: {
|
|
896
|
+
line: number;
|
|
897
|
+
column: number;
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
interface ScopeResourceAnalysis {
|
|
901
|
+
acquisitions: ResourceAcquisition[];
|
|
902
|
+
scopeBoundaries: ScopeBoundary[];
|
|
903
|
+
poolCreations: string[];
|
|
904
|
+
potentialLeaks: string[];
|
|
905
|
+
}
|
|
906
|
+
declare function analyzeScopeResource(ir: StaticEffectIR): ScopeResourceAnalysis;
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* Observability Analysis (GAP 11)
|
|
910
|
+
*
|
|
911
|
+
* Detects Effect.withSpan, Effect.log*, Metric.*, Logger usage.
|
|
912
|
+
*/
|
|
913
|
+
|
|
914
|
+
interface SpanInfo {
|
|
915
|
+
nodeId: string;
|
|
916
|
+
name?: string;
|
|
917
|
+
location?: {
|
|
918
|
+
line: number;
|
|
919
|
+
column: number;
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
interface LogPointInfo {
|
|
923
|
+
nodeId: string;
|
|
924
|
+
level: 'debug' | 'info' | 'warning' | 'error';
|
|
925
|
+
location?: {
|
|
926
|
+
line: number;
|
|
927
|
+
column: number;
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
interface MetricInfo {
|
|
931
|
+
nodeId: string;
|
|
932
|
+
type: 'counter' | 'gauge' | 'histogram' | 'summary' | 'timer';
|
|
933
|
+
/** Whether this metric uses Metric.tagged / taggedWithLabels */
|
|
934
|
+
isTagged?: boolean;
|
|
935
|
+
location?: {
|
|
936
|
+
line: number;
|
|
937
|
+
column: number;
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
interface ObservabilityAnalysis {
|
|
941
|
+
spans: SpanInfo[];
|
|
942
|
+
logPoints: LogPointInfo[];
|
|
943
|
+
metrics: MetricInfo[];
|
|
944
|
+
coverage: {
|
|
945
|
+
effectCount: number;
|
|
946
|
+
effectsWithSpans: number;
|
|
947
|
+
effectsWithMetrics: number;
|
|
948
|
+
errorHandlersWithLogging: number;
|
|
949
|
+
errorHandlerCount: number;
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
declare function analyzeObservability(ir: StaticEffectIR): ObservabilityAnalysis;
|
|
953
|
+
|
|
954
|
+
interface ServiceCompletenessEntry {
|
|
955
|
+
serviceId: string;
|
|
956
|
+
status: 'ok' | 'missing' | 'missing-dependency';
|
|
957
|
+
providedBy?: string;
|
|
958
|
+
message: string;
|
|
959
|
+
}
|
|
960
|
+
interface DICompletenessReport {
|
|
961
|
+
programName: string;
|
|
962
|
+
requiredServices: string[];
|
|
963
|
+
providedByLayer: Map<string, string>;
|
|
964
|
+
entries: ServiceCompletenessEntry[];
|
|
965
|
+
layerGraphAcyclic: boolean;
|
|
966
|
+
valid: boolean;
|
|
967
|
+
readonly layerConflicts?: {
|
|
968
|
+
serviceId: string;
|
|
969
|
+
providers: SourceLocation[];
|
|
970
|
+
}[];
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Check DI completeness for a single program IR: required services vs what layers provide.
|
|
974
|
+
*/
|
|
975
|
+
declare function checkDICompleteness(ir: StaticEffectIR): DICompletenessReport;
|
|
976
|
+
/**
|
|
977
|
+
* Format a DI completeness report as text.
|
|
978
|
+
*/
|
|
979
|
+
declare function formatDICompletenessReport(report: DICompletenessReport): string;
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Strict Mode Diagnostics for Effect IR
|
|
983
|
+
*
|
|
984
|
+
* Validates Effect programs against strict rules: error type declarations,
|
|
985
|
+
* parallel/race error handling, and optional labelling.
|
|
986
|
+
*/
|
|
987
|
+
|
|
988
|
+
interface StrictDiagnostic {
|
|
989
|
+
rule: StrictRule;
|
|
990
|
+
severity: 'error' | 'warning';
|
|
991
|
+
message: string;
|
|
992
|
+
fix?: string | undefined;
|
|
993
|
+
location?: SourceLocation | undefined;
|
|
994
|
+
nodeId?: string | undefined;
|
|
995
|
+
}
|
|
996
|
+
type StrictRule = 'missing-error-type' | 'unknown-error-type' | 'parallel-missing-errors' | 'race-missing-errors' | 'effect-without-handler' | 'fiber-potential-leak' | 'resource-missing-scope' | 'unbounded-concurrency' | 'unused-service' | 'dead-code-path';
|
|
997
|
+
interface StrictValidationResult {
|
|
998
|
+
valid: boolean;
|
|
999
|
+
diagnostics: StrictDiagnostic[];
|
|
1000
|
+
errors: StrictDiagnostic[];
|
|
1001
|
+
warnings: StrictDiagnostic[];
|
|
1002
|
+
}
|
|
1003
|
+
interface StrictValidationOptions {
|
|
1004
|
+
/** Require effect nodes to have a declared error type (not unknown/never when they can fail) */
|
|
1005
|
+
requireErrors?: boolean | undefined;
|
|
1006
|
+
/** Require effects in parallel/race to have error type */
|
|
1007
|
+
requireParallelErrors?: boolean | undefined;
|
|
1008
|
+
warningsAsErrors?: boolean | undefined;
|
|
1009
|
+
}
|
|
1010
|
+
declare function validateStrict(ir: StaticEffectIR, options?: StrictValidationOptions): StrictValidationResult;
|
|
1011
|
+
declare function formatDiagnostics(result: StrictValidationResult): string;
|
|
1012
|
+
declare function formatDiagnosticsJSON(result: StrictValidationResult): string;
|
|
1013
|
+
declare function getSummary(result: StrictValidationResult): string;
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Path Generator
|
|
1017
|
+
*
|
|
1018
|
+
* Generates all possible execution paths through an Effect program based on
|
|
1019
|
+
* static analysis. Each path represents a unique sequence of steps that could
|
|
1020
|
+
* execute given certain conditions.
|
|
1021
|
+
*/
|
|
1022
|
+
|
|
1023
|
+
interface PathGeneratorOptions {
|
|
1024
|
+
/** Maximum paths to generate (default: 1000) */
|
|
1025
|
+
maxPaths?: number;
|
|
1026
|
+
/** Whether to include loop iterations as separate paths (default: false) */
|
|
1027
|
+
expandLoops?: boolean;
|
|
1028
|
+
/** Maximum loop iterations to expand if expandLoops is true (default: 3) */
|
|
1029
|
+
maxLoopIterations?: number;
|
|
1030
|
+
}
|
|
1031
|
+
interface PathGenerationResult {
|
|
1032
|
+
/** Generated effect paths */
|
|
1033
|
+
paths: EffectPath[];
|
|
1034
|
+
/** Whether the maxPaths limit was hit (truncation occurred) */
|
|
1035
|
+
limitHit: boolean;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Generate all possible execution paths through an Effect program.
|
|
1039
|
+
*/
|
|
1040
|
+
declare function generatePaths(ir: StaticEffectIR, options?: PathGeneratorOptions): EffectPath[];
|
|
1041
|
+
/**
|
|
1042
|
+
* Generate all possible execution paths with metadata.
|
|
1043
|
+
*/
|
|
1044
|
+
declare function generatePathsWithMetadata(ir: StaticEffectIR, options?: PathGeneratorOptions): PathGenerationResult;
|
|
1045
|
+
interface PathStatistics {
|
|
1046
|
+
totalPaths: number;
|
|
1047
|
+
pathLimitHit: boolean;
|
|
1048
|
+
pathsWithLoops: number;
|
|
1049
|
+
pathsWithUnresolvedRefs: number;
|
|
1050
|
+
uniqueConditions: string[];
|
|
1051
|
+
maxPathLength: number;
|
|
1052
|
+
minPathLength: number;
|
|
1053
|
+
avgPathLength: number;
|
|
1054
|
+
}
|
|
1055
|
+
interface PathStatisticsOptions {
|
|
1056
|
+
limitHit?: boolean;
|
|
1057
|
+
}
|
|
1058
|
+
declare function calculatePathStatistics(paths: EffectPath[], options?: PathStatisticsOptions): PathStatistics;
|
|
1059
|
+
declare function filterPaths(paths: EffectPath[], filter: {
|
|
1060
|
+
mustIncludeStep?: string;
|
|
1061
|
+
mustExcludeStep?: string;
|
|
1062
|
+
conditionTrue?: string;
|
|
1063
|
+
conditionFalse?: string;
|
|
1064
|
+
noLoops?: boolean;
|
|
1065
|
+
maxLength?: number;
|
|
1066
|
+
}): EffectPath[];
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Complexity Metrics Calculator
|
|
1070
|
+
*
|
|
1071
|
+
* Calculates complexity metrics for Effect programs including:
|
|
1072
|
+
* - Cyclomatic complexity (McCabe)
|
|
1073
|
+
* - Cognitive complexity (Sonar-style)
|
|
1074
|
+
* - Path count (bounded or unbounded)
|
|
1075
|
+
* - Depth and breadth metrics
|
|
1076
|
+
*/
|
|
1077
|
+
|
|
1078
|
+
declare const DEFAULT_THRESHOLDS: ComplexityThresholds;
|
|
1079
|
+
declare function calculateComplexity(ir: StaticEffectIR): ComplexityMetrics;
|
|
1080
|
+
interface ComplexityAssessment {
|
|
1081
|
+
level: 'low' | 'medium' | 'high' | 'very-high';
|
|
1082
|
+
warnings: ComplexityWarning[];
|
|
1083
|
+
recommendations: string[];
|
|
1084
|
+
}
|
|
1085
|
+
interface ComplexityWarning {
|
|
1086
|
+
type: 'cyclomatic' | 'cognitive' | 'paths' | 'depth' | 'breadth';
|
|
1087
|
+
message: string;
|
|
1088
|
+
severity: 'warning' | 'error';
|
|
1089
|
+
}
|
|
1090
|
+
declare function assessComplexity(metrics: ComplexityMetrics, thresholds?: ComplexityThresholds): ComplexityAssessment;
|
|
1091
|
+
declare function formatComplexitySummary(metrics: ComplexityMetrics, assessment: ComplexityAssessment): string;
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Test Coverage Matrix Generator
|
|
1095
|
+
*
|
|
1096
|
+
* Generates a test coverage matrix from Effect paths, helping developers
|
|
1097
|
+
* ensure all paths through an Effect program are tested.
|
|
1098
|
+
*/
|
|
1099
|
+
|
|
1100
|
+
interface TestMatrixOptions {
|
|
1101
|
+
/** Prefix for generated test names */
|
|
1102
|
+
testNamePrefix?: string;
|
|
1103
|
+
/** Function to customize test name generation */
|
|
1104
|
+
testNameGenerator?: (path: EffectPath) => string;
|
|
1105
|
+
/** Whether to include paths with loops (they may need special handling) */
|
|
1106
|
+
includeLoopPaths?: boolean;
|
|
1107
|
+
}
|
|
1108
|
+
declare function generateTestMatrix(paths: EffectPath[], options?: TestMatrixOptions): TestMatrix;
|
|
1109
|
+
declare function formatTestMatrixMarkdown(matrix: TestMatrix): string;
|
|
1110
|
+
declare function formatTestMatrixAsCode(matrix: TestMatrix, options?: {
|
|
1111
|
+
testRunner?: 'vitest' | 'jest' | 'mocha';
|
|
1112
|
+
programName?: string;
|
|
1113
|
+
}): string;
|
|
1114
|
+
declare function formatTestChecklist(matrix: TestMatrix): string;
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Config Module Analysis (GAP 9)
|
|
1118
|
+
*
|
|
1119
|
+
* Detects Effect Config / ConfigProvider usage.
|
|
1120
|
+
*/
|
|
1121
|
+
|
|
1122
|
+
interface ConfigItem {
|
|
1123
|
+
readonly key: string;
|
|
1124
|
+
readonly type: 'string' | 'number' | 'integer' | 'boolean' | 'date' | 'duration' | 'url' | 'port' | 'logLevel' | 'literal' | 'array' | 'map' | 'nested' | 'secret' | 'unknown';
|
|
1125
|
+
readonly required: boolean;
|
|
1126
|
+
readonly hasDefault: boolean;
|
|
1127
|
+
readonly location?: SourceLocation;
|
|
1128
|
+
}
|
|
1129
|
+
interface ConfigCombinator {
|
|
1130
|
+
readonly kind: 'map' | 'mapAttempt' | 'mapOrFail' | 'orElse' | 'orElseIf' | 'withDefault' | 'withDescription' | 'validate' | 'repeat' | 'option';
|
|
1131
|
+
readonly location?: SourceLocation;
|
|
1132
|
+
}
|
|
1133
|
+
interface ConfigAnalysis {
|
|
1134
|
+
readonly requiredConfigs: ConfigItem[];
|
|
1135
|
+
readonly optionalConfigs: ConfigItem[];
|
|
1136
|
+
readonly secretConfigs: ConfigItem[];
|
|
1137
|
+
readonly providerOverrides: string[];
|
|
1138
|
+
readonly envVarHints: Map<string, string>;
|
|
1139
|
+
readonly combinators: ConfigCombinator[];
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Analyze a TypeScript file for Effect Config usage.
|
|
1143
|
+
*/
|
|
1144
|
+
declare function analyzeConfig(filePath: string, source?: string): ConfigAnalysis;
|
|
1145
|
+
/**
|
|
1146
|
+
* Format config analysis as a markdown table.
|
|
1147
|
+
*/
|
|
1148
|
+
declare function formatConfigReport(analysis: ConfigAnalysis): string;
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* Pattern Matching (Match) Analysis (GAP 12)
|
|
1152
|
+
*
|
|
1153
|
+
* Detects Effect Match module usage and non-exhaustive matches.
|
|
1154
|
+
*/
|
|
1155
|
+
|
|
1156
|
+
interface MatchArmInfo {
|
|
1157
|
+
readonly kind: 'tag' | 'when' | 'not' | 'orElse' | 'exhaustive';
|
|
1158
|
+
readonly tag?: string;
|
|
1159
|
+
readonly location?: SourceLocation;
|
|
1160
|
+
}
|
|
1161
|
+
interface MatchAnalysis {
|
|
1162
|
+
readonly matchSites: MatchSiteInfo[];
|
|
1163
|
+
readonly nonExhaustive: MatchSiteInfo[];
|
|
1164
|
+
}
|
|
1165
|
+
interface MatchSiteInfo {
|
|
1166
|
+
readonly location?: SourceLocation;
|
|
1167
|
+
readonly arms: MatchArmInfo[];
|
|
1168
|
+
readonly hasExhaustive: boolean;
|
|
1169
|
+
readonly hasOrElse: boolean;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Analyze a file for Effect Match usage.
|
|
1173
|
+
*/
|
|
1174
|
+
declare function analyzeMatch(filePath: string, source?: string): MatchAnalysis;
|
|
1175
|
+
|
|
1176
|
+
/**
|
|
1177
|
+
* Platform Integration Detection (GAP 14)
|
|
1178
|
+
*
|
|
1179
|
+
* Detects which Effect platform modules are in use (HTTP, FileSystem, etc.).
|
|
1180
|
+
*/
|
|
1181
|
+
|
|
1182
|
+
interface PlatformUsageAnalysis {
|
|
1183
|
+
readonly platforms: ('node' | 'bun' | 'browser')[];
|
|
1184
|
+
readonly modules: {
|
|
1185
|
+
readonly http: {
|
|
1186
|
+
client: boolean;
|
|
1187
|
+
server: boolean;
|
|
1188
|
+
routes: string[];
|
|
1189
|
+
api: boolean;
|
|
1190
|
+
apiBuilder: boolean;
|
|
1191
|
+
endpoint: boolean;
|
|
1192
|
+
security: boolean;
|
|
1193
|
+
middleware: boolean;
|
|
1194
|
+
};
|
|
1195
|
+
readonly filesystem: {
|
|
1196
|
+
reads: string[];
|
|
1197
|
+
writes: string[];
|
|
1198
|
+
};
|
|
1199
|
+
readonly sockets: boolean;
|
|
1200
|
+
readonly terminal: boolean;
|
|
1201
|
+
readonly workers: boolean;
|
|
1202
|
+
readonly commands: string[];
|
|
1203
|
+
readonly keyValueStore: boolean;
|
|
1204
|
+
readonly multipart: boolean;
|
|
1205
|
+
readonly codecs: string[];
|
|
1206
|
+
readonly openApi: boolean;
|
|
1207
|
+
};
|
|
1208
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1209
|
+
readonly fileSystemOps?: {
|
|
1210
|
+
op: string;
|
|
1211
|
+
location: SourceLocation;
|
|
1212
|
+
}[];
|
|
1213
|
+
readonly commandOps?: {
|
|
1214
|
+
op: string;
|
|
1215
|
+
location: SourceLocation;
|
|
1216
|
+
}[];
|
|
1217
|
+
readonly routeDefinitions?: {
|
|
1218
|
+
readonly method: string;
|
|
1219
|
+
readonly name: string;
|
|
1220
|
+
readonly path: string;
|
|
1221
|
+
readonly location: SourceLocation;
|
|
1222
|
+
readonly apiId?: string;
|
|
1223
|
+
readonly groupName?: string;
|
|
1224
|
+
}[];
|
|
1225
|
+
readonly middlewareChain?: {
|
|
1226
|
+
name: string;
|
|
1227
|
+
location: SourceLocation;
|
|
1228
|
+
}[];
|
|
1229
|
+
readonly cliCommands?: {
|
|
1230
|
+
name: string;
|
|
1231
|
+
hasSchema: boolean;
|
|
1232
|
+
location: SourceLocation;
|
|
1233
|
+
}[];
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Analyze a file for Effect platform usage.
|
|
1237
|
+
*/
|
|
1238
|
+
declare function analyzePlatformUsage(filePath: string, source?: string): PlatformUsageAnalysis;
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
* Effect Schema AST → OpenAPI JSON Schema
|
|
1242
|
+
*
|
|
1243
|
+
* Walks Effect Schema expressions in the AST and produces OpenAPI-compatible
|
|
1244
|
+
* JSON Schema (no $schema, suitable for OpenAPI components.schemas).
|
|
1245
|
+
*/
|
|
1246
|
+
|
|
1247
|
+
type JsonSchemaObject = Record<string, unknown>;
|
|
1248
|
+
/**
|
|
1249
|
+
* Extract OpenAPI JSON Schema from an Effect Schema AST node.
|
|
1250
|
+
*/
|
|
1251
|
+
declare function schemaToJsonSchema(node: Node, sf: SourceFile, project: Project, defs?: Map<string, JsonSchemaObject>): JsonSchemaObject | undefined;
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* HttpApi Structure Extractor
|
|
1255
|
+
*
|
|
1256
|
+
* Extracts HttpApi, HttpApiGroup, and HttpApiEndpoint structure from @effect/platform
|
|
1257
|
+
* source code for API documentation generation.
|
|
1258
|
+
*/
|
|
1259
|
+
|
|
1260
|
+
interface HttpApiEndpointInfo {
|
|
1261
|
+
readonly name: string;
|
|
1262
|
+
readonly method: string;
|
|
1263
|
+
readonly path: string;
|
|
1264
|
+
readonly location: SourceLocation;
|
|
1265
|
+
readonly description?: string;
|
|
1266
|
+
readonly summary?: string;
|
|
1267
|
+
readonly deprecated?: boolean;
|
|
1268
|
+
readonly excluded?: boolean;
|
|
1269
|
+
/** Request body schema (from .setPayload) as OpenAPI JSON Schema */
|
|
1270
|
+
readonly requestSchema?: JsonSchemaObject;
|
|
1271
|
+
/** Success response schema (from .addSuccess) as OpenAPI JSON Schema */
|
|
1272
|
+
readonly responseSchema?: JsonSchemaObject;
|
|
1273
|
+
/** URL/query params schema (from .setUrlParams) as OpenAPI JSON Schema */
|
|
1274
|
+
readonly urlParamsSchema?: JsonSchemaObject;
|
|
1275
|
+
}
|
|
1276
|
+
interface HttpApiGroupInfo {
|
|
1277
|
+
readonly name: string;
|
|
1278
|
+
readonly endpoints: readonly HttpApiEndpointInfo[];
|
|
1279
|
+
readonly description?: string;
|
|
1280
|
+
readonly topLevel?: boolean;
|
|
1281
|
+
readonly prefix?: string;
|
|
1282
|
+
}
|
|
1283
|
+
interface HttpApiStructure {
|
|
1284
|
+
readonly apiId: string;
|
|
1285
|
+
readonly filePath: string;
|
|
1286
|
+
readonly groups: readonly HttpApiGroupInfo[];
|
|
1287
|
+
readonly prefix?: string;
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Extract HttpApi structure from a source file.
|
|
1291
|
+
* Returns all HttpApi.make(...) declarations with their groups and endpoints.
|
|
1292
|
+
*/
|
|
1293
|
+
declare function extractHttpApiStructure(sourceFile: SourceFile, filePath: string): HttpApiStructure[];
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* API Documentation Output
|
|
1297
|
+
*
|
|
1298
|
+
* Renders HttpApi structure as markdown and OpenAPI paths.
|
|
1299
|
+
*/
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Render API docs as markdown with H1 per API, H2 per group, and endpoint table.
|
|
1303
|
+
*/
|
|
1304
|
+
declare function renderApiDocsMarkdown(structures: readonly HttpApiStructure[]): string;
|
|
1305
|
+
/**
|
|
1306
|
+
* Render API structure as Mermaid flowchart (API -> groups -> endpoints).
|
|
1307
|
+
*/
|
|
1308
|
+
declare function renderApiDocsMermaid(structures: readonly HttpApiStructure[]): string;
|
|
1309
|
+
/**
|
|
1310
|
+
* Render minimal OpenAPI paths object for merging into full spec.
|
|
1311
|
+
* Includes request/response schemas when extracted from Effect Schema.
|
|
1312
|
+
*/
|
|
1313
|
+
declare function renderOpenApiPaths(structures: readonly HttpApiStructure[]): {
|
|
1314
|
+
paths: Record<string, Record<string, {
|
|
1315
|
+
operationId: string;
|
|
1316
|
+
summary?: string;
|
|
1317
|
+
deprecated?: boolean;
|
|
1318
|
+
requestBody?: {
|
|
1319
|
+
content: {
|
|
1320
|
+
'application/json': {
|
|
1321
|
+
schema: unknown;
|
|
1322
|
+
};
|
|
1323
|
+
};
|
|
1324
|
+
};
|
|
1325
|
+
responses?: Record<string, {
|
|
1326
|
+
content?: {
|
|
1327
|
+
'application/json': {
|
|
1328
|
+
schema: unknown;
|
|
1329
|
+
};
|
|
1330
|
+
};
|
|
1331
|
+
description?: string;
|
|
1332
|
+
}>;
|
|
1333
|
+
parameters?: {
|
|
1334
|
+
name: string;
|
|
1335
|
+
in: string;
|
|
1336
|
+
schema: unknown;
|
|
1337
|
+
}[];
|
|
1338
|
+
}>>;
|
|
1339
|
+
};
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Testing Pattern Analysis (GAP 16)
|
|
1343
|
+
*
|
|
1344
|
+
* Detects TestClock, TestContext, mock layers, and test entry points.
|
|
1345
|
+
*/
|
|
1346
|
+
|
|
1347
|
+
interface TestingPatternAnalysis {
|
|
1348
|
+
readonly testClockUsed: boolean;
|
|
1349
|
+
readonly testContextUsed: boolean;
|
|
1350
|
+
readonly mockLayers: string[];
|
|
1351
|
+
readonly runInTests: boolean;
|
|
1352
|
+
readonly effectVitestUsed: boolean;
|
|
1353
|
+
readonly effectVitestImported: boolean;
|
|
1354
|
+
readonly sharedLayerUsed: boolean;
|
|
1355
|
+
readonly testAnnotationsUsed: boolean;
|
|
1356
|
+
readonly flakyTestUsed: boolean;
|
|
1357
|
+
readonly exitAssertionsUsed: boolean;
|
|
1358
|
+
readonly testServicesUsed: boolean;
|
|
1359
|
+
readonly fastCheckUsed: boolean;
|
|
1360
|
+
readonly propertyTestUsed: boolean;
|
|
1361
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
* Analyze a file for Effect testing patterns.
|
|
1365
|
+
*/
|
|
1366
|
+
declare function analyzeTestingPatterns(filePath: string, source?: string): TestingPatternAnalysis;
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* Effect Version Compatibility (GAP 25)
|
|
1370
|
+
*
|
|
1371
|
+
* Reads package.json for Effect version and flags deprecated API usage.
|
|
1372
|
+
*/
|
|
1373
|
+
interface EffectVersionInfo {
|
|
1374
|
+
readonly version: string;
|
|
1375
|
+
readonly major: number;
|
|
1376
|
+
readonly minor: number;
|
|
1377
|
+
readonly patch: number;
|
|
1378
|
+
readonly isPrerelease: boolean;
|
|
1379
|
+
}
|
|
1380
|
+
interface VersionCompatReport {
|
|
1381
|
+
readonly effectVersion: EffectVersionInfo | null;
|
|
1382
|
+
readonly deprecationWarnings: string[];
|
|
1383
|
+
readonly suggestion: string | null;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Read Effect version from package.json at dir (or cwd).
|
|
1387
|
+
*/
|
|
1388
|
+
declare function getEffectVersion(dir?: string): Promise<EffectVersionInfo | null>;
|
|
1389
|
+
/**
|
|
1390
|
+
* Produce a minimal compatibility report (version + any known deprecations).
|
|
1391
|
+
*/
|
|
1392
|
+
declare function checkVersionCompat(projectRoot?: string): Promise<VersionCompatReport>;
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Effect.gen Yield Analysis Enhancement (GAP 28)
|
|
1396
|
+
*
|
|
1397
|
+
* Tracks variable bindings from yields and data flow through generator.
|
|
1398
|
+
*/
|
|
1399
|
+
|
|
1400
|
+
interface YieldBinding {
|
|
1401
|
+
readonly yieldIndex: number;
|
|
1402
|
+
readonly variableName?: string;
|
|
1403
|
+
readonly effectCallee?: string;
|
|
1404
|
+
readonly nodeId: string;
|
|
1405
|
+
}
|
|
1406
|
+
interface GenYieldAnalysis {
|
|
1407
|
+
readonly bindings: YieldBinding[];
|
|
1408
|
+
readonly unusedYieldIndices: number[];
|
|
1409
|
+
readonly serviceYields: string[];
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Analyze yield bindings and service usage in a generator program.
|
|
1413
|
+
*/
|
|
1414
|
+
declare function analyzeGenYields(ir: StaticEffectIR): GenYieldAnalysis;
|
|
1415
|
+
|
|
1416
|
+
/**
|
|
1417
|
+
* SQL / Database Pattern Detection (GAP 15)
|
|
1418
|
+
*
|
|
1419
|
+
* Detects SqlClient, SqlSchema, transactions, and N+1 patterns.
|
|
1420
|
+
*/
|
|
1421
|
+
|
|
1422
|
+
interface SqlPatternAnalysis {
|
|
1423
|
+
readonly sqlClientUsed: boolean;
|
|
1424
|
+
readonly withTransaction: boolean;
|
|
1425
|
+
readonly schemaDefs: string[];
|
|
1426
|
+
readonly queryInLoop: boolean;
|
|
1427
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1428
|
+
readonly resolvers?: {
|
|
1429
|
+
name: string;
|
|
1430
|
+
table?: string;
|
|
1431
|
+
location: SourceLocation;
|
|
1432
|
+
}[];
|
|
1433
|
+
readonly migrations?: {
|
|
1434
|
+
name: string;
|
|
1435
|
+
location: SourceLocation;
|
|
1436
|
+
}[];
|
|
1437
|
+
readonly queriesInLoops?: {
|
|
1438
|
+
query: string;
|
|
1439
|
+
location: SourceLocation;
|
|
1440
|
+
}[];
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Analyze a file for Effect SQL/database patterns.
|
|
1444
|
+
*/
|
|
1445
|
+
declare function analyzeSqlPatterns(filePath: string, source?: string): SqlPatternAnalysis;
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* RPC Pattern Detection (GAP 20)
|
|
1449
|
+
*
|
|
1450
|
+
* Detects @effect/rpc usage: Rpc.make, routers, client calls.
|
|
1451
|
+
*/
|
|
1452
|
+
|
|
1453
|
+
interface RpcPatternAnalysis {
|
|
1454
|
+
readonly rpcDefined: boolean;
|
|
1455
|
+
readonly routers: string[];
|
|
1456
|
+
readonly clientCalls: string[];
|
|
1457
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1458
|
+
readonly rpcDefinitions?: {
|
|
1459
|
+
name: string;
|
|
1460
|
+
isStreaming: boolean;
|
|
1461
|
+
location: SourceLocation;
|
|
1462
|
+
}[];
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* Analyze a file for Effect RPC patterns.
|
|
1466
|
+
*/
|
|
1467
|
+
declare function analyzeRpcPatterns(filePath: string, source?: string): RpcPatternAnalysis;
|
|
1468
|
+
|
|
1469
|
+
/**
|
|
1470
|
+
* Request Batching / DataLoader Pattern (GAP 19)
|
|
1471
|
+
*
|
|
1472
|
+
* Detects RequestResolver, Request.tagged, Effect.withRequestBatching.
|
|
1473
|
+
*/
|
|
1474
|
+
|
|
1475
|
+
interface RequestBatchingAnalysis {
|
|
1476
|
+
readonly requestTagged: boolean;
|
|
1477
|
+
readonly resolverBatched: boolean;
|
|
1478
|
+
readonly withBatching: boolean;
|
|
1479
|
+
readonly withCaching: boolean;
|
|
1480
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Analyze a file for Effect request batching patterns.
|
|
1484
|
+
*/
|
|
1485
|
+
declare function analyzeRequestBatching(filePath: string, source?: string): RequestBatchingAnalysis;
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* STM (Software Transactional Memory) Analysis (GAP 13)
|
|
1489
|
+
*
|
|
1490
|
+
* Detects STM.commit, TRef, TMap, TQueue, transactional refs.
|
|
1491
|
+
*/
|
|
1492
|
+
|
|
1493
|
+
interface StmAnalysis {
|
|
1494
|
+
readonly commitSites: SourceLocation[];
|
|
1495
|
+
readonly tRefs: string[];
|
|
1496
|
+
readonly tMaps: string[];
|
|
1497
|
+
readonly tQueues: string[];
|
|
1498
|
+
readonly retryUsed: boolean;
|
|
1499
|
+
readonly locations: Map<string, SourceLocation>;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Analyze a file for Effect STM usage.
|
|
1503
|
+
*/
|
|
1504
|
+
declare function analyzeStm(filePath: string, source?: string): StmAnalysis;
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* Effect Playground / REPL Integration (GAP 30 - minimal)
|
|
1508
|
+
*
|
|
1509
|
+
* Serializes IR + metadata for shareable or client-side exploration.
|
|
1510
|
+
*/
|
|
1511
|
+
|
|
1512
|
+
interface PlaygroundPayload {
|
|
1513
|
+
readonly version: 1;
|
|
1514
|
+
readonly ir: StaticEffectIR;
|
|
1515
|
+
readonly mermaid: string;
|
|
1516
|
+
readonly programName: string;
|
|
1517
|
+
readonly exportedAt: string;
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Export IR and Mermaid as a JSON payload for sharing or embedding.
|
|
1521
|
+
*/
|
|
1522
|
+
declare function exportForPlayground(ir: StaticEffectIR): PlaygroundPayload;
|
|
1523
|
+
/**
|
|
1524
|
+
* Encode payload as a base64 JSON string (for URL-safe sharing).
|
|
1525
|
+
*/
|
|
1526
|
+
declare function encodePlaygroundPayload(payload: PlaygroundPayload): string;
|
|
1527
|
+
/**
|
|
1528
|
+
* Decode a base64url string back to PlaygroundPayload.
|
|
1529
|
+
*/
|
|
1530
|
+
declare function decodePlaygroundPayload(encoded: string): PlaygroundPayload;
|
|
1531
|
+
|
|
1532
|
+
/**
|
|
1533
|
+
* Disk cache for analysis results.
|
|
1534
|
+
* When --cache is used, IR is stored by file path + content hash for reuse.
|
|
1535
|
+
*/
|
|
1536
|
+
|
|
1537
|
+
/**
|
|
1538
|
+
* Read cached IRs if valid (same content hash and mtime).
|
|
1539
|
+
*/
|
|
1540
|
+
declare function getCached(filePath: string, content: string, baseDir?: string): Promise<readonly StaticEffectIR[] | null>;
|
|
1541
|
+
/**
|
|
1542
|
+
* Write IRs to cache.
|
|
1543
|
+
*/
|
|
1544
|
+
declare function setCached(filePath: string, content: string, irs: readonly StaticEffectIR[], baseDir?: string): Promise<void>;
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* Const Inliner
|
|
1548
|
+
*
|
|
1549
|
+
* Resolves same-module const references for static analysis.
|
|
1550
|
+
* Handles patterns like:
|
|
1551
|
+
* const myErrors = tags('A', 'B');
|
|
1552
|
+
* await step('x', fn, { errors: myErrors });
|
|
1553
|
+
*
|
|
1554
|
+
* This is used by the analyzer to inline const values for full static extraction.
|
|
1555
|
+
*/
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Result of resolving a const reference.
|
|
1559
|
+
*/
|
|
1560
|
+
interface ConstResolution {
|
|
1561
|
+
/** Whether the resolution was successful */
|
|
1562
|
+
resolved: boolean;
|
|
1563
|
+
/** The resolved value (if successful) */
|
|
1564
|
+
value?: ConstValue;
|
|
1565
|
+
/** Reason for failure (if not resolved) */
|
|
1566
|
+
reason?: string;
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* A resolved const value.
|
|
1570
|
+
*/
|
|
1571
|
+
type ConstValue = {
|
|
1572
|
+
type: "string";
|
|
1573
|
+
value: string;
|
|
1574
|
+
} | {
|
|
1575
|
+
type: "number";
|
|
1576
|
+
value: number;
|
|
1577
|
+
} | {
|
|
1578
|
+
type: "boolean";
|
|
1579
|
+
value: boolean;
|
|
1580
|
+
} | {
|
|
1581
|
+
type: "array";
|
|
1582
|
+
value: ConstValue[];
|
|
1583
|
+
} | {
|
|
1584
|
+
type: "object";
|
|
1585
|
+
value: Record<string, ConstValue>;
|
|
1586
|
+
} | {
|
|
1587
|
+
type: "null";
|
|
1588
|
+
value: null;
|
|
1589
|
+
} | {
|
|
1590
|
+
type: "undefined";
|
|
1591
|
+
value: undefined;
|
|
1592
|
+
};
|
|
1593
|
+
/**
|
|
1594
|
+
* Cache for resolved const declarations in a source file.
|
|
1595
|
+
*/
|
|
1596
|
+
interface ConstCache {
|
|
1597
|
+
/** Map of variable name to its resolved value */
|
|
1598
|
+
values: Map<string, ConstResolution>;
|
|
1599
|
+
/** Source file this cache is for */
|
|
1600
|
+
sourceFile: SourceFile;
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Create a const cache for a source file.
|
|
1604
|
+
*/
|
|
1605
|
+
declare function createConstCache(sourceFile: SourceFile): ConstCache;
|
|
1606
|
+
/**
|
|
1607
|
+
* Resolve a const reference by name.
|
|
1608
|
+
*/
|
|
1609
|
+
declare function resolveConst(name: string, cache: ConstCache): ConstResolution;
|
|
1610
|
+
/**
|
|
1611
|
+
* Resolve a node to a const value.
|
|
1612
|
+
*/
|
|
1613
|
+
declare function resolveNode(node: Node, cache: ConstCache): ConstResolution;
|
|
1614
|
+
/**
|
|
1615
|
+
* Convert a ConstValue to a plain JavaScript value.
|
|
1616
|
+
*/
|
|
1617
|
+
declare function constValueToJS(value: ConstValue): unknown;
|
|
1618
|
+
/**
|
|
1619
|
+
* Extract string array from a ConstValue.
|
|
1620
|
+
* Returns undefined if the value is not a string array.
|
|
1621
|
+
*/
|
|
1622
|
+
declare function extractStringArray(value: ConstValue): string[] | undefined;
|
|
1623
|
+
/**
|
|
1624
|
+
* Extract a string from a ConstValue.
|
|
1625
|
+
* Returns undefined if the value is not a string.
|
|
1626
|
+
*/
|
|
1627
|
+
declare function extractString(value: ConstValue): string | undefined;
|
|
1628
|
+
|
|
1629
|
+
type StepChangeKind = "added" | "removed" | "unchanged" | "renamed" | "moved";
|
|
1630
|
+
interface StepDiffEntry {
|
|
1631
|
+
kind: StepChangeKind;
|
|
1632
|
+
stepId: string;
|
|
1633
|
+
previousStepId?: string;
|
|
1634
|
+
callee?: string;
|
|
1635
|
+
containerBefore?: string;
|
|
1636
|
+
containerAfter?: string;
|
|
1637
|
+
}
|
|
1638
|
+
interface StructuralChange {
|
|
1639
|
+
kind: "added" | "removed";
|
|
1640
|
+
nodeType: string;
|
|
1641
|
+
description: string;
|
|
1642
|
+
}
|
|
1643
|
+
interface DiffSummary {
|
|
1644
|
+
stepsAdded: number;
|
|
1645
|
+
stepsRemoved: number;
|
|
1646
|
+
stepsRenamed: number;
|
|
1647
|
+
stepsMoved: number;
|
|
1648
|
+
stepsUnchanged: number;
|
|
1649
|
+
structuralChanges: number;
|
|
1650
|
+
hasRegressions: boolean;
|
|
1651
|
+
}
|
|
1652
|
+
interface ProgramDiff {
|
|
1653
|
+
beforeName: string;
|
|
1654
|
+
afterName: string;
|
|
1655
|
+
diffedAt: number;
|
|
1656
|
+
steps: StepDiffEntry[];
|
|
1657
|
+
structuralChanges: StructuralChange[];
|
|
1658
|
+
summary: DiffSummary;
|
|
1659
|
+
}
|
|
1660
|
+
interface DiffOptions {
|
|
1661
|
+
detectRenames?: boolean;
|
|
1662
|
+
regressionMode?: boolean;
|
|
1663
|
+
}
|
|
1664
|
+
interface DiffMarkdownOptions {
|
|
1665
|
+
showUnchanged?: boolean;
|
|
1666
|
+
title?: string;
|
|
1667
|
+
}
|
|
1668
|
+
interface DiffMermaidOptions {
|
|
1669
|
+
showRemovedSteps?: boolean;
|
|
1670
|
+
direction?: "TB" | "LR" | "BT" | "RL";
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
declare function diffPrograms(before: StaticEffectIR, after: StaticEffectIR, options?: DiffOptions): ProgramDiff;
|
|
1674
|
+
|
|
1675
|
+
declare function renderDiffMarkdown(diff: ProgramDiff, options?: DiffMarkdownOptions): string;
|
|
1676
|
+
|
|
1677
|
+
declare function renderDiffJSON(diff: ProgramDiff, options?: {
|
|
1678
|
+
pretty?: boolean;
|
|
1679
|
+
}): string;
|
|
1680
|
+
|
|
1681
|
+
/**
|
|
1682
|
+
* Render a mermaid diagram of the "after" IR with diff annotations overlaid
|
|
1683
|
+
* (style classes for added, removed, moved, renamed steps).
|
|
1684
|
+
*/
|
|
1685
|
+
declare function renderDiffMermaid(after: StaticEffectIR, diff: ProgramDiff, options?: DiffMermaidOptions): string;
|
|
1686
|
+
|
|
1687
|
+
/**
|
|
1688
|
+
* Parse a source argument that can be:
|
|
1689
|
+
* - A file path (./src/foo.ts)
|
|
1690
|
+
* - A git ref:path combo (HEAD~1:src/foo.ts or main:src/foo.ts)
|
|
1691
|
+
* - A PR URL (https://github.com/org/repo/pull/123)
|
|
1692
|
+
*/
|
|
1693
|
+
declare function parseSourceArg(arg: string): {
|
|
1694
|
+
kind: 'file' | 'git-ref' | 'github-pr';
|
|
1695
|
+
filePath?: string;
|
|
1696
|
+
ref?: string;
|
|
1697
|
+
prUrl?: string;
|
|
1698
|
+
};
|
|
1699
|
+
/**
|
|
1700
|
+
* Resolve a git ref:path to the file contents from that commit.
|
|
1701
|
+
* Returns the source text of the file at the given ref.
|
|
1702
|
+
*/
|
|
1703
|
+
declare function resolveGitSource(ref: string, filePath: string, cwd?: string): string;
|
|
1704
|
+
|
|
1705
|
+
type AutoFormat = 'mermaid' | 'mermaid-railway' | 'mermaid-services' | 'mermaid-errors' | 'mermaid-concurrency' | 'mermaid-decisions' | 'mermaid-layers' | 'mermaid-retry' | 'mermaid-testability' | 'mermaid-dataflow' | 'mermaid-causes' | 'mermaid-timeline';
|
|
1706
|
+
/**
|
|
1707
|
+
* Analyzes the IR and returns the most relevant format names to render.
|
|
1708
|
+
* Includes `mermaid-railway` or `mermaid` as baseline (auto-detected),
|
|
1709
|
+
* plus up to 2 specialized formats based on what's interesting in the program.
|
|
1710
|
+
*/
|
|
1711
|
+
declare function selectFormats(ir: StaticEffectIR): AutoFormat[];
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Fiber Lifecycle Analysis
|
|
1715
|
+
*
|
|
1716
|
+
* Detects fiber fork patterns and potential leaks:
|
|
1717
|
+
* - Unscoped forks (Effect.fork) without a corresponding join/await/interrupt
|
|
1718
|
+
* - Daemon forks (fire-and-forget) flagged as intentional
|
|
1719
|
+
* - Scoped forks (forkScoped) always safe within scope
|
|
1720
|
+
*/
|
|
1721
|
+
|
|
1722
|
+
type FiberRisk = 'safe' | 'daemon' | 'potential-leak' | 'uncertain';
|
|
1723
|
+
interface FiberForkInfo {
|
|
1724
|
+
/** Node ID of the fork */
|
|
1725
|
+
nodeId: string;
|
|
1726
|
+
/** Fork variant */
|
|
1727
|
+
operation: StaticFiberNode['operation'];
|
|
1728
|
+
/** Whether this fork is scoped (forkScoped) */
|
|
1729
|
+
isScoped: boolean;
|
|
1730
|
+
/** Whether this fork is daemon (forkDaemon) — fire-and-forget intentional */
|
|
1731
|
+
isDaemon: boolean;
|
|
1732
|
+
/** Whether a join/await/interrupt is found in the same program tree */
|
|
1733
|
+
hasJoin: boolean;
|
|
1734
|
+
/** Risk classification */
|
|
1735
|
+
risk: FiberRisk;
|
|
1736
|
+
location?: {
|
|
1737
|
+
filePath: string;
|
|
1738
|
+
line: number;
|
|
1739
|
+
column: number;
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
interface FiberLeakAnalysis {
|
|
1743
|
+
/** All fork operations found */
|
|
1744
|
+
forks: FiberForkInfo[];
|
|
1745
|
+
/** Forks classified as potential leaks (unscoped, non-daemon, no join) */
|
|
1746
|
+
potentialLeaks: FiberForkInfo[];
|
|
1747
|
+
/** Daemon (fire-and-forget) forks */
|
|
1748
|
+
daemonForks: FiberForkInfo[];
|
|
1749
|
+
/** Safely scoped forks */
|
|
1750
|
+
safeForks: FiberForkInfo[];
|
|
1751
|
+
/** Summary counts */
|
|
1752
|
+
summary: {
|
|
1753
|
+
total: number;
|
|
1754
|
+
safe: number;
|
|
1755
|
+
daemon: number;
|
|
1756
|
+
potentialLeaks: number;
|
|
1757
|
+
uncertain: number;
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
declare function analyzeFiberLeaks(ir: StaticEffectIR): FiberLeakAnalysis;
|
|
1761
|
+
declare function formatFiberLeakReport(analysis: FiberLeakAnalysis): string;
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Type Signature Extractor
|
|
1765
|
+
*
|
|
1766
|
+
* Uses ts-morph's TypeChecker to extract Effect type parameters:
|
|
1767
|
+
* - A (Success type)
|
|
1768
|
+
* - E (Error type)
|
|
1769
|
+
* - R (Requirements/Context type)
|
|
1770
|
+
*/
|
|
1771
|
+
|
|
1772
|
+
/**
|
|
1773
|
+
* Extract Effect type signature from a node
|
|
1774
|
+
*/
|
|
1775
|
+
declare const extractEffectTypeSignature: (node: Node, _typeChecker: TypeChecker) => EffectTypeSignature | undefined;
|
|
1776
|
+
/**
|
|
1777
|
+
* Extract service requirements from a Context type
|
|
1778
|
+
*/
|
|
1779
|
+
declare const extractServiceRequirements: (node: Node, _typeChecker: TypeChecker) => ServiceRequirement[];
|
|
1780
|
+
/**
|
|
1781
|
+
* Track how an Effect type transforms through a pipe operation
|
|
1782
|
+
*/
|
|
1783
|
+
declare const trackTypeTransformation: (inputType: EffectTypeSignature, operation: string, outputType: EffectTypeSignature) => {
|
|
1784
|
+
operation: string;
|
|
1785
|
+
typeChange: string;
|
|
1786
|
+
};
|
|
1787
|
+
/**
|
|
1788
|
+
* Format type signature for display
|
|
1789
|
+
*/
|
|
1790
|
+
declare const formatTypeSignature: (sig: EffectTypeSignature) => string;
|
|
1791
|
+
/**
|
|
1792
|
+
* Extract Stream<A, E, R> type args from a node's type (regex fallback).
|
|
1793
|
+
*/
|
|
1794
|
+
declare function extractStreamTypeSignature(node: Node): StreamTypeSignature | undefined;
|
|
1795
|
+
/**
|
|
1796
|
+
* Extract Layer<ROut, E, RIn> type args from a node's type (regex fallback).
|
|
1797
|
+
*/
|
|
1798
|
+
declare function extractLayerTypeSignature(node: Node): LayerTypeSignature | undefined;
|
|
1799
|
+
/**
|
|
1800
|
+
* Extract Schedule<Out, In, R> type args from a node's type (regex fallback).
|
|
1801
|
+
*/
|
|
1802
|
+
declare function extractScheduleTypeSignature(node: Node): ScheduleTypeSignature | undefined;
|
|
1803
|
+
/**
|
|
1804
|
+
* Extract Cause<E> type arg from a node's type (regex fallback).
|
|
1805
|
+
*/
|
|
1806
|
+
declare function extractCauseTypeSignature(node: Node): CauseTypeSignature | undefined;
|
|
1807
|
+
/**
|
|
1808
|
+
* Check if a type is a Schema type
|
|
1809
|
+
*/
|
|
1810
|
+
declare const isSchemaType: (type: Type) => boolean;
|
|
1811
|
+
/**
|
|
1812
|
+
* Extract Schema validation information
|
|
1813
|
+
*/
|
|
1814
|
+
declare const extractSchemaInfo: (type: Type) => {
|
|
1815
|
+
encoded: string;
|
|
1816
|
+
decoded: string;
|
|
1817
|
+
} | undefined;
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Effect-Specific Linter
|
|
1821
|
+
*
|
|
1822
|
+
* Detects common issues and anti-patterns in Effect code:
|
|
1823
|
+
* - Untagged yields (potential bugs)
|
|
1824
|
+
* - Missing error handlers
|
|
1825
|
+
* - Unhandled error types
|
|
1826
|
+
* - Complex Layer compositions that could be simplified
|
|
1827
|
+
* - Dead code (unused yields)
|
|
1828
|
+
*/
|
|
1829
|
+
|
|
1830
|
+
interface LintRule {
|
|
1831
|
+
readonly name: string;
|
|
1832
|
+
readonly description: string;
|
|
1833
|
+
readonly severity: 'error' | 'warning' | 'info';
|
|
1834
|
+
readonly check: (ir: StaticEffectIR) => readonly LintIssue[];
|
|
1835
|
+
}
|
|
1836
|
+
interface LintIssue {
|
|
1837
|
+
readonly rule: string;
|
|
1838
|
+
readonly message: string;
|
|
1839
|
+
readonly severity: 'error' | 'warning' | 'info';
|
|
1840
|
+
readonly location?: SourceLocation | undefined;
|
|
1841
|
+
readonly nodeId?: string | undefined;
|
|
1842
|
+
/** Human-readable suggestion (shown in diagnostics) */
|
|
1843
|
+
readonly suggestion?: string | undefined;
|
|
1844
|
+
/** Optional code replacement for quick-fix (must be valid replacement text) */
|
|
1845
|
+
readonly fix?: string | undefined;
|
|
1846
|
+
}
|
|
1847
|
+
/**
|
|
1848
|
+
* Detect untagged yields in Effect.gen
|
|
1849
|
+
* A yield without storing the result is often a bug
|
|
1850
|
+
*/
|
|
1851
|
+
declare const untaggedYieldRule: LintRule;
|
|
1852
|
+
/**
|
|
1853
|
+
* Detect missing error handlers on Effects that can fail
|
|
1854
|
+
*/
|
|
1855
|
+
declare const missingErrorHandlerRule: LintRule;
|
|
1856
|
+
/**
|
|
1857
|
+
* Detect dead code - yields whose results are never used in later yields or return
|
|
1858
|
+
*/
|
|
1859
|
+
declare const deadCodeRule: LintRule;
|
|
1860
|
+
/**
|
|
1861
|
+
* Detect complex Layer compositions that could be simplified
|
|
1862
|
+
*/
|
|
1863
|
+
declare const complexLayerRule: LintRule;
|
|
1864
|
+
/**
|
|
1865
|
+
* Detect catchAll when catchTag would be more appropriate
|
|
1866
|
+
*/
|
|
1867
|
+
declare const catchAllVsCatchTagRule: LintRule;
|
|
1868
|
+
/** Error channel is unknown or Error instead of tagged errors */
|
|
1869
|
+
declare const errorTypeTooWideRule: LintRule;
|
|
1870
|
+
/** Effect.all with concurrency "unbounded" on potentially large collections */
|
|
1871
|
+
declare const unboundedParallelismRule: LintRule;
|
|
1872
|
+
/** .pipe() with only one transformation */
|
|
1873
|
+
declare const redundantPipeRule: LintRule;
|
|
1874
|
+
/** orDie used - may convert recoverable errors to defects */
|
|
1875
|
+
declare const orDieWarningRule: LintRule;
|
|
1876
|
+
declare const DEFAULT_LINT_RULES: readonly LintRule[];
|
|
1877
|
+
interface LintResult {
|
|
1878
|
+
readonly issues: readonly LintIssue[];
|
|
1879
|
+
readonly summary: {
|
|
1880
|
+
readonly errors: number;
|
|
1881
|
+
readonly warnings: number;
|
|
1882
|
+
readonly infos: number;
|
|
1883
|
+
readonly total: number;
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Run all lint rules on an Effect IR
|
|
1888
|
+
*/
|
|
1889
|
+
declare const lintEffectProgram: (ir: StaticEffectIR, rules?: readonly LintRule[]) => LintResult;
|
|
1890
|
+
/**
|
|
1891
|
+
* Format lint issues as a readable report
|
|
1892
|
+
*/
|
|
1893
|
+
declare const formatLintReport: (result: LintResult, programName: string) => string;
|
|
1894
|
+
|
|
1895
|
+
export { AnalysisError, type AnalyzeProjectOptions, AnalyzerOptions, CauseTypeSignature, type ComplexityAssessment, ComplexityMetrics, ComplexityThresholds, type ComplexityWarning, type CompositionResolverOptions, type ConfigAnalysis, type ConfigItem, type ConstCache, type ConstResolution, type ConstValue, type CoverageAuditResult, DEFAULT_LINT_RULES, DEFAULT_THRESHOLDS, type DICompletenessReport, type DataFlowEdge, type DataFlowGraph, type DataFlowIssue, type DataFlowNode, type DataFlowValidation, DiagramQuality, DiagramQualityWithFile, DiagramTopOffendersReport, type DiagramType, type DiamondDependency, type DisplayPathStep, type DocSection, type DocumentationOptions, type DuplicateWrite, EffectPath, EffectTypeSignature, type EffectVersionInfo, type EnhancedMermaidOptions, type ErrorFlowAnalysis, type ErrorFlowEdge, type ErrorPropagation, type ErrorPropagationAnalysis, type ErrorValidation, type FiberForkInfo, type FiberLeakAnalysis, type FileOutcome, type GenYieldAnalysis, type HtmlOutputOptions, type HttpApiEndpointInfo, type HttpApiGroupInfo, type HttpApiStructure, JSONRenderOptions, type JsonSchemaObject, type LayerCycle, type LayerDependencyGraph, type LayerGraphEdge, type LayerNodeInfo, LayerTypeSignature, type LintIssue, type LintResult, type LintRule, type LogPointInfo, type MatchAnalysis, type MatchArmInfo, type MatchSiteInfo, MermaidOptions, type MetricInfo, type MigrationOpportunity, type MigrationReport, type ObservabilityAnalysis, type PathGenerationResult, type PathGeneratorOptions, type PathStatistics, type PathStatisticsOptions, type PathSummaryResult, type PathsMermaidOptions, type PlatformUsageAnalysis, type PlaygroundPayload, type ProgramCallEdge, type ProgramGraph, type ProgramGraphNode, type ProjectAnalysisResult, type ProjectCompositionOptions, type ProjectFileFailure, ProjectServiceMap, ProjectServiceMap as ProjectServiceMapType, type RaceCondition, type RefInfo, type RefMutation, type RequestBatchingAnalysis, type ResourceAcquisition, type RpcPatternAnalysis, ScheduleTypeSignature, type ScopeBoundary, type ScopeResourceAnalysis, type ServiceCompletenessEntry, type ServiceFlowAnalysis, type ServiceLifecycleEntry, type ServiceProvision, ServiceRequirement, ShowcaseEntry, type ShowcaseOptions, SourceLocation, type SpanInfo, type SqlPatternAnalysis, type StateFlowAnalysis, StaticEffectIR, StaticEffectNode, StaticFiberNode, type StepErrorInfo, type StmAnalysis, StreamTypeSignature, type StrictDiagnostic, type StrictRule, type StrictValidationOptions, type StrictValidationResult, TestMatrix, type TestMatrixOptions, type TestingPatternAnalysis, type UndefinedRead, type UnresolvedProgramRef, type UnsatisfiedService, type VersionCompatReport, type YieldBinding, type YieldStarCall, analyzeConfig, analyzeEffectFile, analyzeEffectSource, analyzeErrorFlow, analyzeErrorPropagation, analyzeFiberLeaks, analyzeGenYields, analyzeMatch, analyzeObservability, analyzePlatformUsage, analyzeProgramGraph, analyzeProject, analyzeProjectComposition, analyzeRequestBatching, analyzeRpcPatterns, analyzeScopeResource, analyzeServiceFlow, analyzeSqlPatterns, analyzeStateFlow, analyzeStm, analyzeTestingPatterns, assessComplexity, buildDataFlowGraph, buildLayerDependencyGraph, buildProjectServiceMap, buildTopOffendersReport, calculateComplexity, calculateGraphComplexity, calculatePathStatistics, catchAllVsCatchTagRule, checkDICompleteness, checkVersionCompat, complexLayerRule, computeFileDiagramQuality, computeProgramDiagramQuality, constValueToJS, createConstCache, deadCodeRule, decodePlaygroundPayload, detectDiamondDependencies, detectLayerCycles, diffPrograms, encodePlaygroundPayload, errorTypeTooWideRule, exportForPlayground, extractCauseTypeSignature, extractEffectTypeSignature, extractHttpApiStructure, extractLayerTypeSignature, extractScheduleTypeSignature, extractSchemaInfo, extractServiceRequirements, extractStreamTypeSignature, extractString, extractStringArray, filterPaths, findCycles, findMigrationOpportunities, findMigrationOpportunitiesInProject, findUnsatisfiedServices, formatComplexitySummary, formatConfigReport, formatDICompletenessReport, formatDiagnostics, formatDiagnosticsJSON, formatErrorSummary, formatFiberLeakReport, formatLintReport, formatMigrationReport, formatTestChecklist, formatTestMatrixAsCode, formatTestMatrixMarkdown, formatTypeSignature, generateMultipleShowcase, generatePaths, generatePathsWithMetadata, generateShowcase, generateTestMatrix, getCached, getConsumers, getDataFlowOrder, getDependencies, getDependents, getEffectVersion, getErrorProducers, getErrorsAtPoint, getProducers, getSummary, getTopologicalOrder, getTransitiveDependencies, inferBestDiagramType, isSchemaType, lintEffectProgram, loadDiagramQualityHintsFromEslintJson, missingErrorHandlerRule, orDieWarningRule, parseSourceArg, redundantPipeRule, renderApiDocsMarkdown, renderApiDocsMermaid, renderCausesMermaid, renderCompositionMermaid, renderCompositionWithServicesMermaid, renderConcurrencyMermaid, renderDataFlowMermaid, renderDataflowMermaid, renderDecisionsMermaid, renderDependencyMatrix, renderDependencyMatrixFromServiceMap, renderDiffJSON, renderDiffMarkdown, renderDiffMermaid, renderDocumentation, renderEnhancedMermaid, renderEnhancedMermaidEffect, renderErrorFlowMermaid, renderErrorsMermaid, renderExplanation, renderGraphMermaid, renderInteractiveHTML, renderJSON, renderLayerGraphMermaid, renderLayersMermaid, renderMermaid, renderMultiProgramDocs, renderMultipleExplanations, renderMultipleJSON, renderMultipleSummaries, renderOpenApiPaths, renderPathsMermaid, renderRailwayMermaid, renderRetryGanttMermaid, renderRetryMermaid, renderSequenceMermaid, renderServiceGraphMermaid, renderServicesMermaid, renderServicesMermaidFromMap, renderStaticMermaid, renderSummary, renderTestabilityMermaid, renderTimelineMermaid, resetIdCounter, resolveConst, resolveGitSource, resolveNode, runCoverageAudit, schemaToJsonSchema, selectFormats, setCached, summarizePathSteps, trackTypeTransformation, unboundedParallelismRule, untaggedYieldRule, validateDataFlow, validateStrict, validateWorkflowErrors };
|