perfgraph 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.
Files changed (263) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/causal/builder.d.ts +34 -0
  4. package/dist/causal/builder.d.ts.map +1 -0
  5. package/dist/causal/builder.js +132 -0
  6. package/dist/causal/builder.js.map +1 -0
  7. package/dist/causal/index.d.ts +11 -0
  8. package/dist/causal/index.d.ts.map +1 -0
  9. package/dist/causal/index.js +10 -0
  10. package/dist/causal/index.js.map +1 -0
  11. package/dist/causal/rules/js.d.ts +49 -0
  12. package/dist/causal/rules/js.d.ts.map +1 -0
  13. package/dist/causal/rules/js.js +209 -0
  14. package/dist/causal/rules/js.js.map +1 -0
  15. package/dist/causal/rules/layout.d.ts +39 -0
  16. package/dist/causal/rules/layout.d.ts.map +1 -0
  17. package/dist/causal/rules/layout.js +169 -0
  18. package/dist/causal/rules/layout.js.map +1 -0
  19. package/dist/causal/rules/lcp.d.ts +49 -0
  20. package/dist/causal/rules/lcp.d.ts.map +1 -0
  21. package/dist/causal/rules/lcp.js +250 -0
  22. package/dist/causal/rules/lcp.js.map +1 -0
  23. package/dist/causal/rules/network.d.ts +39 -0
  24. package/dist/causal/rules/network.d.ts.map +1 -0
  25. package/dist/causal/rules/network.js +140 -0
  26. package/dist/causal/rules/network.js.map +1 -0
  27. package/dist/causal/types.d.ts +142 -0
  28. package/dist/causal/types.d.ts.map +1 -0
  29. package/dist/causal/types.js +88 -0
  30. package/dist/causal/types.js.map +1 -0
  31. package/dist/cli/analyze.d.ts +33 -0
  32. package/dist/cli/analyze.d.ts.map +1 -0
  33. package/dist/cli/analyze.js +137 -0
  34. package/dist/cli/analyze.js.map +1 -0
  35. package/dist/cli/collect.d.ts +28 -0
  36. package/dist/cli/collect.d.ts.map +1 -0
  37. package/dist/cli/collect.js +125 -0
  38. package/dist/cli/collect.js.map +1 -0
  39. package/dist/cli/extract.d.ts +31 -0
  40. package/dist/cli/extract.d.ts.map +1 -0
  41. package/dist/cli/extract.js +135 -0
  42. package/dist/cli/extract.js.map +1 -0
  43. package/dist/cli/mcp.d.ts +14 -0
  44. package/dist/cli/mcp.d.ts.map +1 -0
  45. package/dist/cli/mcp.js +53 -0
  46. package/dist/cli/mcp.js.map +1 -0
  47. package/dist/cli/normalize.d.ts +58 -0
  48. package/dist/cli/normalize.d.ts.map +1 -0
  49. package/dist/cli/normalize.js +179 -0
  50. package/dist/cli/normalize.js.map +1 -0
  51. package/dist/cli/report.d.ts +33 -0
  52. package/dist/cli/report.d.ts.map +1 -0
  53. package/dist/cli/report.js +137 -0
  54. package/dist/cli/report.js.map +1 -0
  55. package/dist/cli/run.d.ts +49 -0
  56. package/dist/cli/run.d.ts.map +1 -0
  57. package/dist/cli/run.js +243 -0
  58. package/dist/cli/run.js.map +1 -0
  59. package/dist/collect/buffer-monitor.d.ts +25 -0
  60. package/dist/collect/buffer-monitor.d.ts.map +1 -0
  61. package/dist/collect/buffer-monitor.js +69 -0
  62. package/dist/collect/buffer-monitor.js.map +1 -0
  63. package/dist/collect/console.d.ts +25 -0
  64. package/dist/collect/console.d.ts.map +1 -0
  65. package/dist/collect/console.js +82 -0
  66. package/dist/collect/console.js.map +1 -0
  67. package/dist/collect/coverage.d.ts +26 -0
  68. package/dist/collect/coverage.d.ts.map +1 -0
  69. package/dist/collect/coverage.js +99 -0
  70. package/dist/collect/coverage.js.map +1 -0
  71. package/dist/collect/dom.d.ts +37 -0
  72. package/dist/collect/dom.d.ts.map +1 -0
  73. package/dist/collect/dom.js +118 -0
  74. package/dist/collect/dom.js.map +1 -0
  75. package/dist/collect/lighthouse.d.ts +41 -0
  76. package/dist/collect/lighthouse.d.ts.map +1 -0
  77. package/dist/collect/lighthouse.js +111 -0
  78. package/dist/collect/lighthouse.js.map +1 -0
  79. package/dist/collect/network.d.ts +32 -0
  80. package/dist/collect/network.d.ts.map +1 -0
  81. package/dist/collect/network.js +236 -0
  82. package/dist/collect/network.js.map +1 -0
  83. package/dist/collect/orchestrator.d.ts +23 -0
  84. package/dist/collect/orchestrator.d.ts.map +1 -0
  85. package/dist/collect/orchestrator.js +350 -0
  86. package/dist/collect/orchestrator.js.map +1 -0
  87. package/dist/collect/performance.d.ts +28 -0
  88. package/dist/collect/performance.d.ts.map +1 -0
  89. package/dist/collect/performance.js +108 -0
  90. package/dist/collect/performance.js.map +1 -0
  91. package/dist/collect/runtime.d.ts +26 -0
  92. package/dist/collect/runtime.d.ts.map +1 -0
  93. package/dist/collect/runtime.js +81 -0
  94. package/dist/collect/runtime.js.map +1 -0
  95. package/dist/collect/session.d.ts +58 -0
  96. package/dist/collect/session.d.ts.map +1 -0
  97. package/dist/collect/session.js +162 -0
  98. package/dist/collect/session.js.map +1 -0
  99. package/dist/collect/trace.d.ts +40 -0
  100. package/dist/collect/trace.d.ts.map +1 -0
  101. package/dist/collect/trace.js +127 -0
  102. package/dist/collect/trace.js.map +1 -0
  103. package/dist/collect/types.d.ts +317 -0
  104. package/dist/collect/types.d.ts.map +1 -0
  105. package/dist/collect/types.js +12 -0
  106. package/dist/collect/types.js.map +1 -0
  107. package/dist/distill/insights.d.ts +67 -0
  108. package/dist/distill/insights.d.ts.map +1 -0
  109. package/dist/distill/insights.js +317 -0
  110. package/dist/distill/insights.js.map +1 -0
  111. package/dist/distill/summaries.d.ts +71 -0
  112. package/dist/distill/summaries.d.ts.map +1 -0
  113. package/dist/distill/summaries.js +165 -0
  114. package/dist/distill/summaries.js.map +1 -0
  115. package/dist/extract/critical-path.d.ts +17 -0
  116. package/dist/extract/critical-path.d.ts.map +1 -0
  117. package/dist/extract/critical-path.js +95 -0
  118. package/dist/extract/critical-path.js.map +1 -0
  119. package/dist/extract/index.d.ts +16 -0
  120. package/dist/extract/index.d.ts.map +1 -0
  121. package/dist/extract/index.js +32 -0
  122. package/dist/extract/index.js.map +1 -0
  123. package/dist/extract/js-hotspots.d.ts +15 -0
  124. package/dist/extract/js-hotspots.d.ts.map +1 -0
  125. package/dist/extract/js-hotspots.js +22 -0
  126. package/dist/extract/js-hotspots.js.map +1 -0
  127. package/dist/extract/layout-shifts.d.ts +19 -0
  128. package/dist/extract/layout-shifts.d.ts.map +1 -0
  129. package/dist/extract/layout-shifts.js +47 -0
  130. package/dist/extract/layout-shifts.js.map +1 -0
  131. package/dist/extract/lcp-breakdown.d.ts +19 -0
  132. package/dist/extract/lcp-breakdown.d.ts.map +1 -0
  133. package/dist/extract/lcp-breakdown.js +110 -0
  134. package/dist/extract/lcp-breakdown.js.map +1 -0
  135. package/dist/extract/main-thread.d.ts +16 -0
  136. package/dist/extract/main-thread.d.ts.map +1 -0
  137. package/dist/extract/main-thread.js +41 -0
  138. package/dist/extract/main-thread.js.map +1 -0
  139. package/dist/extract/render-blocking.d.ts +16 -0
  140. package/dist/extract/render-blocking.d.ts.map +1 -0
  141. package/dist/extract/render-blocking.js +79 -0
  142. package/dist/extract/render-blocking.js.map +1 -0
  143. package/dist/extract/third-party.d.ts +15 -0
  144. package/dist/extract/third-party.d.ts.map +1 -0
  145. package/dist/extract/third-party.js +127 -0
  146. package/dist/extract/third-party.js.map +1 -0
  147. package/dist/extract/types.d.ts +183 -0
  148. package/dist/extract/types.d.ts.map +1 -0
  149. package/dist/extract/types.js +118 -0
  150. package/dist/extract/types.js.map +1 -0
  151. package/dist/index.d.ts +20 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +188 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/mcp/handlers.d.ts +72 -0
  156. package/dist/mcp/handlers.d.ts.map +1 -0
  157. package/dist/mcp/handlers.js +285 -0
  158. package/dist/mcp/handlers.js.map +1 -0
  159. package/dist/mcp/progress.d.ts +37 -0
  160. package/dist/mcp/progress.d.ts.map +1 -0
  161. package/dist/mcp/progress.js +51 -0
  162. package/dist/mcp/progress.js.map +1 -0
  163. package/dist/mcp/prompts.d.ts +57 -0
  164. package/dist/mcp/prompts.d.ts.map +1 -0
  165. package/dist/mcp/prompts.js +225 -0
  166. package/dist/mcp/prompts.js.map +1 -0
  167. package/dist/mcp/resources.d.ts +48 -0
  168. package/dist/mcp/resources.d.ts.map +1 -0
  169. package/dist/mcp/resources.js +149 -0
  170. package/dist/mcp/resources.js.map +1 -0
  171. package/dist/mcp/server.d.ts +34 -0
  172. package/dist/mcp/server.d.ts.map +1 -0
  173. package/dist/mcp/server.js +452 -0
  174. package/dist/mcp/server.js.map +1 -0
  175. package/dist/mcp/types.d.ts +47 -0
  176. package/dist/mcp/types.d.ts.map +1 -0
  177. package/dist/mcp/types.js +67 -0
  178. package/dist/mcp/types.js.map +1 -0
  179. package/dist/normalize/clock.d.ts +40 -0
  180. package/dist/normalize/clock.d.ts.map +1 -0
  181. package/dist/normalize/clock.js +96 -0
  182. package/dist/normalize/clock.js.map +1 -0
  183. package/dist/normalize/dom-ir.d.ts +16 -0
  184. package/dist/normalize/dom-ir.d.ts.map +1 -0
  185. package/dist/normalize/dom-ir.js +48 -0
  186. package/dist/normalize/dom-ir.js.map +1 -0
  187. package/dist/normalize/index.d.ts +23 -0
  188. package/dist/normalize/index.d.ts.map +1 -0
  189. package/dist/normalize/index.js +118 -0
  190. package/dist/normalize/index.js.map +1 -0
  191. package/dist/normalize/lighthouse-insights.d.ts +27 -0
  192. package/dist/normalize/lighthouse-insights.d.ts.map +1 -0
  193. package/dist/normalize/lighthouse-insights.js +318 -0
  194. package/dist/normalize/lighthouse-insights.js.map +1 -0
  195. package/dist/normalize/lighthouse-ir.d.ts +25 -0
  196. package/dist/normalize/lighthouse-ir.d.ts.map +1 -0
  197. package/dist/normalize/lighthouse-ir.js +151 -0
  198. package/dist/normalize/lighthouse-ir.js.map +1 -0
  199. package/dist/normalize/network-ir.d.ts +23 -0
  200. package/dist/normalize/network-ir.d.ts.map +1 -0
  201. package/dist/normalize/network-ir.js +180 -0
  202. package/dist/normalize/network-ir.js.map +1 -0
  203. package/dist/normalize/runtime-ir.d.ts +18 -0
  204. package/dist/normalize/runtime-ir.d.ts.map +1 -0
  205. package/dist/normalize/runtime-ir.js +114 -0
  206. package/dist/normalize/runtime-ir.js.map +1 -0
  207. package/dist/normalize/trace-ir.d.ts +20 -0
  208. package/dist/normalize/trace-ir.d.ts.map +1 -0
  209. package/dist/normalize/trace-ir.js +224 -0
  210. package/dist/normalize/trace-ir.js.map +1 -0
  211. package/dist/normalize/types.d.ts +536 -0
  212. package/dist/normalize/types.d.ts.map +1 -0
  213. package/dist/normalize/types.js +242 -0
  214. package/dist/normalize/types.js.map +1 -0
  215. package/dist/output/manifest.d.ts +44 -0
  216. package/dist/output/manifest.d.ts.map +1 -0
  217. package/dist/output/manifest.js +232 -0
  218. package/dist/output/manifest.js.map +1 -0
  219. package/dist/output/toon.d.ts +19 -0
  220. package/dist/output/toon.d.ts.map +1 -0
  221. package/dist/output/toon.js +22 -0
  222. package/dist/output/toon.js.map +1 -0
  223. package/dist/output/writer.d.ts +31 -0
  224. package/dist/output/writer.d.ts.map +1 -0
  225. package/dist/output/writer.js +51 -0
  226. package/dist/output/writer.js.map +1 -0
  227. package/dist/report/analyzer.d.ts +29 -0
  228. package/dist/report/analyzer.d.ts.map +1 -0
  229. package/dist/report/analyzer.js +330 -0
  230. package/dist/report/analyzer.js.map +1 -0
  231. package/dist/report/index.d.ts +13 -0
  232. package/dist/report/index.d.ts.map +1 -0
  233. package/dist/report/index.js +12 -0
  234. package/dist/report/index.js.map +1 -0
  235. package/dist/report/markdown.d.ts +21 -0
  236. package/dist/report/markdown.d.ts.map +1 -0
  237. package/dist/report/markdown.js +182 -0
  238. package/dist/report/markdown.js.map +1 -0
  239. package/dist/report/remediations.d.ts +42 -0
  240. package/dist/report/remediations.d.ts.map +1 -0
  241. package/dist/report/remediations.js +179 -0
  242. package/dist/report/remediations.js.map +1 -0
  243. package/dist/report/scorer.d.ts +35 -0
  244. package/dist/report/scorer.d.ts.map +1 -0
  245. package/dist/report/scorer.js +72 -0
  246. package/dist/report/scorer.js.map +1 -0
  247. package/dist/report/types.d.ts +201 -0
  248. package/dist/report/types.d.ts.map +1 -0
  249. package/dist/report/types.js +149 -0
  250. package/dist/report/types.js.map +1 -0
  251. package/dist/shared/fs-utils.d.ts +12 -0
  252. package/dist/shared/fs-utils.d.ts.map +1 -0
  253. package/dist/shared/fs-utils.js +44 -0
  254. package/dist/shared/fs-utils.js.map +1 -0
  255. package/dist/shared/types.d.ts +69 -0
  256. package/dist/shared/types.d.ts.map +1 -0
  257. package/dist/shared/types.js +18 -0
  258. package/dist/shared/types.js.map +1 -0
  259. package/dist/shared/utils.d.ts +6 -0
  260. package/dist/shared/utils.d.ts.map +1 -0
  261. package/dist/shared/utils.js +9 -0
  262. package/dist/shared/utils.js.map +1 -0
  263. package/package.json +67 -0
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Markdown report generator — produces a human-readable performance report
3
+ * from a PerfGraph {@link Report} and optional {@link Insights}.
4
+ *
5
+ * The output is designed for direct consumption by developers and includes
6
+ * score summary, all issues with severities, causal chains, recommendations,
7
+ * and Lighthouse insights when available.
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ // ---------------------------------------------------------------------------
12
+ // Severity → emoji helpers
13
+ // ---------------------------------------------------------------------------
14
+ function severityBadge(severity) {
15
+ switch (severity) {
16
+ case 'critical':
17
+ return '🔴';
18
+ case 'warning':
19
+ return '🟡';
20
+ case 'high':
21
+ return '🟡';
22
+ case 'info':
23
+ return '🔵';
24
+ default:
25
+ return '⚪';
26
+ }
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // Public API
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Generate a human-readable markdown report from a PerfGraph Report + Insights.
33
+ *
34
+ * @param report - The structured report from `buildReport()`
35
+ * @param insights - Optional Lighthouse-derived insights from `buildInsights()`
36
+ * @returns A formatted Markdown string
37
+ */
38
+ export function buildReportMarkdown(report, insights) {
39
+ const lines = [];
40
+ // -----------------------------------------------------------------------
41
+ // Header
42
+ // -----------------------------------------------------------------------
43
+ lines.push('# PerfGraph Performance Report');
44
+ lines.push('');
45
+ lines.push(`**URL:** ${report.meta.url}`);
46
+ lines.push(`**Analyzed at:** ${report.meta.analyzedAt}`);
47
+ lines.push(`**Score:** ${report.summary.score.toUpperCase()}`);
48
+ if (report.summary.lighthousePerformance != null) {
49
+ lines.push(`**Lighthouse Performance:** ${(report.summary.lighthousePerformance * 100).toFixed(0)}/100`);
50
+ }
51
+ if (report.summary.scoreExplanation) {
52
+ lines.push(`**Note:** ${report.summary.scoreExplanation}`);
53
+ }
54
+ lines.push('');
55
+ // -----------------------------------------------------------------------
56
+ // Summary stats
57
+ // -----------------------------------------------------------------------
58
+ lines.push('## Summary');
59
+ lines.push('');
60
+ lines.push('| Metric | Count |');
61
+ lines.push('|--------|-------|');
62
+ lines.push(`| Critical issues | ${report.summary.criticalIssues} |`);
63
+ lines.push(`| Warnings | ${report.summary.warnings} |`);
64
+ lines.push(`| Info | ${report.summary.infos} |`);
65
+ lines.push('');
66
+ // -----------------------------------------------------------------------
67
+ // Top Issues
68
+ // -----------------------------------------------------------------------
69
+ if (report.summary.topIssues.length > 0) {
70
+ lines.push('## Top Issues');
71
+ lines.push('');
72
+ for (const issue of report.summary.topIssues) {
73
+ lines.push(`### ${severityBadge(issue.severity)} ${issue.label}`);
74
+ lines.push('');
75
+ lines.push(`- **Confidence:** ${issue.confidence}`);
76
+ lines.push('');
77
+ }
78
+ }
79
+ // -----------------------------------------------------------------------
80
+ // All Issues
81
+ // -----------------------------------------------------------------------
82
+ if (report.issues.length > 0) {
83
+ lines.push('## All Issues');
84
+ lines.push('');
85
+ for (const issue of report.issues) {
86
+ lines.push(`### ${severityBadge(issue.severity)} ${issue.label}`);
87
+ lines.push('');
88
+ lines.push(`**ID:** \`${issue.id}\``);
89
+ lines.push(`**Severity:** ${issue.severity}`);
90
+ if (issue.value != null) {
91
+ lines.push(`**Value:** ${issue.value}${issue.unit ? ` ${issue.unit}` : ''}`);
92
+ }
93
+ if (issue.evidence?.urls && issue.evidence.urls.length > 0) {
94
+ lines.push('**URLs:**');
95
+ for (const url of issue.evidence.urls) {
96
+ lines.push(`- \`${url}\``);
97
+ }
98
+ }
99
+ if (issue.evidence?.selector) {
100
+ lines.push(`**Selector:** \`${issue.evidence.selector}\``);
101
+ }
102
+ lines.push('');
103
+ lines.push(issue.remediation);
104
+ lines.push('');
105
+ lines.push('---');
106
+ lines.push('');
107
+ }
108
+ }
109
+ // -----------------------------------------------------------------------
110
+ // Causal Chains
111
+ // -----------------------------------------------------------------------
112
+ if (report.chains.length > 0) {
113
+ lines.push('## Causal Chains');
114
+ lines.push('');
115
+ for (const chain of report.chains) {
116
+ lines.push(`### ${severityBadge(chain.severity)} ${chain.rootCause}`);
117
+ lines.push('');
118
+ lines.push(`**Impact:** ${chain.impact}`);
119
+ lines.push(`**Confidence:** ${chain.confidence}`);
120
+ lines.push(`**Path:** \`${chain.path.map((n) => n.label).join(' → ')}\``);
121
+ lines.push('');
122
+ }
123
+ }
124
+ // -----------------------------------------------------------------------
125
+ // Recommendations
126
+ // -----------------------------------------------------------------------
127
+ if (report.recommendations.length > 0) {
128
+ lines.push('## Recommendations');
129
+ lines.push('');
130
+ for (const rec of report.recommendations) {
131
+ const badge = severityBadge(rec.priority);
132
+ lines.push(`### ${badge} [${rec.category}] ${rec.title}`);
133
+ lines.push('');
134
+ lines.push(rec.action);
135
+ if (rec.expectedImpact) {
136
+ lines.push('');
137
+ lines.push(`**Expected impact:** ${rec.expectedImpact}`);
138
+ }
139
+ lines.push('');
140
+ }
141
+ }
142
+ // -----------------------------------------------------------------------
143
+ // Lighthouse Insights
144
+ // -----------------------------------------------------------------------
145
+ if (insights?.lighthouse) {
146
+ lines.push('## Lighthouse Insights');
147
+ lines.push('');
148
+ lines.push('| Metric | Value |');
149
+ lines.push('|--------|-------|');
150
+ if (insights.lighthouse.performance != null) {
151
+ lines.push(`| Performance | ${(insights.lighthouse.performance * 100).toFixed(0)} |`);
152
+ }
153
+ if (insights.lighthouse.lcpMs != null) {
154
+ lines.push(`| LCP | ${insights.lighthouse.lcpMs} ms |`);
155
+ }
156
+ if (insights.lighthouse.fcpMs != null) {
157
+ lines.push(`| FCP | ${insights.lighthouse.fcpMs} ms |`);
158
+ }
159
+ if (insights.lighthouse.cls != null) {
160
+ lines.push(`| CLS | ${insights.lighthouse.cls.toFixed(3)} |`);
161
+ }
162
+ if (insights.lighthouse.tbtMs != null) {
163
+ lines.push(`| TBT | ${insights.lighthouse.tbtMs} ms |`);
164
+ }
165
+ lines.push('');
166
+ if (insights.lcpElement) {
167
+ lines.push(`**LCP Element:** \`${insights.lcpElement.selector}\``);
168
+ lines.push('');
169
+ }
170
+ if (insights.renderBlocking && insights.renderBlocking.length > 0) {
171
+ lines.push(`**Render-blocking resources:** ${insights.renderBlocking.length} total`);
172
+ lines.push('');
173
+ }
174
+ }
175
+ // -----------------------------------------------------------------------
176
+ // Footer
177
+ // -----------------------------------------------------------------------
178
+ lines.push('---');
179
+ lines.push(`*Generated by PerfGraph at ${report.meta.analyzedAt}*`);
180
+ return lines.join('\n');
181
+ }
182
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Remediation texts — lookup table of human-readable recommendations
3
+ * keyed by node ID or node type / rule ID patterns.
4
+ *
5
+ * Each entry is a plain-English suggestion for fixing the issue.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export interface RemediationContext {
10
+ /** Evidence payload (URLs, selector, lighthouse audit, metric) */
11
+ evidence?: {
12
+ urls?: string[];
13
+ selector?: string;
14
+ lighthouseAuditId?: string;
15
+ metric?: {
16
+ name: string;
17
+ value: number;
18
+ unit: string;
19
+ };
20
+ };
21
+ /** The issue's value/metric for context (e.g. TTFB=1200) */
22
+ value?: number;
23
+ /** Unit label for the value */
24
+ unit?: string;
25
+ /** Node type for fallback lookup (metric, bottleneck, impact) */
26
+ nodeType?: string;
27
+ /** Rule ID for fallback lookup by prefix */
28
+ ruleId?: string;
29
+ }
30
+ /**
31
+ * Get remediation text for an issue by its ID, with optional evidence context
32
+ * to produce parameterized, specific guidance.
33
+ *
34
+ * When `context` provides evidence (URLs, metric values), the returned text
35
+ * includes those details. Without context, falls back to static boilerplate
36
+ * then to rule-prefix and node-type fallbacks.
37
+ *
38
+ * @param issueId - The issue / node ID to remediate
39
+ * @param context - Optional evidence, values, and fallback hints
40
+ */
41
+ export declare function getRemediation(issueId: string, context?: RemediationContext): string;
42
+ //# sourceMappingURL=remediations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediations.d.ts","sourceRoot":"","sources":["../../src/report/remediations.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,MAAM,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KACxD,CAAC;IACF,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoID;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,kBAAkB,GAC3B,MAAM,CAsFR"}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Remediation texts — lookup table of human-readable recommendations
3
+ * keyed by node ID or node type / rule ID patterns.
4
+ *
5
+ * Each entry is a plain-English suggestion for fixing the issue.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ const REMEDIATIONS = {
10
+ // ---- LCP rules ----
11
+ 'high-ttfb': 'Optimise TTFB: use a CDN, enable server-side caching, ' +
12
+ 'move static assets to the edge, optimise server logic (fastify/compression). ' +
13
+ 'Target: TTFB < 800ms.',
14
+ 'delayed-html-parse': 'Ensure HTML is streamed without delay — enable chunked transfer encoding, ' +
15
+ 'remove blocking middleware on the server.',
16
+ 'delayed-css-discovery': 'Inline critical CSS in <head>, load non-critical CSS asynchronously ' +
17
+ 'via <link rel="preload" as="style" ...> + onload=this.rel="stylesheet".',
18
+ 'blocked-render': 'Eliminate render-blocking resources: inline critical CSS, async/defer for JS, ' +
19
+ 'preconnect to third-party origins.',
20
+ 'increased-lcp': 'Optimise LCP: ensure the LCP element loads early, use modern image formats ' +
21
+ '(WebP/AVIF) with correct dimensions, ' +
22
+ 'add fetchpriority="high" on the LCP image.',
23
+ 'rb-resources': 'Reduce the number of render-blocking resources: inline critical CSS, ' +
24
+ 'defer non-critical CSS via media="print" onload, use async/defer for scripts.',
25
+ 'blocked-render-rb': 'Analyse the render-blocking resource chain in DevTools (Performance → View: KPI Warning). ' +
26
+ 'Move non-critical CSS/JS off the critical path.',
27
+ 'increased-lcp-rb': 'Use Lighthouse "Eliminate render-blocking resources" for precise recommendations. ' +
28
+ 'Consider code splitting and lazy loading for non-critical scripts.',
29
+ 'lcp-resource-delay': 'Optimise LCP resource loading: use preload <link rel="preload"> for the LCP image, ' +
30
+ 'set fetchpriority="high", optimise the resource itself (compression, modern formats).',
31
+ 'increased-lcp-resource': 'Check that the LCP resource is not blocked by other loads. ' +
32
+ 'Use HTTP/2 Server Push (with caution) or early preload.',
33
+ // ---- Network rules ----
34
+ 'deep-critical-chain': 'Reduce critical chain depth: bundle scripts, use code splitting, ' +
35
+ 'lazy-load non-critical resources. A Webpack/Rollup bundle analyser helps find optimisations.',
36
+ 'waterfall-delay': 'Analyse the load waterfall in DevTools (Network → Waterfall). ' +
37
+ 'Eliminate sequential loads, use preload/preconnect ' +
38
+ 'for critical resources.',
39
+ 'slow-page-load': 'General slow page load: use Lighthouse to prioritise improvements. ' +
40
+ 'Focus on TTFB, render-blocking resources, image optimisation, and JS bundle size.',
41
+ 'excessive-requests': 'Reduce the number of requests on the critical path: bundle files, use ' +
42
+ 'sprites/SVG, HTTP/2 multiplexing, tree shaking, code splitting.',
43
+ 'bandwidth-contention': 'Reduce bandwidth contention: prioritise critical resources (preload), ' +
44
+ 'defer non-critical ones (lazy load, async/defer), use HTTP/2.',
45
+ // ---- JS rules ----
46
+ 'high-main-thread-blocking': 'Reduce main thread blocking: break up long tasks (<50ms), use ' +
47
+ 'Web Workers for background computation, remove heavy polyfills.',
48
+ 'high-tbt': 'Use Lighthouse "Reduce JavaScript execution time" for precise recommendations. ' +
49
+ 'Optimise heavy scripts, remove dead code (tree shaking).',
50
+ 'delayed-inp-tbt': 'INP may be high due to long tasks: break tasks into 50ms chunks with ' +
51
+ 'setTimeout(yield) or scheduler.postTask(). Use Browser Timeline to find culprits.',
52
+ 'js-hotspots': 'Profile JS hotspots in DevTools (Performance → Main thread). ' +
53
+ 'Optimise hot functions, use debounce/throttle for frequent handlers.',
54
+ 'long-tasks-js': 'Long tasks block the main thread and delay interaction: ' +
55
+ 'break into micro-tasks, use Web Workers, optimise rendering.',
56
+ 'delayed-inp-hotspots': 'Improve INP: use passive event listeners, eliminate scroll jank, ' +
57
+ 'optimise animations via requestAnimationFrame.',
58
+ 'many-scripts': 'Reduce the number of scripts: bundle modules, use code splitting, ' +
59
+ 'tree shaking, remove unused dependencies.',
60
+ 'long-parse-time': 'Long JS parse/compile time: use code splitting, lazy loading, ' +
61
+ 'remove unused code. Modern bundlers (esbuild/swc) reduce compilation time.',
62
+ // ---- Layout rules ----
63
+ 'layout-shifts': 'Fix layout shifts: set explicit dimensions (width/height) on images and iframes, ' +
64
+ 'use aspect-ratio CSS, reserve space for dynamic content.',
65
+ 'high-cls': 'Use Lighthouse "Avoid large layout shifts" for precise recommendations. ' +
66
+ 'Inline critical CSS, avoid inserting content above existing content (insertBefore).',
67
+ 'layout-shift-clusters': 'Shift clusters indicate dynamic content insertion problems: ' +
68
+ 'use CSS contain, reserve space, avoid DOM mutations above visible content.',
69
+ 'complex-dom-tree': 'DOM tree is too complex: reduce nesting, use simpler semantic ' +
70
+ 'markup, virtualise large lists (Virtual Scroller).',
71
+ 'layout-instability': 'Use CSS contain: layout to isolate each component. ' +
72
+ 'This limits layout recalculation scope on changes.',
73
+ };
74
+ // Fallback by node type
75
+ const TYPE_FALLBACKS = {
76
+ metric: 'Analyse this metric against your project baseline. ' +
77
+ 'Target compliance with Google Core Web Vitals.',
78
+ bottleneck: 'Eliminate this bottleneck: it may cascade into other metric regressions.',
79
+ impact: 'This metric indicates a negative impact on user experience. ' +
80
+ 'Fix the root causes listed in the dependency chain.',
81
+ };
82
+ // Fallback by rule ID prefix
83
+ const RULE_FALLBACKS = {
84
+ lcp: 'Check Lighthouse recommendations for Largest Contentful Paint improvements (Performance → LCP).',
85
+ net: 'Optimise network resource loading: reduce request count, ' +
86
+ 'use HTTP/2, preload critical resources.',
87
+ js: 'Optimise JavaScript: reduce bundle size, use code splitting, ' +
88
+ 'remove dead code, break up long tasks.',
89
+ layout: 'Stabilise the layout: set element dimensions, avoid unexpected ' +
90
+ 'content insertion, use CSS contain.',
91
+ };
92
+ // ---------------------------------------------------------------------------
93
+ // Public API
94
+ // ---------------------------------------------------------------------------
95
+ /**
96
+ * Get remediation text for an issue by its ID, with optional evidence context
97
+ * to produce parameterized, specific guidance.
98
+ *
99
+ * When `context` provides evidence (URLs, metric values), the returned text
100
+ * includes those details. Without context, falls back to static boilerplate
101
+ * then to rule-prefix and node-type fallbacks.
102
+ *
103
+ * @param issueId - The issue / node ID to remediate
104
+ * @param context - Optional evidence, values, and fallback hints
105
+ */
106
+ export function getRemediation(issueId, context) {
107
+ // ---- Parameterized remediations (evidence-aware) ----
108
+ if (context) {
109
+ // Render-blocking resources with specific URLs
110
+ if (issueId === 'rb-resources' && context.evidence?.urls && context.evidence.urls.length > 0) {
111
+ const urls = context.evidence.urls.join(', ');
112
+ return `Render-blocking resources: ${urls}. Consider inlining critical CSS, deferring non-critical stylesheets, and adding preload hints.`;
113
+ }
114
+ // TTFB with measured value
115
+ if (issueId === 'high-ttfb' && context.value != null) {
116
+ return `High TTFB (${context.value}ms). Optimize server response time: use CDN, enable caching, upgrade hosting, or move server closer to users.`;
117
+ }
118
+ // Deep critical chain with URLs
119
+ if (issueId === 'deep-critical-chain' && context.evidence?.urls && context.evidence.urls.length > 0) {
120
+ return `Deep critical chain (${context.value ?? '?'} levels): ${context.evidence.urls.join(' → ')}. Optimize dependency ordering and lazy-load non-critical resources.`;
121
+ }
122
+ // Layout shifts with CLS value
123
+ if (issueId === 'layout-shifts' && context.value != null) {
124
+ return `Layout shifts detected (CLS: ${context.value.toFixed(3)}). Ensure all elements have explicit dimensions, avoid inserting content above existing content.`;
125
+ }
126
+ // CLS with value
127
+ if (issueId === 'high-cls' && context.value != null) {
128
+ return `High CLS (${context.value.toFixed(3)}). Use Lighthouse "Avoid large layout shifts" for precise recommendations. Inline critical CSS, avoid inserting content above existing content (insertBefore).`;
129
+ }
130
+ // Main thread blocking with value
131
+ if (issueId === 'high-main-thread-blocking' && context.value != null) {
132
+ return `High main thread blocking (${context.value}ms). Break up long tasks, defer non-critical JavaScript, use web workers for heavy computation.`;
133
+ }
134
+ // Render-blocking chain with URLs
135
+ if (issueId === 'rb-chain' && context.evidence?.urls && context.evidence.urls.length > 0) {
136
+ const urls = context.evidence.urls.join(', ');
137
+ return `Render-blocking chain: ${urls}. Analyse the waterfall in DevTools (Performance → View: KPI Warning). Move unused CSS/JS off the critical path.`;
138
+ }
139
+ // Render-blocking LCP with URLs
140
+ if (issueId === 'render-blocking-lcp' && context.evidence?.urls && context.evidence.urls.length > 0) {
141
+ const urls = context.evidence.urls.join(', ');
142
+ return `Render-blocking resources delaying LCP: ${urls}. Use Lighthouse "Eliminate render-blocking resources" for precise recommendations. Consider code splitting and lazy loading for non-critical scripts.`;
143
+ }
144
+ // Increased LCP with value
145
+ if (issueId === 'increased-lcp' && context.value != null) {
146
+ return `LCP is high (${context.value}ms). Optimise the LCP element: ensure it loads early, use modern image formats (WebP/AVIF) with correct dimensions, add fetchpriority="high" on the LCP image.`;
147
+ }
148
+ // High TBT with value
149
+ if (issueId === 'high-tbt' && context.value != null) {
150
+ return `High Total Blocking Time (${context.value}ms). Use Lighthouse "Reduce JavaScript execution time" for precise recommendations. Optimise heavy scripts, remove dead code (tree shaking).`;
151
+ }
152
+ // Waterfall delay with URLs
153
+ if (issueId === 'waterfall-delay' && context.evidence?.urls && context.evidence.urls.length > 0) {
154
+ const urls = context.evidence.urls.join(', ');
155
+ return `Sequential waterfall detected: ${urls}. Analyse the Network waterfall in DevTools, use preload/preconnect for critical resources.`;
156
+ }
157
+ }
158
+ // ---- Static exact match ----
159
+ if (REMEDIATIONS[issueId]) {
160
+ return REMEDIATIONS[issueId];
161
+ }
162
+ // ---- Rule-based fallback ----
163
+ const ruleId = context?.ruleId;
164
+ if (ruleId) {
165
+ for (const [prefix, text] of Object.entries(RULE_FALLBACKS)) {
166
+ if (ruleId.startsWith(prefix)) {
167
+ return text;
168
+ }
169
+ }
170
+ }
171
+ // ---- Type-based fallback ----
172
+ const nodeType = context?.nodeType;
173
+ if (nodeType && TYPE_FALLBACKS[nodeType]) {
174
+ return TYPE_FALLBACKS[nodeType];
175
+ }
176
+ return 'Diagnose the issue with Chrome DevTools (Performance → Measure → Reload) ' +
177
+ 'and follow Lighthouse recommendations.';
178
+ }
179
+ //# sourceMappingURL=remediations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediations.js","sourceRoot":"","sources":["../../src/report/remediations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Report scoring — compute overall performance score from CausalGraph.
3
+ *
4
+ * The score is a simple heuristic based on severity distribution:
5
+ * - Any critical nodes → "poor"
6
+ * - Any warning nodes → "moderate"
7
+ * - Info only / empty → "good"
8
+ *
9
+ * Optionally accepts a Lighthouse performance score to override the
10
+ * heuristic when Lighthouse indicates acceptable performance despite
11
+ * causal-rule triggers (e.g., 2 small render-blocking stylesheets).
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ import type { CausalGraph } from '../causal/types.js';
16
+ import type { ReportScore } from './types.js';
17
+ /**
18
+ * Compute overall performance score from a CausalGraph.
19
+ *
20
+ * When `lighthousePerformance` is provided the score may be promoted:
21
+ * - Lighthouse >= 0.9 and no genuine regression → "good"
22
+ * - Lighthouse >= 0.7, criticalCount <= 1, no genuine regression → "moderate"
23
+ * - Otherwise the heuristic score is returned unchanged.
24
+ *
25
+ * @param graph - The causal graph to evaluate
26
+ * @param lighthousePerformance - Optional Lighthouse performance score (0–1)
27
+ * @returns A string score when called without lighthouse data; otherwise
28
+ * either a string or an object with `score` and optional `explanation`.
29
+ */
30
+ export declare function computeScore(graph: CausalGraph): ReportScore;
31
+ export declare function computeScore(graph: CausalGraph, lighthousePerformance?: number): ReportScore | {
32
+ score: ReportScore;
33
+ explanation?: string;
34
+ };
35
+ //# sourceMappingURL=scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../../src/report/scorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2B9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAAC;AAC9D,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,EAClB,qBAAqB,CAAC,EAAE,MAAM,GAC7B,WAAW,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Report scoring — compute overall performance score from CausalGraph.
3
+ *
4
+ * The score is a simple heuristic based on severity distribution:
5
+ * - Any critical nodes → "poor"
6
+ * - Any warning nodes → "moderate"
7
+ * - Info only / empty → "good"
8
+ *
9
+ * Optionally accepts a Lighthouse performance score to override the
10
+ * heuristic when Lighthouse indicates acceptable performance despite
11
+ * causal-rule triggers (e.g., 2 small render-blocking stylesheets).
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /**
16
+ * Check whether a node represents a genuinely bad performance regression,
17
+ * as opposed to a rule-triggered flag. Used to decide whether Lighthouse
18
+ * data should override the heuristic score.
19
+ *
20
+ * A genuine regression is:
21
+ * - Any node (metric or impact) with a value > 4000 (e.g. LCP > 4 s)
22
+ * - Any ms-valued node with a value > 2500 (e.g. TTFB > 2.5 s)
23
+ */
24
+ function isGenuineRegression(node) {
25
+ if (node.value == null)
26
+ return false;
27
+ // Any value above 4000 is a clear regression regardless of semantics
28
+ if (node.value > 4000)
29
+ return true;
30
+ // ms-valued metrics above 2500 are "poor" by Google thresholds
31
+ if (node.unit === 'ms' && node.value > 2500)
32
+ return true;
33
+ return false;
34
+ }
35
+ function hasGenuineRegression(nodes) {
36
+ return nodes.some(isGenuineRegression);
37
+ }
38
+ export function computeScore(graph, lighthousePerformance) {
39
+ let criticalCount = 0;
40
+ let warningCount = 0;
41
+ for (const node of graph.nodes) {
42
+ if (node.severity === 'critical') {
43
+ criticalCount++;
44
+ }
45
+ if (node.severity === 'warning') {
46
+ warningCount++;
47
+ }
48
+ }
49
+ // When Lighthouse data is available, consider overriding the heuristic
50
+ if (lighthousePerformance !== undefined) {
51
+ const genuineRegression = hasGenuineRegression(graph.nodes);
52
+ if (lighthousePerformance >= 0.9 && !genuineRegression) {
53
+ return {
54
+ score: 'good',
55
+ explanation: 'Lighthouse performance >= 0.9, no genuine regressions detected',
56
+ };
57
+ }
58
+ if (lighthousePerformance >= 0.7 && criticalCount <= 1 && !genuineRegression) {
59
+ return {
60
+ score: 'moderate',
61
+ explanation: 'Lighthouse performance >= 0.7, minimal critical issues, no genuine regressions',
62
+ };
63
+ }
64
+ }
65
+ // Fallback heuristic (unchanged from original)
66
+ if (criticalCount > 0)
67
+ return 'poor';
68
+ if (warningCount > 0)
69
+ return 'moderate';
70
+ return 'good';
71
+ }
72
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/report/scorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,IAAgB;IAC3C,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IAErC,qEAAqE;IACrE,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IAEnC,+DAA+D;IAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IAEzD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmB;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACzC,CAAC;AAoBD,MAAM,UAAU,YAAY,CAC1B,KAAkB,EAClB,qBAA8B;IAE9B,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACjC,aAAa,EAAE,CAAC;QAClB,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,IAAI,qBAAqB,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAE5D,IAAI,qBAAqB,IAAI,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvD,OAAO;gBACL,KAAK,EAAE,MAAM;gBACb,WAAW,EACT,gEAAgE;aACnE,CAAC;QACJ,CAAC;QAED,IAAI,qBAAqB,IAAI,GAAG,IAAI,aAAa,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC7E,OAAO;gBACL,KAAK,EAAE,UAAU;gBACjB,WAAW,EACT,gFAAgF;aACnF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,IAAI,aAAa,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IACrC,IAAI,YAAY,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC"}