@paulirish/trace_engine 0.0.53 → 0.0.55

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 (241) hide show
  1. package/.tmp/tsbuildinfo/analyze-inspector-issues.d.mts +13 -0
  2. package/.tmp/tsbuildinfo/analyze-inspector-issues.d.mts.map +1 -0
  3. package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
  4. package/analyze-inspector-issues.mjs +60 -0
  5. package/core/common/common.d.ts +1 -0
  6. package/core/common/common.js +1 -0
  7. package/core/host/host.d.ts +1 -0
  8. package/core/host/host.js +1 -0
  9. package/core/platform/MimeType.d.ts +3 -2
  10. package/core/platform/MimeType.js +4 -3
  11. package/core/platform/MimeType.js.map +1 -1
  12. package/core/root/root.d.ts +1 -0
  13. package/core/root/root.js +1 -0
  14. package/core/sdk/sdk.d.ts +1 -0
  15. package/core/sdk/sdk.js +1 -0
  16. package/generated/protocol.d.ts +115 -16
  17. package/locales/af.json +52 -10
  18. package/locales/am.json +52 -10
  19. package/locales/ar.json +51 -9
  20. package/locales/as.json +52 -10
  21. package/locales/az.json +52 -10
  22. package/locales/be.json +52 -10
  23. package/locales/bg.json +52 -10
  24. package/locales/bn.json +52 -10
  25. package/locales/bs.json +52 -10
  26. package/locales/ca.json +52 -10
  27. package/locales/cs.json +52 -10
  28. package/locales/cy.json +52 -10
  29. package/locales/da.json +52 -10
  30. package/locales/de.json +52 -10
  31. package/locales/el.json +52 -10
  32. package/locales/en-GB.json +52 -10
  33. package/locales/en-US.json +12 -12
  34. package/locales/en-XL.json +12 -12
  35. package/locales/es-419.json +52 -10
  36. package/locales/es.json +50 -8
  37. package/locales/et.json +52 -10
  38. package/locales/eu.json +52 -10
  39. package/locales/fa.json +51 -9
  40. package/locales/fi.json +52 -10
  41. package/locales/fil.json +52 -10
  42. package/locales/fr-CA.json +52 -10
  43. package/locales/fr.json +52 -10
  44. package/locales/gl.json +52 -10
  45. package/locales/gu.json +52 -10
  46. package/locales/he.json +52 -10
  47. package/locales/hi.json +52 -10
  48. package/locales/hr.json +52 -10
  49. package/locales/hu.json +51 -9
  50. package/locales/hy.json +51 -9
  51. package/locales/id.json +52 -10
  52. package/locales/is.json +53 -11
  53. package/locales/it.json +51 -9
  54. package/locales/ja.json +52 -10
  55. package/locales/ka.json +53 -11
  56. package/locales/kk.json +51 -9
  57. package/locales/km.json +52 -10
  58. package/locales/kn.json +52 -10
  59. package/locales/ko.json +52 -10
  60. package/locales/ky.json +51 -9
  61. package/locales/lo.json +52 -10
  62. package/locales/lt.json +52 -10
  63. package/locales/lv.json +51 -9
  64. package/locales/mk.json +52 -10
  65. package/locales/ml.json +53 -11
  66. package/locales/mn.json +52 -10
  67. package/locales/mr.json +52 -10
  68. package/locales/ms.json +52 -10
  69. package/locales/my.json +51 -9
  70. package/locales/ne.json +52 -10
  71. package/locales/nl.json +52 -10
  72. package/locales/no.json +52 -10
  73. package/locales/or.json +53 -11
  74. package/locales/pa.json +53 -11
  75. package/locales/pl.json +51 -9
  76. package/locales/pt-PT.json +52 -10
  77. package/locales/pt.json +52 -10
  78. package/locales/ro.json +52 -10
  79. package/locales/ru.json +53 -11
  80. package/locales/si.json +52 -10
  81. package/locales/sk.json +51 -9
  82. package/locales/sl.json +51 -9
  83. package/locales/sq.json +52 -10
  84. package/locales/sr-Latn.json +52 -10
  85. package/locales/sr.json +52 -10
  86. package/locales/sv.json +52 -10
  87. package/locales/sw.json +51 -9
  88. package/locales/ta.json +52 -10
  89. package/locales/te.json +52 -10
  90. package/locales/th.json +51 -9
  91. package/locales/tr.json +52 -10
  92. package/locales/uk.json +52 -10
  93. package/locales/ur.json +52 -10
  94. package/locales/uz.json +51 -9
  95. package/locales/vi.json +52 -10
  96. package/locales/zh-HK.json +52 -10
  97. package/locales/zh-TW.json +51 -9
  98. package/locales/zh.json +52 -10
  99. package/locales/zu.json +52 -10
  100. package/models/cpu_profile/CPUProfileDataModel.d.ts +4 -2
  101. package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
  102. package/models/cpu_profile/ProfileTreeModel.d.ts +0 -1
  103. package/models/cpu_profile/ProfileTreeModel.js +0 -2
  104. package/models/cpu_profile/ProfileTreeModel.js.map +1 -1
  105. package/models/issues_manager/CheckFormsIssuesTrigger.d.ts +1 -0
  106. package/models/issues_manager/CheckFormsIssuesTrigger.js +1 -0
  107. package/models/issues_manager/ContrastCheckTrigger.d.ts +1 -0
  108. package/models/issues_manager/ContrastCheckTrigger.js +1 -0
  109. package/models/issues_manager/DeprecationIssue.d.ts +1 -0
  110. package/models/issues_manager/DeprecationIssue.js +1 -0
  111. package/models/issues_manager/IssueResolver.d.ts +1 -0
  112. package/models/issues_manager/IssueResolver.js +1 -0
  113. package/models/issues_manager/RelatedIssue.d.ts +1 -0
  114. package/models/issues_manager/RelatedIssue.js +1 -0
  115. package/models/issues_manager/SourceFrameIssuesManager.d.ts +1 -0
  116. package/models/issues_manager/SourceFrameIssuesManager.js +1 -0
  117. package/models/trace/LanternComputationData.js +9 -8
  118. package/models/trace/LanternComputationData.js.map +1 -1
  119. package/models/trace/ModelImpl.js +1 -1
  120. package/models/trace/ModelImpl.js.map +1 -1
  121. package/models/trace/Processor.js +23 -16
  122. package/models/trace/Processor.js.map +1 -1
  123. package/models/trace/extras/ThirdParties.js +1 -1
  124. package/models/trace/extras/ThirdParties.js.map +1 -1
  125. package/models/trace/extras/TraceFilter.js +2 -2
  126. package/models/trace/extras/TraceFilter.js.map +1 -1
  127. package/models/trace/extras/extras-tsconfig.json +0 -2
  128. package/models/trace/extras/extras.d.ts +4 -1
  129. package/models/trace/extras/extras.js +4 -1
  130. package/models/trace/extras/extras.js.map +1 -1
  131. package/models/trace/handlers/AuctionWorkletsHandler.js +5 -5
  132. package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
  133. package/models/trace/handlers/ExtensionTraceDataHandler.js +4 -4
  134. package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
  135. package/models/trace/handlers/FlowsHandler.js +3 -3
  136. package/models/trace/handlers/FlowsHandler.js.map +1 -1
  137. package/models/trace/handlers/FramesHandler.js +7 -7
  138. package/models/trace/handlers/FramesHandler.js.map +1 -1
  139. package/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  140. package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
  141. package/models/trace/handlers/LayoutShiftsHandler.d.ts +1 -1
  142. package/models/trace/handlers/LayoutShiftsHandler.js +18 -10
  143. package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
  144. package/models/trace/handlers/MetaHandler.js +9 -7
  145. package/models/trace/handlers/MetaHandler.js.map +1 -1
  146. package/models/trace/handlers/NetworkRequestsHandler.d.ts +0 -5
  147. package/models/trace/handlers/NetworkRequestsHandler.js +3 -22
  148. package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
  149. package/models/trace/handlers/PageLoadMetricsHandler.d.ts +2 -2
  150. package/models/trace/handlers/PageLoadMetricsHandler.js +54 -25
  151. package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
  152. package/models/trace/handlers/RendererHandler.js +1 -1
  153. package/models/trace/handlers/RendererHandler.js.map +1 -1
  154. package/models/trace/handlers/SamplesHandler.js +7 -2
  155. package/models/trace/handlers/SamplesHandler.js.map +1 -1
  156. package/models/trace/handlers/ScriptsHandler.js.map +1 -1
  157. package/models/trace/handlers/Threads.d.ts +1 -1
  158. package/models/trace/handlers/Threads.js +17 -7
  159. package/models/trace/handlers/Threads.js.map +1 -1
  160. package/models/trace/handlers/UserInteractionsHandler.js +4 -3
  161. package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
  162. package/models/trace/handlers/WarningsHandler.js +2 -2
  163. package/models/trace/handlers/WarningsHandler.js.map +1 -1
  164. package/models/trace/helpers/SamplesIntegrator.d.ts +1 -1
  165. package/models/trace/helpers/SamplesIntegrator.js +23 -21
  166. package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
  167. package/models/trace/helpers/Trace.js +111 -118
  168. package/models/trace/helpers/Trace.js.map +1 -1
  169. package/models/trace/insights/CLSCulprits.d.ts +25 -5
  170. package/models/trace/insights/CLSCulprits.js +73 -33
  171. package/models/trace/insights/CLSCulprits.js.map +1 -1
  172. package/models/trace/insights/Common.js +4 -3
  173. package/models/trace/insights/Common.js.map +1 -1
  174. package/models/trace/insights/DOMSize.js +3 -3
  175. package/models/trace/insights/DOMSize.js.map +1 -1
  176. package/models/trace/insights/DocumentLatency.d.ts +2 -2
  177. package/models/trace/insights/DocumentLatency.js +4 -4
  178. package/models/trace/insights/DocumentLatency.js.map +1 -1
  179. package/models/trace/insights/DuplicatedJavaScript.js +2 -2
  180. package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
  181. package/models/trace/insights/FontDisplay.js +2 -2
  182. package/models/trace/insights/FontDisplay.js.map +1 -1
  183. package/models/trace/insights/ForcedReflow.js +2 -2
  184. package/models/trace/insights/ForcedReflow.js.map +1 -1
  185. package/models/trace/insights/ImageDelivery.js +2 -2
  186. package/models/trace/insights/ImageDelivery.js.map +1 -1
  187. package/models/trace/insights/InteractionToNextPaint.js +3 -3
  188. package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
  189. package/models/trace/insights/LCPDiscovery.js +3 -3
  190. package/models/trace/insights/LCPDiscovery.js.map +1 -1
  191. package/models/trace/insights/LCPPhases.js +3 -3
  192. package/models/trace/insights/LCPPhases.js.map +1 -1
  193. package/models/trace/insights/LegacyJavaScript.js +2 -2
  194. package/models/trace/insights/LegacyJavaScript.js.map +1 -1
  195. package/models/trace/insights/ModernHTTP.js +2 -2
  196. package/models/trace/insights/ModernHTTP.js.map +1 -1
  197. package/models/trace/insights/NetworkDependencyTree.d.ts +31 -5
  198. package/models/trace/insights/NetworkDependencyTree.js +137 -12
  199. package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
  200. package/models/trace/insights/RenderBlocking.js +3 -3
  201. package/models/trace/insights/RenderBlocking.js.map +1 -1
  202. package/models/trace/insights/SlowCSSSelector.js +2 -2
  203. package/models/trace/insights/SlowCSSSelector.js.map +1 -1
  204. package/models/trace/insights/ThirdParties.js +2 -2
  205. package/models/trace/insights/ThirdParties.js.map +1 -1
  206. package/models/trace/insights/Viewport.d.ts +8 -2
  207. package/models/trace/insights/Viewport.js +18 -3
  208. package/models/trace/insights/Viewport.js.map +1 -1
  209. package/models/trace/insights/types.d.ts +1 -1
  210. package/models/trace/insights/types.js +19 -0
  211. package/models/trace/insights/types.js.map +1 -1
  212. package/models/trace/lantern/graph/BaseNode.d.ts +5 -2
  213. package/models/trace/lantern/graph/BaseNode.js +8 -5
  214. package/models/trace/lantern/graph/BaseNode.js.map +1 -1
  215. package/models/trace/lantern/graph/PageDependencyGraph.js +46 -3
  216. package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
  217. package/models/trace/lantern/simulation/Simulator.js +1 -1
  218. package/models/trace/lantern/simulation/Simulator.js.map +1 -1
  219. package/models/trace/trace-tsconfig.json +0 -1
  220. package/models/trace/trace.d.ts +1 -2
  221. package/models/trace/trace.js +1 -2
  222. package/models/trace/trace.js.map +1 -1
  223. package/models/trace/types/Extensions.d.ts +6 -1
  224. package/models/trace/types/Extensions.js.map +1 -1
  225. package/models/trace/types/File.d.ts +18 -4
  226. package/models/trace/types/File.js +28 -4
  227. package/models/trace/types/File.js.map +1 -1
  228. package/models/trace/types/TraceEvents.d.ts +13 -10
  229. package/models/trace/types/TraceEvents.js +377 -108
  230. package/models/trace/types/TraceEvents.js.map +1 -1
  231. package/package.json +1 -1
  232. package/test/test-trace-engine.mjs +77 -0
  233. package/third_party/marked/marked.d.ts +1 -0
  234. package/third_party/marked/marked.js +1 -0
  235. package/models/trace/TracingManager.js.map +0 -1
  236. package/models/trace/extras/FetchNodes.d.ts +0 -61
  237. package/models/trace/extras/FetchNodes.js +0 -214
  238. package/models/trace/extras/FetchNodes.js.map +0 -1
  239. package/models/trace/extras/Metadata.d.ts +0 -3
  240. package/models/trace/extras/Metadata.js +0 -71
  241. package/models/trace/extras/Metadata.js.map +0 -1
@@ -6,7 +6,7 @@ import * as Platform from '../../../core/platform/platform.js';
6
6
  import * as Handlers from '../handlers/handlers.js';
7
7
  import * as Helpers from '../helpers/helpers.js';
8
8
  import * as Types from '../types/types.js';
9
- import { InsightCategory, } from './types.js';
9
+ import { InsightCategory, InsightKeys, } from './types.js';
10
10
  export const UIStrings = {
11
11
  /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits ("reasons"). */
12
12
  title: 'Layout shift culprits',
@@ -45,9 +45,9 @@ export const UIStrings = {
45
45
  */
46
46
  animation: 'Animation',
47
47
  /**
48
- * @description Text for a culprit type of Unsized images.
48
+ * @description Text for a culprit type of Unsized image.
49
49
  */
50
- unsizedImages: 'Unsized Images',
50
+ unsizedImage: 'Unsized image element',
51
51
  /**
52
52
  * @description Text status when there were no layout shifts detected.
53
53
  */
@@ -59,6 +59,34 @@ export const UIStrings = {
59
59
  };
60
60
  // const str_ = i18n.i18n.registerUIStrings('models/trace/insights/CLSCulprits.ts', UIStrings);
61
61
  export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.getLocalizedString.bind(undefined, str_);
62
+ export var AnimationFailureReasons;
63
+ (function (AnimationFailureReasons) {
64
+ AnimationFailureReasons["ACCELERATED_ANIMATIONS_DISABLED"] = "ACCELERATED_ANIMATIONS_DISABLED";
65
+ AnimationFailureReasons["EFFECT_SUPPRESSED_BY_DEVTOOLS"] = "EFFECT_SUPPRESSED_BY_DEVTOOLS";
66
+ AnimationFailureReasons["INVALID_ANIMATION_OR_EFFECT"] = "INVALID_ANIMATION_OR_EFFECT";
67
+ AnimationFailureReasons["EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS"] = "EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS";
68
+ AnimationFailureReasons["EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE"] = "EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE";
69
+ AnimationFailureReasons["TARGET_HAS_INVALID_COMPOSITING_STATE"] = "TARGET_HAS_INVALID_COMPOSITING_STATE";
70
+ AnimationFailureReasons["TARGET_HAS_INCOMPATIBLE_ANIMATIONS"] = "TARGET_HAS_INCOMPATIBLE_ANIMATIONS";
71
+ AnimationFailureReasons["TARGET_HAS_CSS_OFFSET"] = "TARGET_HAS_CSS_OFFSET";
72
+ AnimationFailureReasons["ANIMATION_AFFECTS_NON_CSS_PROPERTIES"] = "ANIMATION_AFFECTS_NON_CSS_PROPERTIES";
73
+ AnimationFailureReasons["TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET"] = "TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET";
74
+ AnimationFailureReasons["TRANSFROM_BOX_SIZE_DEPENDENT"] = "TRANSFROM_BOX_SIZE_DEPENDENT";
75
+ AnimationFailureReasons["FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS"] = "FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS";
76
+ AnimationFailureReasons["UNSUPPORTED_CSS_PROPERTY"] = "UNSUPPORTED_CSS_PROPERTY";
77
+ AnimationFailureReasons["MIXED_KEYFRAME_VALUE_TYPES"] = "MIXED_KEYFRAME_VALUE_TYPES";
78
+ AnimationFailureReasons["TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE"] = "TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE";
79
+ AnimationFailureReasons["ANIMATION_HAS_NO_VISIBLE_CHANGE"] = "ANIMATION_HAS_NO_VISIBLE_CHANGE";
80
+ AnimationFailureReasons["AFFECTS_IMPORTANT_PROPERTY"] = "AFFECTS_IMPORTANT_PROPERTY";
81
+ AnimationFailureReasons["SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY"] = "SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY";
82
+ })(AnimationFailureReasons || (AnimationFailureReasons = {}));
83
+ export var LayoutShiftType;
84
+ (function (LayoutShiftType) {
85
+ LayoutShiftType[LayoutShiftType["FONT_REQUESTS"] = 0] = "FONT_REQUESTS";
86
+ LayoutShiftType[LayoutShiftType["IFRAMES"] = 1] = "IFRAMES";
87
+ LayoutShiftType[LayoutShiftType["ANIMATIONS"] = 2] = "ANIMATIONS";
88
+ LayoutShiftType[LayoutShiftType["UNSIZED_IMAGE"] = 3] = "UNSIZED_IMAGE";
89
+ })(LayoutShiftType || (LayoutShiftType = {}));
62
90
  /**
63
91
  * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define
64
92
  * which bit corresponds to each failure reason.
@@ -67,77 +95,77 @@ export const i18nString = (i18nId, values) => ({i18nId, values}); // i18n.i18n.g
67
95
  const ACTIONABLE_FAILURE_REASONS = [
68
96
  {
69
97
  flag: 1 << 0,
70
- failure: "ACCELERATED_ANIMATIONS_DISABLED" /* AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED */,
98
+ failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED,
71
99
  },
72
100
  {
73
101
  flag: 1 << 1,
74
- failure: "EFFECT_SUPPRESSED_BY_DEVTOOLS" /* AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS */,
102
+ failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS,
75
103
  },
76
104
  {
77
105
  flag: 1 << 2,
78
- failure: "INVALID_ANIMATION_OR_EFFECT" /* AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT */,
106
+ failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT,
79
107
  },
80
108
  {
81
109
  flag: 1 << 3,
82
- failure: "EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS" /* AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS */,
110
+ failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS,
83
111
  },
84
112
  {
85
113
  flag: 1 << 4,
86
- failure: "EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE" /* AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE */,
114
+ failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE,
87
115
  },
88
116
  {
89
117
  flag: 1 << 5,
90
- failure: "TARGET_HAS_INVALID_COMPOSITING_STATE" /* AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE */,
118
+ failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE,
91
119
  },
92
120
  {
93
121
  flag: 1 << 6,
94
- failure: "TARGET_HAS_INCOMPATIBLE_ANIMATIONS" /* AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS */,
122
+ failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS,
95
123
  },
96
124
  {
97
125
  flag: 1 << 7,
98
- failure: "TARGET_HAS_CSS_OFFSET" /* AnimationFailureReasons.TARGET_HAS_CSS_OFFSET */,
126
+ failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET,
99
127
  },
100
128
  // The failure 1 << 8 is marked as obsolete in Blink
101
129
  {
102
130
  flag: 1 << 9,
103
- failure: "ANIMATION_AFFECTS_NON_CSS_PROPERTIES" /* AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES */,
131
+ failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES,
104
132
  },
105
133
  {
106
134
  flag: 1 << 10,
107
- failure: "TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET" /* AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET */,
135
+ failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET,
108
136
  },
109
137
  {
110
138
  flag: 1 << 11,
111
- failure: "TRANSFROM_BOX_SIZE_DEPENDENT" /* AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT */,
139
+ failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,
112
140
  },
113
141
  {
114
142
  flag: 1 << 12,
115
- failure: "FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS" /* AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS */,
143
+ failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS,
116
144
  },
117
145
  {
118
146
  flag: 1 << 13,
119
- failure: "UNSUPPORTED_CSS_PROPERTY" /* AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY */,
147
+ failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,
120
148
  },
121
149
  // The failure 1 << 14 is marked as obsolete in Blink
122
150
  {
123
151
  flag: 1 << 15,
124
- failure: "MIXED_KEYFRAME_VALUE_TYPES" /* AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES */,
152
+ failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES,
125
153
  },
126
154
  {
127
155
  flag: 1 << 16,
128
- failure: "TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE" /* AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE */,
156
+ failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE,
129
157
  },
130
158
  {
131
159
  flag: 1 << 17,
132
- failure: "ANIMATION_HAS_NO_VISIBLE_CHANGE" /* AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE */,
160
+ failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE,
133
161
  },
134
162
  {
135
163
  flag: 1 << 18,
136
- failure: "AFFECTS_IMPORTANT_PROPERTY" /* AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY */,
164
+ failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY,
137
165
  },
138
166
  {
139
167
  flag: 1 << 19,
140
- failure: "SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY" /* AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY */,
168
+ failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY,
141
169
  },
142
170
  ];
143
171
  // 500ms window.
@@ -256,7 +284,7 @@ function getNextEvent(sourceEvents, targetEvent) {
256
284
  * An Iframe is considered a root cause if the iframe event occurs before a prePaint event
257
285
  * and within this prePaint event a layout shift(s) occurs.
258
286
  */
259
- function getIframeRootCauses(iframeCreatedEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents) {
287
+ function getIframeRootCauses(parsedTrace, iframeCreatedEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents) {
260
288
  for (const iframeEvent of iframeCreatedEvents) {
261
289
  const nextPrePaint = getNextEvent(prePaintEvents, iframeEvent);
262
290
  // If no following prePaint, this is not a root cause.
@@ -280,7 +308,13 @@ function getIframeRootCauses(iframeCreatedEvents, prePaintEvents, shiftsByPrePai
280
308
  return e.ts >= iframeEvent.ts && e.ts <= maxIframe;
281
309
  });
282
310
  if (domEvent?.args.frame) {
283
- rootCausesForShift.iframeIds.push(domEvent.args.frame);
311
+ const frame = domEvent.args.frame;
312
+ let url;
313
+ const processes = parsedTrace.Meta.rendererProcessesByFrame.get(frame);
314
+ if (processes && processes.size > 0) {
315
+ url = [...processes.values()][0]?.[0].frame.url;
316
+ }
317
+ rootCausesForShift.iframes.push({ frame, url });
284
318
  }
285
319
  }
286
320
  }
@@ -320,7 +354,7 @@ function getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsB
320
354
  return rootCausesByShift;
321
355
  }
322
356
  export function isCLSCulprits(insight) {
323
- return insight.insightKey === "CLSCulprits" /* InsightKeys.CLS_CULPRITS */;
357
+ return insight.insightKey === InsightKeys.CLS_CULPRITS;
324
358
  }
325
359
  /**
326
360
  * A font request is considered a root cause if the request occurs before a prePaint event
@@ -368,20 +402,26 @@ function getTopCulprits(cluster, culpritsByShift) {
368
402
  continue;
369
403
  }
370
404
  const fontReq = culprits.fontRequests;
371
- const iframes = culprits.iframeIds;
405
+ const iframes = culprits.iframes;
372
406
  const animations = culprits.nonCompositedAnimations;
373
407
  const unsizedImages = culprits.unsizedImages;
374
408
  for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {
375
- causes.push(i18nString(UIStrings.fontRequest));
409
+ causes.push({ type: LayoutShiftType.FONT_REQUESTS, description: i18nString(UIStrings.fontRequest) });
376
410
  }
377
411
  for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {
378
- causes.push(i18nString(UIStrings.injectedIframe));
412
+ causes.push({ type: LayoutShiftType.IFRAMES, description: i18nString(UIStrings.injectedIframe) });
379
413
  }
380
414
  for (let i = 0; i < animations.length && causes.length < MAX_TOP_CULPRITS; i++) {
381
- causes.push(i18nString(UIStrings.animation));
415
+ causes.push({ type: LayoutShiftType.ANIMATIONS, description: i18nString(UIStrings.animation) });
382
416
  }
383
417
  for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {
384
- causes.push(i18nString(UIStrings.unsizedImages));
418
+ causes.push({
419
+ type: LayoutShiftType.UNSIZED_IMAGE,
420
+ description: i18nString(UIStrings.unsizedImage),
421
+ url: unsizedImages[i].paintImageEvent.args.data.url || '',
422
+ backendNodeId: unsizedImages[i].backendNodeId,
423
+ frame: unsizedImages[i].paintImageEvent.args.data.frame || '',
424
+ });
385
425
  }
386
426
  if (causes.length >= MAX_TOP_CULPRITS) {
387
427
  break;
@@ -393,7 +433,7 @@ function finalize(partialModel) {
393
433
  let state = 'pass';
394
434
  if (partialModel.worstCluster) {
395
435
  const classification = Handlers.ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(partialModel.worstCluster.clusterCumulativeScore);
396
- if (classification === "good" /* Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD */) {
436
+ if (classification === Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD) {
397
437
  state = 'informative';
398
438
  }
399
439
  else {
@@ -401,7 +441,7 @@ function finalize(partialModel) {
401
441
  }
402
442
  }
403
443
  return {
404
- insightKey: "CLSCulprits" /* InsightKeys.CLS_CULPRITS */,
444
+ insightKey: InsightKeys.CLS_CULPRITS,
405
445
  strings: UIStrings,
406
446
  title: i18nString(UIStrings.title),
407
447
  description: i18nString(UIStrings.description),
@@ -428,10 +468,10 @@ export function generateInsight(parsedTrace, context) {
428
468
  const rootCausesByShift = new Map();
429
469
  const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);
430
470
  for (const shift of layoutShifts) {
431
- rootCausesByShift.set(shift, { iframeIds: [], fontRequests: [], nonCompositedAnimations: [], unsizedImages: [] });
471
+ rootCausesByShift.set(shift, { iframes: [], fontRequests: [], nonCompositedAnimations: [], unsizedImages: [] });
432
472
  }
433
473
  // Populate root causes for rootCausesByShift.
434
- getIframeRootCauses(iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);
474
+ getIframeRootCauses(parsedTrace, iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);
435
475
  getFontRootCauses(networkRequests, prePaintEvents, shiftsByPrePaint, rootCausesByShift);
436
476
  getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsByPrePaint, rootCausesByShift);
437
477
  const animationFailures = getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift);
@@ -1 +1 @@
1
- {"version":3,"file":"CLSCulprits.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/CLSCulprits.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits (\"reasons\"). */\n title: 'Layout shift culprits',\n /**\n * @description Description of a DevTools insight that identifies the reasons that elements shift on the page.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description:\n 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://web.dev/articles/optimize-cls), such as elements being added, removed, or their fonts changing as the page loads.',\n /**\n *@description Text indicating the worst layout shift cluster.\n */\n worstLayoutShiftCluster: 'Worst layout shift cluster',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstCluster: 'Worst cluster',\n /**\n * @description Text indicating a layout shift cluster and its start time.\n * @example {32 ms} PH1\n */\n layoutShiftCluster: 'Layout shift cluster @ {PH1}',\n /**\n *@description Text indicating the biggest reasons for the layout shifts.\n */\n topCulprits: 'Top layout shift culprits',\n /**\n * @description Text for a culprit type of Injected iframe.\n */\n injectedIframe: 'Injected iframe',\n /**\n * @description Text for a culprit type of Font request.\n */\n fontRequest: 'Font request',\n /**\n * @description Text for a culprit type of Animation.\n */\n animation: 'Animation',\n /**\n * @description Text for a culprit type of Unsized images.\n */\n unsizedImages: 'Unsized Images',\n /**\n * @description Text status when there were no layout shifts detected.\n */\n noLayoutShifts: 'No layout shifts',\n /**\n * @description Text status when there no layout shifts culprits/root causes were found.\n */\n noCulprits: 'Could not detect any layout shift culprits',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/CLSCulprits.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CLSCulpritsInsightModel = InsightModel<typeof UIStrings, {\n animationFailures: readonly NoncompositedAnimationFailure[],\n shifts: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n clusters: Types.Events.SyntheticLayoutShiftCluster[],\n worstCluster: Types.Events.SyntheticLayoutShiftCluster | undefined,\n /** The top 3 shift root causes for each cluster. */\n topCulpritsByCluster: Map<Types.Events.SyntheticLayoutShiftCluster, Platform.UIString.LocalizedString[]>,\n}>;\n\nexport const enum AnimationFailureReasons {\n ACCELERATED_ANIMATIONS_DISABLED = 'ACCELERATED_ANIMATIONS_DISABLED',\n EFFECT_SUPPRESSED_BY_DEVTOOLS = 'EFFECT_SUPPRESSED_BY_DEVTOOLS',\n INVALID_ANIMATION_OR_EFFECT = 'INVALID_ANIMATION_OR_EFFECT',\n EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS = 'EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS',\n EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE = 'EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE',\n TARGET_HAS_INVALID_COMPOSITING_STATE = 'TARGET_HAS_INVALID_COMPOSITING_STATE',\n TARGET_HAS_INCOMPATIBLE_ANIMATIONS = 'TARGET_HAS_INCOMPATIBLE_ANIMATIONS',\n TARGET_HAS_CSS_OFFSET = 'TARGET_HAS_CSS_OFFSET',\n ANIMATION_AFFECTS_NON_CSS_PROPERTIES = 'ANIMATION_AFFECTS_NON_CSS_PROPERTIES',\n TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET =\n 'TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET',\n TRANSFROM_BOX_SIZE_DEPENDENT = 'TRANSFROM_BOX_SIZE_DEPENDENT',\n FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS = 'FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS',\n UNSUPPORTED_CSS_PROPERTY = 'UNSUPPORTED_CSS_PROPERTY',\n MIXED_KEYFRAME_VALUE_TYPES = 'MIXED_KEYFRAME_VALUE_TYPES',\n TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE = 'TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE',\n ANIMATION_HAS_NO_VISIBLE_CHANGE = 'ANIMATION_HAS_NO_VISIBLE_CHANGE',\n AFFECTS_IMPORTANT_PROPERTY = 'AFFECTS_IMPORTANT_PROPERTY',\n SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY = 'SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY',\n}\n\nexport interface NoncompositedAnimationFailure {\n /**\n * Animation name.\n */\n name?: string;\n /**\n * Failure reason based on mask number defined in\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.\n */\n failureReasons: AnimationFailureReasons[];\n /**\n * Unsupported properties.\n */\n unsupportedProperties?: Types.Events.Animation['args']['data']['unsupportedProperties'];\n /**\n * Animation event.\n */\n animation?: Types.Events.SyntheticAnimationPair;\n}\n\n/**\n * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define\n * which bit corresponds to each failure reason.\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22\n */\nconst ACTIONABLE_FAILURE_REASONS: Array<{\n flag: number,\n failure: AnimationFailureReasons,\n}> =\n [\n {\n flag: 1 << 0,\n failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED,\n },\n {\n flag: 1 << 1,\n failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS,\n },\n {\n flag: 1 << 2,\n failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT,\n },\n {\n flag: 1 << 3,\n failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS,\n },\n {\n flag: 1 << 4,\n failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE,\n },\n {\n flag: 1 << 5,\n failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 6,\n failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS,\n },\n {\n flag: 1 << 7,\n failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET,\n },\n // The failure 1 << 8 is marked as obsolete in Blink\n {\n flag: 1 << 9,\n failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES,\n },\n {\n flag: 1 << 10,\n failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET,\n },\n {\n flag: 1 << 11,\n failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,\n },\n {\n flag: 1 << 12,\n failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS,\n },\n {\n flag: 1 << 13,\n failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,\n },\n // The failure 1 << 14 is marked as obsolete in Blink\n {\n flag: 1 << 15,\n failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES,\n },\n {\n flag: 1 << 16,\n failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 17,\n failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE,\n },\n {\n flag: 1 << 18,\n failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY,\n },\n {\n flag: 1 << 19,\n failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY,\n },\n ] as const;\n\n// 500ms window.\n// Use this window to consider events and requests that may have caused a layout shift.\nconst ROOT_CAUSE_WINDOW = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(0.5));\n\nexport interface UnsizedImage {\n backendNodeId: Protocol.DOM.BackendNodeId;\n paintImageEvent: Types.Events.PaintImage;\n}\n\nexport interface LayoutShiftRootCausesData {\n iframeIds: string[];\n fontRequests: Types.Events.SyntheticNetworkRequest[];\n nonCompositedAnimations: NoncompositedAnimationFailure[];\n unsizedImages: UnsizedImage[];\n}\n\n/**\n * Returns if an event happens within the root cause window, before the target event.\n * ROOT_CAUSE_WINDOW v target event\n * |------------------------|=======================\n */\nfunction isInRootCauseWindow(event: Types.Events.Event, targetEvent: Types.Events.Event): boolean {\n const eventEnd = event.dur ? event.ts + event.dur : event.ts;\n return eventEnd < targetEvent.ts && eventEnd >= targetEvent.ts - ROOT_CAUSE_WINDOW;\n}\n\nexport function getNonCompositedFailure(animationEvent: Types.Events.SyntheticAnimationPair):\n NoncompositedAnimationFailure[] {\n const failures: NoncompositedAnimationFailure[] = [];\n const beginEvent = animationEvent.args.data.beginEvent;\n const instantEvents = animationEvent.args.data.instantEvents || [];\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n for (const event of instantEvents) {\n const failureMask = event.args.data.compositeFailed;\n const unsupportedProperties = event.args.data.unsupportedProperties;\n if (!failureMask) {\n continue;\n }\n const failureReasons =\n ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => reason.failure);\n const failure: NoncompositedAnimationFailure = {\n name: beginEvent.args.data.displayName,\n failureReasons,\n unsupportedProperties,\n animation: animationEvent,\n };\n failures.push(failure);\n }\n return failures;\n}\n\nfunction getNonCompositedFailureRootCauses(\n animationEvents: Types.Events.SyntheticAnimationPair[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n ): NoncompositedAnimationFailure[] {\n const allAnimationFailures: NoncompositedAnimationFailure[] = [];\n for (const animation of animationEvents) {\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n const failures = getNonCompositedFailure(animation);\n if (!failures) {\n continue;\n }\n allAnimationFailures.push(...failures);\n\n const nextPrePaint = getNextEvent(prePaintEvents, animation) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n\n // If the animation event is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(animation, nextPrePaint)) {\n continue;\n }\n\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.nonCompositedAnimations.push(...failures);\n }\n }\n\n return allAnimationFailures;\n}\n\n/**\n * Given an array of layout shift and PrePaint events, returns a mapping from\n * PrePaint events to layout shifts dispatched within it.\n */\nfunction getShiftsByPrePaintEvents(\n layoutShifts: Types.Events.SyntheticLayoutShift[],\n prePaintEvents: Types.Events.PrePaint[],\n ): Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occurred in each one.\n const shiftsByPrePaint = new Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>();\n\n // Associate all shifts to their corresponding PrePaint.\n for (const prePaintEvent of prePaintEvents) {\n const firstShiftIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(layoutShifts, shift => shift.ts >= prePaintEvent.ts);\n if (firstShiftIndex === null) {\n // No layout shifts registered after this PrePaint start. Continue.\n continue;\n }\n for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n const shift = layoutShifts[i];\n if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n const shiftsInPrePaint = Platform.MapUtilities.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n shiftsInPrePaint.push(shift);\n }\n if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n // Reached all layoutShifts of this PrePaint. Break out to continue with the next prePaint event.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n\n/**\n * Given a source event list, this returns the first event of that list that directly follows the target event.\n */\nfunction getNextEvent(sourceEvents: Types.Events.Event[], targetEvent: Types.Events.Event): Types.Events.Event|\n undefined {\n const index = Platform.ArrayUtilities.nearestIndexFromBeginning(\n sourceEvents, source => source.ts > targetEvent.ts + (targetEvent.dur || 0));\n // No PrePaint event registered after this event\n if (index === null) {\n return undefined;\n }\n\n return sourceEvents[index];\n}\n\n/**\n * An Iframe is considered a root cause if the iframe event occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs.\n */\nfunction getIframeRootCauses(\n iframeCreatedEvents: readonly Types.Events.RenderFrameImplCreateChildFrame[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n domLoadingEvents: readonly Types.Events.DomLoading[]):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n for (const iframeEvent of iframeCreatedEvents) {\n const nextPrePaint = getNextEvent(prePaintEvents, iframeEvent) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n\n // Look for the first dom event that occurs within the bounds of the iframe event.\n // This contains the frame id.\n const domEvent = domLoadingEvents.find(e => {\n const maxIframe = Types.Timing.Micro(iframeEvent.ts + (iframeEvent.dur ?? 0));\n return e.ts >= iframeEvent.ts && e.ts <= maxIframe;\n });\n if (domEvent?.args.frame) {\n rootCausesForShift.iframeIds.push(domEvent.args.frame);\n }\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * An unsized image is considered a root cause if its PaintImage can be correlated to a\n * layout shift. We can correlate PaintImages with unsized images by their matching nodeIds.\n * X <- layout shift\n * |----------------|\n * ^ PrePaint event |-----|\n * ^ PaintImage\n */\nfunction getUnsizedImageRootCauses(\n unsizedImageEvents: readonly Types.Events.LayoutImageUnsized[], paintImageEvents: Types.Events.PaintImage[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n shiftsByPrePaint.forEach((shifts, prePaint) => {\n const paintImage = getNextEvent(paintImageEvents, prePaint) as Types.Events.PaintImage | null;\n if (!paintImage) {\n return;\n }\n // The unsized image corresponds to this PaintImage.\n const matchingNode =\n unsizedImageEvents.find(unsizedImage => unsizedImage.args.data.nodeId === paintImage.args.data.nodeId);\n if (!matchingNode) {\n return;\n }\n // The unsized image is a potential root cause of all the shifts of this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.unsizedImages.push({\n backendNodeId: matchingNode.args.data.nodeId,\n paintImageEvent: paintImage,\n });\n }\n });\n return rootCausesByShift;\n}\n\nexport function isCLSCulprits(insight: InsightModel): insight is CLSCulpritsInsightModel {\n return insight.insightKey === InsightKeys.CLS_CULPRITS;\n}\n\n/**\n * A font request is considered a root cause if the request occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs. Additionally, this font request should\n * happen within the ROOT_CAUSE_WINDOW of the prePaint event.\n */\nfunction getFontRootCauses(\n networkRequests: Types.Events.SyntheticNetworkRequest[], prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n const fontRequests =\n networkRequests.filter(req => req.args.data.resourceType === 'Font' && req.args.data.mimeType.startsWith('font'));\n\n for (const req of fontRequests) {\n const nextPrePaint = getNextEvent(prePaintEvents, req) as Types.Events.PrePaint | null;\n if (!nextPrePaint) {\n continue;\n }\n\n // If the req is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(req, nextPrePaint)) {\n continue;\n }\n\n // Get the shifts that belong to this prepaint\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n\n // if no layout shift(s) in this prePaint, the request is not a root cause.\n if (!shifts) {\n continue;\n }\n // Include the root cause to the shifts in this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.fontRequests.push(req);\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * Returns the top 3 shift root causes based on the given cluster.\n */\nfunction getTopCulprits(\n cluster: Types.Events.SyntheticLayoutShiftCluster,\n culpritsByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Platform.UIString.LocalizedString[] {\n const MAX_TOP_CULPRITS = 3;\n const causes: Platform.UIString.LocalizedString[] = [];\n\n const shifts = cluster.events;\n for (const shift of shifts) {\n const culprits = culpritsByShift.get(shift);\n if (!culprits) {\n continue;\n }\n\n const fontReq = culprits.fontRequests;\n const iframes = culprits.iframeIds;\n const animations = culprits.nonCompositedAnimations;\n const unsizedImages = culprits.unsizedImages;\n\n for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push(i18nString(UIStrings.fontRequest));\n }\n for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push(i18nString(UIStrings.injectedIframe));\n }\n for (let i = 0; i < animations.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push(i18nString(UIStrings.animation));\n }\n for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push(i18nString(UIStrings.unsizedImages));\n }\n\n if (causes.length >= MAX_TOP_CULPRITS) {\n break;\n }\n }\n\n return causes.slice(0, MAX_TOP_CULPRITS);\n}\n\nfunction finalize(partialModel: PartialInsightModel<CLSCulpritsInsightModel>): CLSCulpritsInsightModel {\n let state: CLSCulpritsInsightModel['state'] = 'pass';\n if (partialModel.worstCluster) {\n const classification = Handlers.ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(\n partialModel.worstCluster.clusterCumulativeScore);\n if (classification === Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD) {\n state = 'informative';\n } else {\n state = 'fail';\n }\n }\n\n return {\n insightKey: InsightKeys.CLS_CULPRITS,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.CLS,\n state,\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): CLSCulpritsInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const compositeAnimationEvents = parsedTrace.Animations.animations.filter(isWithinContext);\n const iframeEvents = parsedTrace.LayoutShifts.renderFrameImplCreateChildFrameEvents.filter(isWithinContext);\n const networkRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n const domLoadingEvents = parsedTrace.LayoutShifts.domLoadingEvents.filter(isWithinContext);\n const unsizedImageEvents = parsedTrace.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);\n\n const clusterKey = context.navigation ? context.navigationId : Types.Events.NO_NAVIGATION;\n const clusters = parsedTrace.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];\n const clustersByScore = [...clusters].sort((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);\n const worstCluster = clustersByScore.at(0);\n const layoutShifts = clusters.flatMap(cluster => cluster.events);\n const prePaintEvents = parsedTrace.LayoutShifts.prePaintEvents.filter(isWithinContext);\n const paintImageEvents = parsedTrace.LayoutShifts.paintImageEvents.filter(isWithinContext);\n\n // Get root causes.\n const rootCausesByShift = new Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>();\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n for (const shift of layoutShifts) {\n rootCausesByShift.set(shift, {iframeIds: [], fontRequests: [], nonCompositedAnimations: [], unsizedImages: []});\n }\n\n // Populate root causes for rootCausesByShift.\n getIframeRootCauses(iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);\n getFontRootCauses(networkRequests, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsByPrePaint, rootCausesByShift);\n const animationFailures =\n getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n\n const relatedEvents: Types.Events.Event[] = [...layoutShifts];\n if (worstCluster) {\n relatedEvents.push(worstCluster);\n }\n\n const topCulpritsByCluster = new Map<Types.Events.SyntheticLayoutShiftCluster, Platform.UIString.LocalizedString[]>();\n for (const cluster of clusters) {\n topCulpritsByCluster.set(cluster, getTopCulprits(cluster, rootCausesByShift));\n }\n\n return finalize({\n relatedEvents,\n animationFailures,\n shifts: rootCausesByShift,\n clusters,\n worstCluster,\n topCulpritsByCluster,\n });\n}\n"]}
1
+ {"version":3,"file":"CLSCulprits.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/CLSCulprits.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits (\"reasons\"). */\n title: 'Layout shift culprits',\n /**\n * @description Description of a DevTools insight that identifies the reasons that elements shift on the page.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description:\n 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://web.dev/articles/optimize-cls), such as elements being added, removed, or their fonts changing as the page loads.',\n /**\n *@description Text indicating the worst layout shift cluster.\n */\n worstLayoutShiftCluster: 'Worst layout shift cluster',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstCluster: 'Worst cluster',\n /**\n * @description Text indicating a layout shift cluster and its start time.\n * @example {32 ms} PH1\n */\n layoutShiftCluster: 'Layout shift cluster @ {PH1}',\n /**\n *@description Text indicating the biggest reasons for the layout shifts.\n */\n topCulprits: 'Top layout shift culprits',\n /**\n * @description Text for a culprit type of Injected iframe.\n */\n injectedIframe: 'Injected iframe',\n /**\n * @description Text for a culprit type of Font request.\n */\n fontRequest: 'Font request',\n /**\n * @description Text for a culprit type of Animation.\n */\n animation: 'Animation',\n /**\n * @description Text for a culprit type of Unsized image.\n */\n unsizedImage: 'Unsized image element',\n /**\n * @description Text status when there were no layout shifts detected.\n */\n noLayoutShifts: 'No layout shifts',\n /**\n * @description Text status when there no layout shifts culprits/root causes were found.\n */\n noCulprits: 'Could not detect any layout shift culprits',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/CLSCulprits.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CLSCulpritsInsightModel = InsightModel<typeof UIStrings, {\n animationFailures: readonly NoncompositedAnimationFailure[],\n shifts: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n clusters: Types.Events.SyntheticLayoutShiftCluster[],\n worstCluster: Types.Events.SyntheticLayoutShiftCluster | undefined,\n /** The top 3 shift root causes for each cluster. */\n topCulpritsByCluster: Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>,\n}>;\n\nexport enum AnimationFailureReasons {\n ACCELERATED_ANIMATIONS_DISABLED = 'ACCELERATED_ANIMATIONS_DISABLED',\n EFFECT_SUPPRESSED_BY_DEVTOOLS = 'EFFECT_SUPPRESSED_BY_DEVTOOLS',\n INVALID_ANIMATION_OR_EFFECT = 'INVALID_ANIMATION_OR_EFFECT',\n EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS = 'EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS',\n EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE = 'EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE',\n TARGET_HAS_INVALID_COMPOSITING_STATE = 'TARGET_HAS_INVALID_COMPOSITING_STATE',\n TARGET_HAS_INCOMPATIBLE_ANIMATIONS = 'TARGET_HAS_INCOMPATIBLE_ANIMATIONS',\n TARGET_HAS_CSS_OFFSET = 'TARGET_HAS_CSS_OFFSET',\n ANIMATION_AFFECTS_NON_CSS_PROPERTIES = 'ANIMATION_AFFECTS_NON_CSS_PROPERTIES',\n TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET =\n 'TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET',\n TRANSFROM_BOX_SIZE_DEPENDENT = 'TRANSFROM_BOX_SIZE_DEPENDENT',\n FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS = 'FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS',\n UNSUPPORTED_CSS_PROPERTY = 'UNSUPPORTED_CSS_PROPERTY',\n MIXED_KEYFRAME_VALUE_TYPES = 'MIXED_KEYFRAME_VALUE_TYPES',\n TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE = 'TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE',\n ANIMATION_HAS_NO_VISIBLE_CHANGE = 'ANIMATION_HAS_NO_VISIBLE_CHANGE',\n AFFECTS_IMPORTANT_PROPERTY = 'AFFECTS_IMPORTANT_PROPERTY',\n SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY = 'SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY',\n}\n\nexport enum LayoutShiftType {\n FONT_REQUESTS = 0,\n IFRAMES = 1,\n ANIMATIONS = 2,\n UNSIZED_IMAGE = 3,\n}\n\nexport type LayoutShiftItem = {\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: Platform.UIString.LocalizedString,\n url: string,\n backendNodeId: Protocol.DOM.BackendNodeId,\n frame: string,\n}|{\n type: Exclude<LayoutShiftType, LayoutShiftType.UNSIZED_IMAGE>,\n description: Platform.UIString.LocalizedString,\n};\n\nexport interface NoncompositedAnimationFailure {\n /**\n * Animation name.\n */\n name?: string;\n /**\n * Failure reason based on mask number defined in\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.\n */\n failureReasons: AnimationFailureReasons[];\n /**\n * Unsupported properties.\n */\n unsupportedProperties?: Types.Events.Animation['args']['data']['unsupportedProperties'];\n /**\n * Animation event.\n */\n animation?: Types.Events.SyntheticAnimationPair;\n}\n\n/**\n * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define\n * which bit corresponds to each failure reason.\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22\n */\nconst ACTIONABLE_FAILURE_REASONS: Array<{\n flag: number,\n failure: AnimationFailureReasons,\n}> =\n [\n {\n flag: 1 << 0,\n failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED,\n },\n {\n flag: 1 << 1,\n failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS,\n },\n {\n flag: 1 << 2,\n failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT,\n },\n {\n flag: 1 << 3,\n failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS,\n },\n {\n flag: 1 << 4,\n failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE,\n },\n {\n flag: 1 << 5,\n failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 6,\n failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS,\n },\n {\n flag: 1 << 7,\n failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET,\n },\n // The failure 1 << 8 is marked as obsolete in Blink\n {\n flag: 1 << 9,\n failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES,\n },\n {\n flag: 1 << 10,\n failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET,\n },\n {\n flag: 1 << 11,\n failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,\n },\n {\n flag: 1 << 12,\n failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS,\n },\n {\n flag: 1 << 13,\n failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,\n },\n // The failure 1 << 14 is marked as obsolete in Blink\n {\n flag: 1 << 15,\n failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES,\n },\n {\n flag: 1 << 16,\n failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 17,\n failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE,\n },\n {\n flag: 1 << 18,\n failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY,\n },\n {\n flag: 1 << 19,\n failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY,\n },\n ] as const;\n\n// 500ms window.\n// Use this window to consider events and requests that may have caused a layout shift.\nconst ROOT_CAUSE_WINDOW = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(0.5));\n\nexport interface UnsizedImage {\n backendNodeId: Protocol.DOM.BackendNodeId;\n paintImageEvent: Types.Events.PaintImage;\n}\n\nexport interface IframeRootCause {\n frame: string;\n url?: string;\n}\n\nexport interface LayoutShiftRootCausesData {\n iframes: IframeRootCause[];\n fontRequests: Types.Events.SyntheticNetworkRequest[];\n nonCompositedAnimations: NoncompositedAnimationFailure[];\n unsizedImages: UnsizedImage[];\n}\n\n/**\n * Returns if an event happens within the root cause window, before the target event.\n * ROOT_CAUSE_WINDOW v target event\n * |------------------------|=======================\n */\nfunction isInRootCauseWindow(event: Types.Events.Event, targetEvent: Types.Events.Event): boolean {\n const eventEnd = event.dur ? event.ts + event.dur : event.ts;\n return eventEnd < targetEvent.ts && eventEnd >= targetEvent.ts - ROOT_CAUSE_WINDOW;\n}\n\nexport function getNonCompositedFailure(animationEvent: Types.Events.SyntheticAnimationPair):\n NoncompositedAnimationFailure[] {\n const failures: NoncompositedAnimationFailure[] = [];\n const beginEvent = animationEvent.args.data.beginEvent;\n const instantEvents = animationEvent.args.data.instantEvents || [];\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n for (const event of instantEvents) {\n const failureMask = event.args.data.compositeFailed;\n const unsupportedProperties = event.args.data.unsupportedProperties;\n if (!failureMask) {\n continue;\n }\n const failureReasons =\n ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => reason.failure);\n const failure: NoncompositedAnimationFailure = {\n name: beginEvent.args.data.displayName,\n failureReasons,\n unsupportedProperties,\n animation: animationEvent,\n };\n failures.push(failure);\n }\n return failures;\n}\n\nfunction getNonCompositedFailureRootCauses(\n animationEvents: Types.Events.SyntheticAnimationPair[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n ): NoncompositedAnimationFailure[] {\n const allAnimationFailures: NoncompositedAnimationFailure[] = [];\n for (const animation of animationEvents) {\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n const failures = getNonCompositedFailure(animation);\n if (!failures) {\n continue;\n }\n allAnimationFailures.push(...failures);\n\n const nextPrePaint = getNextEvent(prePaintEvents, animation) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n\n // If the animation event is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(animation, nextPrePaint)) {\n continue;\n }\n\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.nonCompositedAnimations.push(...failures);\n }\n }\n\n return allAnimationFailures;\n}\n\n/**\n * Given an array of layout shift and PrePaint events, returns a mapping from\n * PrePaint events to layout shifts dispatched within it.\n */\nfunction getShiftsByPrePaintEvents(\n layoutShifts: Types.Events.SyntheticLayoutShift[],\n prePaintEvents: Types.Events.PrePaint[],\n ): Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occurred in each one.\n const shiftsByPrePaint = new Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>();\n\n // Associate all shifts to their corresponding PrePaint.\n for (const prePaintEvent of prePaintEvents) {\n const firstShiftIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(layoutShifts, shift => shift.ts >= prePaintEvent.ts);\n if (firstShiftIndex === null) {\n // No layout shifts registered after this PrePaint start. Continue.\n continue;\n }\n for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n const shift = layoutShifts[i];\n if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n const shiftsInPrePaint = Platform.MapUtilities.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n shiftsInPrePaint.push(shift);\n }\n if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n // Reached all layoutShifts of this PrePaint. Break out to continue with the next prePaint event.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n\n/**\n * Given a source event list, this returns the first event of that list that directly follows the target event.\n */\nfunction getNextEvent(sourceEvents: Types.Events.Event[], targetEvent: Types.Events.Event): Types.Events.Event|\n undefined {\n const index = Platform.ArrayUtilities.nearestIndexFromBeginning(\n sourceEvents, source => source.ts > targetEvent.ts + (targetEvent.dur || 0));\n // No PrePaint event registered after this event\n if (index === null) {\n return undefined;\n }\n\n return sourceEvents[index];\n}\n\n/**\n * An Iframe is considered a root cause if the iframe event occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs.\n */\nfunction getIframeRootCauses(\n parsedTrace: Handlers.Types.ParsedTrace,\n iframeCreatedEvents: readonly Types.Events.RenderFrameImplCreateChildFrame[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n domLoadingEvents: readonly Types.Events.DomLoading[]):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n for (const iframeEvent of iframeCreatedEvents) {\n const nextPrePaint = getNextEvent(prePaintEvents, iframeEvent) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n\n // Look for the first dom event that occurs within the bounds of the iframe event.\n // This contains the frame id.\n const domEvent = domLoadingEvents.find(e => {\n const maxIframe = Types.Timing.Micro(iframeEvent.ts + (iframeEvent.dur ?? 0));\n return e.ts >= iframeEvent.ts && e.ts <= maxIframe;\n });\n if (domEvent?.args.frame) {\n const frame = domEvent.args.frame;\n\n let url;\n const processes = parsedTrace.Meta.rendererProcessesByFrame.get(frame);\n if (processes && processes.size > 0) {\n url = [...processes.values()][0]?.[0].frame.url;\n }\n\n rootCausesForShift.iframes.push({frame, url});\n }\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * An unsized image is considered a root cause if its PaintImage can be correlated to a\n * layout shift. We can correlate PaintImages with unsized images by their matching nodeIds.\n * X <- layout shift\n * |----------------|\n * ^ PrePaint event |-----|\n * ^ PaintImage\n */\nfunction getUnsizedImageRootCauses(\n unsizedImageEvents: readonly Types.Events.LayoutImageUnsized[], paintImageEvents: Types.Events.PaintImage[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n shiftsByPrePaint.forEach((shifts, prePaint) => {\n const paintImage = getNextEvent(paintImageEvents, prePaint) as Types.Events.PaintImage | null;\n if (!paintImage) {\n return;\n }\n // The unsized image corresponds to this PaintImage.\n const matchingNode =\n unsizedImageEvents.find(unsizedImage => unsizedImage.args.data.nodeId === paintImage.args.data.nodeId);\n if (!matchingNode) {\n return;\n }\n // The unsized image is a potential root cause of all the shifts of this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.unsizedImages.push({\n backendNodeId: matchingNode.args.data.nodeId,\n paintImageEvent: paintImage,\n });\n }\n });\n return rootCausesByShift;\n}\n\nexport function isCLSCulprits(insight: InsightModel): insight is CLSCulpritsInsightModel {\n return insight.insightKey === InsightKeys.CLS_CULPRITS;\n}\n\n/**\n * A font request is considered a root cause if the request occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs. Additionally, this font request should\n * happen within the ROOT_CAUSE_WINDOW of the prePaint event.\n */\nfunction getFontRootCauses(\n networkRequests: Types.Events.SyntheticNetworkRequest[], prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n const fontRequests =\n networkRequests.filter(req => req.args.data.resourceType === 'Font' && req.args.data.mimeType.startsWith('font'));\n\n for (const req of fontRequests) {\n const nextPrePaint = getNextEvent(prePaintEvents, req) as Types.Events.PrePaint | null;\n if (!nextPrePaint) {\n continue;\n }\n\n // If the req is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(req, nextPrePaint)) {\n continue;\n }\n\n // Get the shifts that belong to this prepaint\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n\n // if no layout shift(s) in this prePaint, the request is not a root cause.\n if (!shifts) {\n continue;\n }\n // Include the root cause to the shifts in this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.fontRequests.push(req);\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * Returns the top 3 shift root causes based on the given cluster.\n */\nfunction getTopCulprits(\n cluster: Types.Events.SyntheticLayoutShiftCluster,\n culpritsByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>): LayoutShiftItem[] {\n const MAX_TOP_CULPRITS = 3;\n const causes: LayoutShiftItem[] = [];\n\n const shifts = cluster.events;\n for (const shift of shifts) {\n const culprits = culpritsByShift.get(shift);\n if (!culprits) {\n continue;\n }\n\n const fontReq = culprits.fontRequests;\n const iframes = culprits.iframes;\n const animations = culprits.nonCompositedAnimations;\n const unsizedImages = culprits.unsizedImages;\n\n for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.FONT_REQUESTS, description: i18nString(UIStrings.fontRequest)});\n }\n for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.IFRAMES, description: i18nString(UIStrings.injectedIframe)});\n }\n for (let i = 0; i < animations.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.ANIMATIONS, description: i18nString(UIStrings.animation)});\n }\n for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: i18nString(UIStrings.unsizedImage),\n url: unsizedImages[i].paintImageEvent.args.data.url || '',\n backendNodeId: unsizedImages[i].backendNodeId,\n frame: unsizedImages[i].paintImageEvent.args.data.frame || '',\n });\n }\n\n if (causes.length >= MAX_TOP_CULPRITS) {\n break;\n }\n }\n\n return causes.slice(0, MAX_TOP_CULPRITS);\n}\n\nfunction finalize(partialModel: PartialInsightModel<CLSCulpritsInsightModel>): CLSCulpritsInsightModel {\n let state: CLSCulpritsInsightModel['state'] = 'pass';\n if (partialModel.worstCluster) {\n const classification = Handlers.ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(\n partialModel.worstCluster.clusterCumulativeScore);\n if (classification === Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD) {\n state = 'informative';\n } else {\n state = 'fail';\n }\n }\n\n return {\n insightKey: InsightKeys.CLS_CULPRITS,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.CLS,\n state,\n ...partialModel,\n };\n}\n\nexport function generateInsight(\n parsedTrace: Handlers.Types.ParsedTrace, context: InsightSetContext): CLSCulpritsInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const compositeAnimationEvents = parsedTrace.Animations.animations.filter(isWithinContext);\n const iframeEvents = parsedTrace.LayoutShifts.renderFrameImplCreateChildFrameEvents.filter(isWithinContext);\n const networkRequests = parsedTrace.NetworkRequests.byTime.filter(isWithinContext);\n const domLoadingEvents = parsedTrace.LayoutShifts.domLoadingEvents.filter(isWithinContext);\n const unsizedImageEvents = parsedTrace.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);\n\n const clusterKey = context.navigation ? context.navigationId : Types.Events.NO_NAVIGATION;\n const clusters = parsedTrace.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];\n const clustersByScore = [...clusters].sort((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);\n const worstCluster = clustersByScore.at(0);\n const layoutShifts = clusters.flatMap(cluster => cluster.events);\n const prePaintEvents = parsedTrace.LayoutShifts.prePaintEvents.filter(isWithinContext);\n const paintImageEvents = parsedTrace.LayoutShifts.paintImageEvents.filter(isWithinContext);\n\n // Get root causes.\n const rootCausesByShift = new Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>();\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n for (const shift of layoutShifts) {\n rootCausesByShift.set(shift, {iframes: [], fontRequests: [], nonCompositedAnimations: [], unsizedImages: []});\n }\n\n // Populate root causes for rootCausesByShift.\n getIframeRootCauses(parsedTrace, iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);\n getFontRootCauses(networkRequests, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsByPrePaint, rootCausesByShift);\n const animationFailures =\n getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n\n const relatedEvents: Types.Events.Event[] = [...layoutShifts];\n if (worstCluster) {\n relatedEvents.push(worstCluster);\n }\n\n const topCulpritsByCluster = new Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>();\n for (const cluster of clusters) {\n topCulpritsByCluster.set(cluster, getTopCulprits(cluster, rootCausesByShift));\n }\n\n return finalize({\n relatedEvents,\n animationFailures,\n shifts: rootCausesByShift,\n clusters,\n worstCluster,\n topCulpritsByCluster,\n });\n}\n"]}
@@ -4,6 +4,7 @@
4
4
  import * as Helpers from '../helpers/helpers.js';
5
5
  import * as Types from '../types/types.js';
6
6
  import { getLogNormalScore } from './Statistics.js';
7
+ import { InsightKeys } from './types.js';
7
8
  const GRAPH_SAVINGS_PRECISION = 50;
8
9
  export function getInsight(insightName, insights, key) {
9
10
  if (!insights || !key) {
@@ -21,7 +22,7 @@ export function getInsight(insightName, insights, key) {
21
22
  return insight;
22
23
  }
23
24
  export function getLCP(insights, key) {
24
- const insight = getInsight("LCPPhases" /* InsightKeys.LCP_PHASES */, insights, key);
25
+ const insight = getInsight(InsightKeys.LCP_PHASES, insights, key);
25
26
  if (!insight || !insight.lcpMs || !insight.lcpEvent) {
26
27
  return null;
27
28
  }
@@ -29,7 +30,7 @@ export function getLCP(insights, key) {
29
30
  return { value, event: insight.lcpEvent };
30
31
  }
31
32
  export function getINP(insights, key) {
32
- const insight = getInsight("InteractionToNextPaint" /* InsightKeys.INTERACTION_TO_NEXT_PAINT */, insights, key);
33
+ const insight = getInsight(InsightKeys.INTERACTION_TO_NEXT_PAINT, insights, key);
33
34
  if (!insight?.longestInteractionEvent?.dur) {
34
35
  return null;
35
36
  }
@@ -37,7 +38,7 @@ export function getINP(insights, key) {
37
38
  return { value, event: insight.longestInteractionEvent };
38
39
  }
39
40
  export function getCLS(insights, key) {
40
- const insight = getInsight("CLSCulprits" /* InsightKeys.CLS_CULPRITS */, insights, key);
41
+ const insight = getInsight(InsightKeys.CLS_CULPRITS, insights, key);
41
42
  if (!insight) {
42
43
  // Unlike the other metrics, there is always a value for CLS even with no data.
43
44
  return { value: 0, worstClusterEvent: null };
@@ -1 +1 @@
1
- {"version":3,"file":"Common.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Common.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAK7B,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAEjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EAAC,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAUlD,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAEnC,MAAM,UAAU,UAAU,CACtB,WAAwB,EAAE,QAA+B,EAAE,GAAgB;IAC7E,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,OAAO,YAAY,KAAK,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yFAAyF;IACzF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,QAA+B,EAAE,GAAgB;IAEtE,MAAM,OAAO,GAAG,UAAU,2CAAyB,QAAQ,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,EAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,QAA+B,EAAE,GAAgB;IAEtE,MAAM,OAAO,GAAG,UAAU,uEAAwC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACjF,IAAI,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,uBAAuB,CAAC,GAAG,CAAC;IAClD,OAAO,EAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,uBAAuB,EAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,MAAM,CAClB,QAA+B,EAAE,GAAgB;IACnD,MAAM,OAAO,GAAG,UAAU,+CAA2B,QAAQ,EAAE,GAAG,CAAC,CAAC;IACpE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,+EAA+E;QAC/E,OAAO,EAAC,KAAK,EAAE,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAC,CAAC;IAC7C,CAAC;IAED,6DAA6D;IAC7D,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,YAAY,CAAC;IACjB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,sBAAsB,GAAG,QAAQ,EAAE,CAAC;YAC9C,QAAQ,GAAG,OAAO,CAAC,sBAAsB,CAAC;YAC1C,YAAY,GAAG,OAAO,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,EAAC,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,YAAY,IAAI,IAAI,EAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAyB;IAC9D,OAAO,iBAAiB,CAAC,EAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAyB;IAC9D,OAAO,iBAAiB,CAAC,EAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAC,EAAE,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,OAAO,iBAAiB,CAAC,EAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAC,EAAE,KAAK,CAAC,CAAC;AAC5D,CAAC;AAuBD,SAAS,aAAa,CAClB,aAAuC,EAAE,GAAW,EAAE,MAAc,EACpE,QAAgC,IAAI;IACtC,OAAO,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;QACjC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC;QAC5E,OAAO,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CACpB,UAAkC,EAAE,IAAqC,EACzE,QAAgC,IAAI;IACtC,MAAM,MAAM,GAAoF,EAAE,CAAC;IACnG,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAC,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAC,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,WAAW,EAAW,CAAC;QAC/D,IAAI,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC;QACpE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO,EAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAC1B,UAAkC,EAAE,IAAqC,EACzE,QAAgC,IAAI;IACtC,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACxD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,MAAM,CAAC,KAA2B,CAAC;QACnD,OAAO,EAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAC,CAAC;IACpF,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,4BAA4B,CACxC,UAAsB,EAAE,QAAkC,EAC1D,QAAgC,IAAI;IACtC,MAAM,aAAa,GAAG,QAAQ,EAAE,aAAa,CAAC;IAC9C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACnG,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,GAAG,EAAE,qBAAqB,CAAC,UAAU,EAAE,wBAAwB,EAAE,KAAK,CAAC;QACvE,GAAG,EAAE,qBAAqB,CAAC,UAAU,EAAE,0BAA0B,EAAE,KAAK,CAAC;QACzE,GAAG,EAAE,qBAAqB,CAAC,UAAU,EAAE,2BAA2B,EAAE,KAAK,CAAC;QAC1E,GAAG,EAAE,eAAe,CAAC,UAAU,EAAE,yBAAyB,EAAE,KAAK,CAAC;QAClE,SAAS,EAAE;YACT,IAAI,EAAE,qBAAqB,CAAC,UAAU,EAAE,mDAAmD,EAAE,KAAK,CAAC;YACnG,SAAS,EAAE,qBAAqB,CAAC,UAAU,EAAE,oDAAoD,EAAE,KAAK,CAAC;YACzG,YAAY,EAAE,qBAAqB,CAAC,UAAU,EAAE,uDAAuD,EAAE,KAAK,CAAC;YAC/G,WAAW,EAAE,qBAAqB,CAAC,UAAU,EAAE,qDAAqD,EAAE,KAAK,CAAC;SAC7G;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gCAAgC,CAC5C,UAAsB,EAAE,QAAkC;IAC5D,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,CAAC,GAAG,CAAC;QACV,GAAG,EAAE,CAAC,GAAG,CAAC;QACV,GAAG,EAAE,CAAC,GAAG,CAAC;KACX,CAAC;IAEF,MAAM,aAAa,GAAG,QAAQ,EAAE,aAAa,CAAC;IAC9C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,YAAY,GAAG,4BAA4B,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACxE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,IAAI,IAAI,CAAC;IACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,IAAI,IAAI,CAAC;IACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,IAAI,IAAI,CAAC;IACjD,MAAM,aAAa,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,aAAa,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,aAAa,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,MAAM,qBAAqB,GAAG,CAAC,GAAG,aAAa,CAAC;IAChD,MAAM,qBAAqB,GAAG,CAAC,GAAG,aAAa,CAAC;IAChD,MAAM,qBAAqB,GAAG,CAAC,GAAG,aAAa,CAAC;IAChD,MAAM,WAAW,GAAG,qBAAqB,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;IAC1F,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,GAAG,GAAG,qBAAqB,GAAG,WAAW,CAAC;IAClD,OAAO,CAAC,GAAG,GAAG,qBAAqB,GAAG,WAAW,CAAC;IAClD,OAAO,CAAC,GAAG,GAAG,qBAAqB,GAAG,WAAW,CAAC;IAElD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAC9B,sBAA2C,EAAE,SAAuC,EACpF,KAAyB;IAC3B,MAAM,uBAAuB,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE1D,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QACpB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,MAAM,WAAW,GAAG,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;QAC3C,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE5D,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,MAAM,sBAAsB,GAAG,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEzD,qEAAqE;IACrE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QACpB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC/E,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,YAAY,GAAG,oBAAoB,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,GAAG,uBAAuB,CAAC,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC;IACjF,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,uBAAuB,CAAC,GAAG,uBAAuB,CAAC;IAClF,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACvC,sBAA2C,EAAE,OAA0B;IACzE,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;QACjC,OAAO,EAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,CAAC;IAClE,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC;IAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,eAAe,CAAC;IAEhF,OAAO;QACL,GAAG,EAAE,yBAAyB,CAAC,sBAAsB,EAAE,SAAS,EAAE,QAAQ,CAAC;QAC3E,GAAG,EAAE,yBAAyB,CAAC,sBAAsB,EAAE,SAAS,EAAE,QAAQ,CAAC;KAC5E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA6C;IAC/E,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+EAA+E;IAC/E,qDAAqD;IACrD,MAAM,QAAQ,GAAG;QACf,qBAAqB,EAAE,oCAAoC;QAC3D,gCAAgC,EAAG,cAAc;KAClD,CAAC;IACF,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CACzC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACrG,CAAC;AAED,SAAS,eAAe,CAAC,OAA6C;IACpE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC;IACzD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC;IACzD,OAAO,EAAC,YAAY,EAAE,YAAY,EAAC,CAAC;AACtC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,CACzC,OAAuD,EAAE,UAAkB,EAC3E,YAA2C;IAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,uFAAuF;QACvF,2CAA2C;QAC3C,+JAA+J;QAC/J,uGAAuG;QACvG,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,YAAY;gBACf,+CAA+C;gBAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;YACtC,KAAK,QAAQ,CAAC;YACd,KAAK,UAAU;gBACb,6CAA6C;gBAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;YACvC;gBACE,sEAAsE;gBACtE,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,oDAAoD;IACpD,MAAM,EAAC,YAAY,EAAE,YAAY,EAAC,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,mBAAmB,GAAG,YAAY,CAAC;IACvC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,+DAA+D;QAC/D,2FAA2F;QAC3F,iDAAiD;QACjD,mBAAmB,GAAG,YAAY,CAAC;IACrC,CAAC;IACD,sEAAsE;IACtE,kDAAkD;IAClD,iDAAiD;IACjD,0BAA0B;IAC1B,8EAA8E;IAC9E,IAAI;IAEJ,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,YAAY,EAAE,CAAC;QACpD,mEAAmE;QACnE,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED,wFAAwF;IACxF,qFAAqF;IACrF,+EAA+E;IAC/E,MAAM,gBAAgB,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtH,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,gBAAgB,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iCAAiC,CAAC,MAA6C;IAC7F,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,qCAAqC;QACrC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;IACzF,MAAM,cAAc,GAAG,6BAA6B,CAAC,OAAO,EAAE,aAAa,sDAAuC,CAAC;IACnH,IAAI,aAAa,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,gBAAgB,GAAG,cAAc,GAAG,aAAa,CAAC;IACxD,OAAO,gBAAgB,CAAC;AAC1B,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Protocol from '../../../generated/protocol.js';\nimport type * as CrUXManager from '../../crux-manager/crux-manager.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport * as Types from '../types/types.js';\n\nimport {getLogNormalScore} from './Statistics.js';\nimport {\n InsightKeys,\n type InsightModels,\n type InsightSet,\n type InsightSetContext,\n type MetricSavings,\n type TraceInsightSets\n} from './types.js';\n\nconst GRAPH_SAVINGS_PRECISION = 50;\n\nexport function getInsight<InsightName extends keyof InsightModels>(\n insightName: InsightName, insights: TraceInsightSets|null, key: string|null): InsightModels[InsightName]|null {\n if (!insights || !key) {\n return null;\n }\n\n const insightSets = insights.get(key);\n if (!insightSets) {\n return null;\n }\n\n const insight = insightSets.model[insightName];\n if (insight instanceof Error) {\n return null;\n }\n\n // For some reason typescript won't narrow the type by removing Error, so do it manually.\n return insight;\n}\n\nexport function getLCP(insights: TraceInsightSets|null, key: string|null):\n {value: Types.Timing.Micro, event: Types.Events.LargestContentfulPaintCandidate}|null {\n const insight = getInsight(InsightKeys.LCP_PHASES, insights, key);\n if (!insight || !insight.lcpMs || !insight.lcpEvent) {\n return null;\n }\n\n const value = Helpers.Timing.milliToMicro(insight.lcpMs);\n return {value, event: insight.lcpEvent};\n}\n\nexport function getINP(insights: TraceInsightSets|null, key: string|null):\n {value: Types.Timing.Micro, event: Types.Events.SyntheticInteractionPair}|null {\n const insight = getInsight(InsightKeys.INTERACTION_TO_NEXT_PAINT, insights, key);\n if (!insight?.longestInteractionEvent?.dur) {\n return null;\n }\n\n const value = insight.longestInteractionEvent.dur;\n return {value, event: insight.longestInteractionEvent};\n}\n\nexport function getCLS(\n insights: TraceInsightSets|null, key: string|null): {value: number, worstClusterEvent: Types.Events.Event|null} {\n const insight = getInsight(InsightKeys.CLS_CULPRITS, insights, key);\n if (!insight) {\n // Unlike the other metrics, there is always a value for CLS even with no data.\n return {value: 0, worstClusterEvent: null};\n }\n\n // TODO(cjamcl): the CLS insight should be doing this for us.\n let maxScore = 0;\n let worstCluster;\n for (const cluster of insight.clusters) {\n if (cluster.clusterCumulativeScore > maxScore) {\n maxScore = cluster.clusterCumulativeScore;\n worstCluster = cluster;\n }\n }\n\n return {value: maxScore, worstClusterEvent: worstCluster ?? null};\n}\n\nexport function evaluateLCPMetricScore(value: Types.Timing.Milli): number {\n return getLogNormalScore({p10: 2500, median: 4000}, value);\n}\n\nexport function evaluateINPMetricScore(value: Types.Timing.Milli): number {\n return getLogNormalScore({p10: 200, median: 500}, value);\n}\n\nexport function evaluateCLSMetricScore(value: number): number {\n return getLogNormalScore({p10: 0.1, median: 0.25}, value);\n}\n\nexport interface CrUXFieldMetricTimingResult {\n value: Types.Timing.Micro;\n pageScope: CrUXManager.PageScope;\n}\nexport interface CrUXFieldMetricNumberResult {\n value: number;\n pageScope: CrUXManager.PageScope;\n}\nexport interface CrUXFieldMetricResults {\n fcp: CrUXFieldMetricTimingResult|null;\n lcp: CrUXFieldMetricTimingResult|null;\n inp: CrUXFieldMetricTimingResult|null;\n cls: CrUXFieldMetricNumberResult|null;\n lcpPhases: {\n ttfb: CrUXFieldMetricTimingResult|null,\n loadDelay: CrUXFieldMetricTimingResult|null,\n loadDuration: CrUXFieldMetricTimingResult|null,\n renderDelay: CrUXFieldMetricTimingResult|null,\n };\n}\n\nfunction getPageResult(\n cruxFieldData: CrUXManager.PageResult[], url: string, origin: string,\n scope: CrUXManager.Scope|null = null): CrUXManager.PageResult|undefined {\n return cruxFieldData.find(result => {\n const key = scope ? result[`${scope.pageScope}-${scope.deviceScope}`]?.record.key :\n (result['url-ALL'] || result['origin-ALL'])?.record.key;\n return (key?.url && key.url === url) || (key?.origin && key.origin === origin);\n });\n}\n\nfunction getMetricResult(\n pageResult: CrUXManager.PageResult, name: CrUXManager.StandardMetricNames,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricNumberResult|null {\n const scopes: Array<{pageScope: CrUXManager.PageScope, deviceScope: CrUXManager.DeviceScope}> = [];\n if (scope) {\n scopes.push(scope);\n } else {\n scopes.push({pageScope: 'url', deviceScope: 'ALL'});\n scopes.push({pageScope: 'origin', deviceScope: 'ALL'});\n }\n\n for (const scope of scopes) {\n const key = `${scope.pageScope}-${scope.deviceScope}` as const;\n let value = pageResult[key]?.record.metrics[name]?.percentiles?.p75;\n if (typeof value === 'string') {\n value = Number(value);\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return {value, pageScope: scope.pageScope};\n }\n }\n\n return null;\n}\n\nfunction getMetricTimingResult(\n pageResult: CrUXManager.PageResult, name: CrUXManager.StandardMetricNames,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricTimingResult|null {\n const result = getMetricResult(pageResult, name, scope);\n if (result) {\n const valueMs = result.value as Types.Timing.Milli;\n return {value: Helpers.Timing.milliToMicro(valueMs), pageScope: result.pageScope};\n }\n\n return null;\n}\n\nexport function getFieldMetricsForInsightSet(\n insightSet: InsightSet, metadata: Types.File.MetaData|null,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricResults|null {\n const cruxFieldData = metadata?.cruxFieldData;\n if (!cruxFieldData) {\n return null;\n }\n\n const pageResult = getPageResult(cruxFieldData, insightSet.url.href, insightSet.url.origin, scope);\n if (!pageResult) {\n return null;\n }\n\n return {\n fcp: getMetricTimingResult(pageResult, 'first_contentful_paint', scope),\n lcp: getMetricTimingResult(pageResult, 'largest_contentful_paint', scope),\n inp: getMetricTimingResult(pageResult, 'interaction_to_next_paint', scope),\n cls: getMetricResult(pageResult, 'cumulative_layout_shift', scope),\n lcpPhases: {\n ttfb: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_time_to_first_byte', scope),\n loadDelay: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_resource_load_delay', scope),\n loadDuration: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_resource_load_duration', scope),\n renderDelay: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_element_render_delay', scope),\n }\n };\n}\n\nexport function calculateMetricWeightsForSorting(\n insightSet: InsightSet, metadata: Types.File.MetaData|null): {lcp: number, inp: number, cls: number} {\n const weights = {\n lcp: 1 / 3,\n inp: 1 / 3,\n cls: 1 / 3,\n };\n\n const cruxFieldData = metadata?.cruxFieldData;\n if (!cruxFieldData) {\n return weights;\n }\n\n const fieldMetrics = getFieldMetricsForInsightSet(insightSet, metadata);\n if (!fieldMetrics) {\n return weights;\n }\n\n const fieldLcp = fieldMetrics.lcp?.value ?? null;\n const fieldInp = fieldMetrics.inp?.value ?? null;\n const fieldCls = fieldMetrics.cls?.value ?? null;\n const fieldLcpScore = fieldLcp !== null ? evaluateLCPMetricScore(Helpers.Timing.microToMilli(fieldLcp)) : 0;\n const fieldInpScore = fieldInp !== null ? evaluateINPMetricScore(Helpers.Timing.microToMilli(fieldInp)) : 0;\n const fieldClsScore = fieldCls !== null ? evaluateCLSMetricScore(fieldCls) : 0;\n const fieldLcpScoreInverted = 1 - fieldLcpScore;\n const fieldInpScoreInverted = 1 - fieldInpScore;\n const fieldClsScoreInverted = 1 - fieldClsScore;\n const invertedSum = fieldLcpScoreInverted + fieldInpScoreInverted + fieldClsScoreInverted;\n if (!invertedSum) {\n return weights;\n }\n\n weights.lcp = fieldLcpScoreInverted / invertedSum;\n weights.inp = fieldInpScoreInverted / invertedSum;\n weights.cls = fieldClsScoreInverted / invertedSum;\n\n return weights;\n}\n\n/**\n * Simulates the provided graph before and after the byte savings from `wastedBytesByRequestId` are applied.\n */\nfunction estimateSavingsWithGraphs(\n wastedBytesByRequestId: Map<string, number>, simulator: Lantern.Simulation.Simulator,\n graph: Lantern.Graph.Node): Types.Timing.Milli {\n const simulationBeforeChanges = simulator.simulate(graph);\n\n const originalTransferSizes = new Map<string, number>();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const wastedBytes = wastedBytesByRequestId.get(node.request.requestId);\n if (!wastedBytes) {\n return;\n }\n\n const original = node.request.transferSize;\n originalTransferSizes.set(node.request.requestId, original);\n\n node.request.transferSize = Math.max(original - wastedBytes, 0);\n });\n\n const simulationAfterChanges = simulator.simulate(graph);\n\n // Restore the original transfer size after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalTransferSize = originalTransferSizes.get(node.request.requestId);\n if (originalTransferSize === undefined) {\n return;\n }\n node.request.transferSize = originalTransferSize;\n });\n\n let savings = simulationBeforeChanges.timeInMs - simulationAfterChanges.timeInMs;\n savings = Math.round(savings / GRAPH_SAVINGS_PRECISION) * GRAPH_SAVINGS_PRECISION;\n return Types.Timing.Milli(savings);\n}\n\n/**\n * Estimates the FCP & LCP savings for wasted bytes in `wastedBytesByRequestId`.\n */\nexport function metricSavingsForWastedBytes(\n wastedBytesByRequestId: Map<string, number>, context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n if (!wastedBytesByRequestId.size) {\n return {FCP: Types.Timing.Milli(0), LCP: Types.Timing.Milli(0)};\n }\n\n const simulator = context.lantern.simulator;\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, fcpGraph),\n LCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, lcpGraph),\n };\n}\n\n/**\n * Returns whether the network request was sent encoded.\n */\nexport function isRequestCompressed(request: Types.Events.SyntheticNetworkRequest): boolean {\n if (!request.args.data.responseHeaders) {\n return false;\n }\n\n // FYI: In Lighthouse, older devtools logs (like our test fixtures) seems to be\n // lower case, while modern logs are Cased-Like-This.\n const patterns = [\n /^content-encoding$/i, /^x-content-encoding-over-network$/i,\n /^x-original-content-encoding$/i, // Lightrider.\n ];\n const compressionTypes = ['gzip', 'br', 'deflate', 'zstd'];\n return request.args.data.responseHeaders.some(\n header => patterns.some(p => header.name.match(p)) && compressionTypes.includes(header.value));\n}\n\nfunction getRequestSizes(request: Types.Events.SyntheticNetworkRequest): {resourceSize: number, transferSize: number} {\n const resourceSize = request.args.data.decodedBodyLength;\n const transferSize = request.args.data.encodedDataLength;\n return {resourceSize, transferSize};\n}\n\n/**\n * Estimates the number of bytes the content of this network record would have consumed on the network based on the\n * uncompressed size (totalBytes). Uses the actual transfer size from the network record if applicable,\n * minus the size of the response headers.\n *\n * @param totalBytes Uncompressed size of the resource\n */\nexport function estimateCompressedContentSize(\n request: Types.Events.SyntheticNetworkRequest|undefined, totalBytes: number,\n resourceType: Protocol.Network.ResourceType): number {\n if (!request) {\n // We don't know how many bytes this asset used on the network, but we can guess it was\n // roughly the size of the content gzipped.\n // See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer for specific CSS/Script examples\n // See https://discuss.httparchive.org/t/file-size-and-compression-savings/145 for fallback multipliers\n switch (resourceType) {\n case 'Stylesheet':\n // Stylesheets tend to compress extremely well.\n return Math.round(totalBytes * 0.2);\n case 'Script':\n case 'Document':\n // Scripts and HTML compress fairly well too.\n return Math.round(totalBytes * 0.33);\n default:\n // Otherwise we'll just fallback to the average savings in HTTPArchive\n return Math.round(totalBytes * 0.5);\n }\n }\n\n // Get the size of the response body on the network.\n const {transferSize, resourceSize} = getRequestSizes(request);\n let contentTransferSize = transferSize;\n if (!isRequestCompressed(request)) {\n // This is not compressed, so we can use resourceSize directly.\n // This would be equivalent to transfer size minus headers transfer size, but transfer size\n // may also include bytes for SSL connection etc.\n contentTransferSize = resourceSize;\n }\n // TODO(cjamcl): Get \"responseHeadersTransferSize\" in Network handler.\n // else if (request.responseHeadersTransferSize) {\n // // Subtract the size of the encoded headers.\n // contentTransferSize =\n // Math.max(0, contentTransferSize - request.responseHeadersTransferSize);\n // }\n\n if (request.args.data.resourceType === resourceType) {\n // This was a regular standalone asset, just use the transfer size.\n return contentTransferSize;\n }\n\n // This was an asset that was inlined in a different resource type (e.g. HTML document).\n // Use the compression ratio of the resource to estimate the total transferred bytes.\n // Get the compression ratio, if it's an invalid number, assume no compression.\n const compressionRatio = Number.isFinite(resourceSize) && resourceSize > 0 ? (contentTransferSize / resourceSize) : 1;\n return Math.round(totalBytes * compressionRatio);\n}\n\n/**\n * Utility function to estimate the ratio of the compression of a script.\n * This excludes the size of the response headers.\n */\nexport function estimateCompressionRatioForScript(script: Handlers.ModelHandlers.Scripts.Script): number {\n if (!script.request) {\n // Can't find request, so just use 1.\n return 1;\n }\n\n const request = script.request;\n const contentLength = request.args.data.decodedBodyLength ?? script.content?.length ?? 0;\n const compressedSize = estimateCompressedContentSize(request, contentLength, Protocol.Network.ResourceType.Script);\n if (contentLength === 0 || compressedSize === 0) {\n return 1;\n }\n\n const compressionRatio = compressedSize / contentLength;\n return compressionRatio;\n}\n"]}
1
+ {"version":3,"file":"Common.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Common.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Protocol from '../../../generated/protocol.js';\nimport type * as CrUXManager from '../../crux-manager/crux-manager.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Lantern from '../lantern/lantern.js';\nimport * as Types from '../types/types.js';\n\nimport {getLogNormalScore} from './Statistics.js';\nimport {\n InsightKeys,\n type InsightModels,\n type InsightSet,\n type InsightSetContext,\n type MetricSavings,\n type TraceInsightSets\n} from './types.js';\n\nconst GRAPH_SAVINGS_PRECISION = 50;\n\nexport function getInsight<InsightName extends keyof InsightModels>(\n insightName: InsightName, insights: TraceInsightSets|null, key: string|null): InsightModels[InsightName]|null {\n if (!insights || !key) {\n return null;\n }\n\n const insightSets = insights.get(key);\n if (!insightSets) {\n return null;\n }\n\n const insight = insightSets.model[insightName];\n if (insight instanceof Error) {\n return null;\n }\n\n // For some reason typescript won't narrow the type by removing Error, so do it manually.\n return insight;\n}\n\nexport function getLCP(insights: TraceInsightSets|null, key: string|null):\n {value: Types.Timing.Micro, event: Types.Events.LargestContentfulPaintCandidate}|null {\n const insight = getInsight(InsightKeys.LCP_PHASES, insights, key);\n if (!insight || !insight.lcpMs || !insight.lcpEvent) {\n return null;\n }\n\n const value = Helpers.Timing.milliToMicro(insight.lcpMs);\n return {value, event: insight.lcpEvent};\n}\n\nexport function getINP(insights: TraceInsightSets|null, key: string|null):\n {value: Types.Timing.Micro, event: Types.Events.SyntheticInteractionPair}|null {\n const insight = getInsight(InsightKeys.INTERACTION_TO_NEXT_PAINT, insights, key);\n if (!insight?.longestInteractionEvent?.dur) {\n return null;\n }\n\n const value = insight.longestInteractionEvent.dur;\n return {value, event: insight.longestInteractionEvent};\n}\n\nexport function getCLS(\n insights: TraceInsightSets|null, key: string|null): {value: number, worstClusterEvent: Types.Events.Event|null} {\n const insight = getInsight(InsightKeys.CLS_CULPRITS, insights, key);\n if (!insight) {\n // Unlike the other metrics, there is always a value for CLS even with no data.\n return {value: 0, worstClusterEvent: null};\n }\n\n // TODO(cjamcl): the CLS insight should be doing this for us.\n let maxScore = 0;\n let worstCluster;\n for (const cluster of insight.clusters) {\n if (cluster.clusterCumulativeScore > maxScore) {\n maxScore = cluster.clusterCumulativeScore;\n worstCluster = cluster;\n }\n }\n\n return {value: maxScore, worstClusterEvent: worstCluster ?? null};\n}\n\nexport function evaluateLCPMetricScore(value: Types.Timing.Milli): number {\n return getLogNormalScore({p10: 2500, median: 4000}, value);\n}\n\nexport function evaluateINPMetricScore(value: Types.Timing.Milli): number {\n return getLogNormalScore({p10: 200, median: 500}, value);\n}\n\nexport function evaluateCLSMetricScore(value: number): number {\n return getLogNormalScore({p10: 0.1, median: 0.25}, value);\n}\n\nexport interface CrUXFieldMetricTimingResult {\n value: Types.Timing.Micro;\n pageScope: CrUXManager.PageScope;\n}\nexport interface CrUXFieldMetricNumberResult {\n value: number;\n pageScope: CrUXManager.PageScope;\n}\nexport interface CrUXFieldMetricResults {\n fcp: CrUXFieldMetricTimingResult|null;\n lcp: CrUXFieldMetricTimingResult|null;\n inp: CrUXFieldMetricTimingResult|null;\n cls: CrUXFieldMetricNumberResult|null;\n lcpPhases: {\n ttfb: CrUXFieldMetricTimingResult|null,\n loadDelay: CrUXFieldMetricTimingResult|null,\n loadDuration: CrUXFieldMetricTimingResult|null,\n renderDelay: CrUXFieldMetricTimingResult|null,\n };\n}\n\nfunction getPageResult(\n cruxFieldData: CrUXManager.PageResult[], url: string, origin: string,\n scope: CrUXManager.Scope|null = null): CrUXManager.PageResult|undefined {\n return cruxFieldData.find(result => {\n const key = scope ? result[`${scope.pageScope}-${scope.deviceScope}`]?.record.key :\n (result['url-ALL'] || result['origin-ALL'])?.record.key;\n return (key?.url && key.url === url) || (key?.origin && key.origin === origin);\n });\n}\n\nfunction getMetricResult(\n pageResult: CrUXManager.PageResult, name: CrUXManager.StandardMetricNames,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricNumberResult|null {\n const scopes: Array<{pageScope: CrUXManager.PageScope, deviceScope: CrUXManager.DeviceScope}> = [];\n if (scope) {\n scopes.push(scope);\n } else {\n scopes.push({pageScope: 'url', deviceScope: 'ALL'});\n scopes.push({pageScope: 'origin', deviceScope: 'ALL'});\n }\n\n for (const scope of scopes) {\n const key = `${scope.pageScope}-${scope.deviceScope}` as const;\n let value = pageResult[key]?.record.metrics[name]?.percentiles?.p75;\n if (typeof value === 'string') {\n value = Number(value);\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return {value, pageScope: scope.pageScope};\n }\n }\n\n return null;\n}\n\nfunction getMetricTimingResult(\n pageResult: CrUXManager.PageResult, name: CrUXManager.StandardMetricNames,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricTimingResult|null {\n const result = getMetricResult(pageResult, name, scope);\n if (result) {\n const valueMs = result.value as Types.Timing.Milli;\n return {value: Helpers.Timing.milliToMicro(valueMs), pageScope: result.pageScope};\n }\n\n return null;\n}\n\nexport function getFieldMetricsForInsightSet(\n insightSet: InsightSet, metadata: Types.File.MetaData|null,\n scope: CrUXManager.Scope|null = null): CrUXFieldMetricResults|null {\n const cruxFieldData = metadata?.cruxFieldData;\n if (!cruxFieldData) {\n return null;\n }\n\n const pageResult = getPageResult(cruxFieldData, insightSet.url.href, insightSet.url.origin, scope);\n if (!pageResult) {\n return null;\n }\n\n return {\n fcp: getMetricTimingResult(pageResult, 'first_contentful_paint', scope),\n lcp: getMetricTimingResult(pageResult, 'largest_contentful_paint', scope),\n inp: getMetricTimingResult(pageResult, 'interaction_to_next_paint', scope),\n cls: getMetricResult(pageResult, 'cumulative_layout_shift', scope),\n lcpPhases: {\n ttfb: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_time_to_first_byte', scope),\n loadDelay: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_resource_load_delay', scope),\n loadDuration: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_resource_load_duration', scope),\n renderDelay: getMetricTimingResult(pageResult, 'largest_contentful_paint_image_element_render_delay', scope),\n }\n };\n}\n\nexport function calculateMetricWeightsForSorting(\n insightSet: InsightSet, metadata: Types.File.MetaData|null): {lcp: number, inp: number, cls: number} {\n const weights = {\n lcp: 1 / 3,\n inp: 1 / 3,\n cls: 1 / 3,\n };\n\n const cruxFieldData = metadata?.cruxFieldData;\n if (!cruxFieldData) {\n return weights;\n }\n\n const fieldMetrics = getFieldMetricsForInsightSet(insightSet, metadata);\n if (!fieldMetrics) {\n return weights;\n }\n\n const fieldLcp = fieldMetrics.lcp?.value ?? null;\n const fieldInp = fieldMetrics.inp?.value ?? null;\n const fieldCls = fieldMetrics.cls?.value ?? null;\n const fieldLcpScore = fieldLcp !== null ? evaluateLCPMetricScore(Helpers.Timing.microToMilli(fieldLcp)) : 0;\n const fieldInpScore = fieldInp !== null ? evaluateINPMetricScore(Helpers.Timing.microToMilli(fieldInp)) : 0;\n const fieldClsScore = fieldCls !== null ? evaluateCLSMetricScore(fieldCls) : 0;\n const fieldLcpScoreInverted = 1 - fieldLcpScore;\n const fieldInpScoreInverted = 1 - fieldInpScore;\n const fieldClsScoreInverted = 1 - fieldClsScore;\n const invertedSum = fieldLcpScoreInverted + fieldInpScoreInverted + fieldClsScoreInverted;\n if (!invertedSum) {\n return weights;\n }\n\n weights.lcp = fieldLcpScoreInverted / invertedSum;\n weights.inp = fieldInpScoreInverted / invertedSum;\n weights.cls = fieldClsScoreInverted / invertedSum;\n\n return weights;\n}\n\n/**\n * Simulates the provided graph before and after the byte savings from `wastedBytesByRequestId` are applied.\n */\nfunction estimateSavingsWithGraphs(\n wastedBytesByRequestId: Map<string, number>, simulator: Lantern.Simulation.Simulator,\n graph: Lantern.Graph.Node): Types.Timing.Milli {\n const simulationBeforeChanges = simulator.simulate(graph);\n\n const originalTransferSizes = new Map<string, number>();\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const wastedBytes = wastedBytesByRequestId.get(node.request.requestId);\n if (!wastedBytes) {\n return;\n }\n\n const original = node.request.transferSize;\n originalTransferSizes.set(node.request.requestId, original);\n\n node.request.transferSize = Math.max(original - wastedBytes, 0);\n });\n\n const simulationAfterChanges = simulator.simulate(graph);\n\n // Restore the original transfer size after we've done our simulation\n graph.traverse(node => {\n if (node.type !== 'network') {\n return;\n }\n const originalTransferSize = originalTransferSizes.get(node.request.requestId);\n if (originalTransferSize === undefined) {\n return;\n }\n node.request.transferSize = originalTransferSize;\n });\n\n let savings = simulationBeforeChanges.timeInMs - simulationAfterChanges.timeInMs;\n savings = Math.round(savings / GRAPH_SAVINGS_PRECISION) * GRAPH_SAVINGS_PRECISION;\n return Types.Timing.Milli(savings);\n}\n\n/**\n * Estimates the FCP & LCP savings for wasted bytes in `wastedBytesByRequestId`.\n */\nexport function metricSavingsForWastedBytes(\n wastedBytesByRequestId: Map<string, number>, context: InsightSetContext): MetricSavings|undefined {\n if (!context.navigation || !context.lantern) {\n return;\n }\n\n if (!wastedBytesByRequestId.size) {\n return {FCP: Types.Timing.Milli(0), LCP: Types.Timing.Milli(0)};\n }\n\n const simulator = context.lantern.simulator;\n const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n\n return {\n FCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, fcpGraph),\n LCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, lcpGraph),\n };\n}\n\n/**\n * Returns whether the network request was sent encoded.\n */\nexport function isRequestCompressed(request: Types.Events.SyntheticNetworkRequest): boolean {\n if (!request.args.data.responseHeaders) {\n return false;\n }\n\n // FYI: In Lighthouse, older devtools logs (like our test fixtures) seems to be\n // lower case, while modern logs are Cased-Like-This.\n const patterns = [\n /^content-encoding$/i, /^x-content-encoding-over-network$/i,\n /^x-original-content-encoding$/i, // Lightrider.\n ];\n const compressionTypes = ['gzip', 'br', 'deflate', 'zstd'];\n return request.args.data.responseHeaders.some(\n header => patterns.some(p => header.name.match(p)) && compressionTypes.includes(header.value));\n}\n\nfunction getRequestSizes(request: Types.Events.SyntheticNetworkRequest): {resourceSize: number, transferSize: number} {\n const resourceSize = request.args.data.decodedBodyLength;\n const transferSize = request.args.data.encodedDataLength;\n return {resourceSize, transferSize};\n}\n\n/**\n * Estimates the number of bytes the content of this network record would have consumed on the network based on the\n * uncompressed size (totalBytes). Uses the actual transfer size from the network record if applicable,\n * minus the size of the response headers.\n *\n * @param totalBytes Uncompressed size of the resource\n */\nexport function estimateCompressedContentSize(\n request: Types.Events.SyntheticNetworkRequest|undefined, totalBytes: number,\n resourceType: Protocol.Network.ResourceType): number {\n if (!request) {\n // We don't know how many bytes this asset used on the network, but we can guess it was\n // roughly the size of the content gzipped.\n // See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer for specific CSS/Script examples\n // See https://discuss.httparchive.org/t/file-size-and-compression-savings/145 for fallback multipliers\n switch (resourceType) {\n case 'Stylesheet':\n // Stylesheets tend to compress extremely well.\n return Math.round(totalBytes * 0.2);\n case 'Script':\n case 'Document':\n // Scripts and HTML compress fairly well too.\n return Math.round(totalBytes * 0.33);\n default:\n // Otherwise we'll just fallback to the average savings in HTTPArchive\n return Math.round(totalBytes * 0.5);\n }\n }\n\n // Get the size of the response body on the network.\n const {transferSize, resourceSize} = getRequestSizes(request);\n let contentTransferSize = transferSize;\n if (!isRequestCompressed(request)) {\n // This is not compressed, so we can use resourceSize directly.\n // This would be equivalent to transfer size minus headers transfer size, but transfer size\n // may also include bytes for SSL connection etc.\n contentTransferSize = resourceSize;\n }\n // TODO(cjamcl): Get \"responseHeadersTransferSize\" in Network handler.\n // else if (request.responseHeadersTransferSize) {\n // // Subtract the size of the encoded headers.\n // contentTransferSize =\n // Math.max(0, contentTransferSize - request.responseHeadersTransferSize);\n // }\n\n if (request.args.data.resourceType === resourceType) {\n // This was a regular standalone asset, just use the transfer size.\n return contentTransferSize;\n }\n\n // This was an asset that was inlined in a different resource type (e.g. HTML document).\n // Use the compression ratio of the resource to estimate the total transferred bytes.\n // Get the compression ratio, if it's an invalid number, assume no compression.\n const compressionRatio = Number.isFinite(resourceSize) && resourceSize > 0 ? (contentTransferSize / resourceSize) : 1;\n return Math.round(totalBytes * compressionRatio);\n}\n\n/**\n * Utility function to estimate the ratio of the compression of a script.\n * This excludes the size of the response headers.\n */\nexport function estimateCompressionRatioForScript(script: Handlers.ModelHandlers.Scripts.Script): number {\n if (!script.request) {\n // Can't find request, so just use 1.\n return 1;\n }\n\n const request = script.request;\n const contentLength = request.args.data.decodedBodyLength ?? script.content?.length ?? 0;\n const compressedSize = estimateCompressedContentSize(request, contentLength, Protocol.Network.ResourceType.Script);\n if (contentLength === 0 || compressedSize === 0) {\n return 1;\n }\n\n const compressionRatio = compressedSize / contentLength;\n return compressionRatio;\n}\n"]}