lighthouse 12.3.0-dev.20250205 → 12.3.0-dev.20250206

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 (53) hide show
  1. package/core/audits/audit.d.ts +5 -0
  2. package/core/audits/audit.js +11 -0
  3. package/core/audits/insights/README.md +3 -0
  4. package/core/audits/insights/cls-culprits-insight.d.ts +11 -0
  5. package/core/audits/insights/cls-culprits-insight.js +52 -0
  6. package/core/audits/insights/document-latency-insight.d.ts +11 -0
  7. package/core/audits/insights/document-latency-insight.js +47 -0
  8. package/core/audits/insights/dom-size-insight.d.ts +11 -0
  9. package/core/audits/insights/dom-size-insight.js +84 -0
  10. package/core/audits/insights/font-display-insight.d.ts +11 -0
  11. package/core/audits/insights/font-display-insight.js +52 -0
  12. package/core/audits/insights/forced-reflow-insight.d.ts +11 -0
  13. package/core/audits/insights/forced-reflow-insight.js +52 -0
  14. package/core/audits/insights/image-delivery-insight.d.ts +11 -0
  15. package/core/audits/insights/image-delivery-insight.js +52 -0
  16. package/core/audits/insights/insight-audit.d.ts +16 -0
  17. package/core/audits/insights/insight-audit.js +88 -0
  18. package/core/audits/insights/interaction-to-next-paint-insight.d.ts +11 -0
  19. package/core/audits/insights/interaction-to-next-paint-insight.js +52 -0
  20. package/core/audits/insights/lcp-discovery-insight.d.ts +11 -0
  21. package/core/audits/insights/lcp-discovery-insight.js +47 -0
  22. package/core/audits/insights/lcp-phases-insight.d.ts +11 -0
  23. package/core/audits/insights/lcp-phases-insight.js +52 -0
  24. package/core/audits/insights/long-critical-network-tree-insight.d.ts +11 -0
  25. package/core/audits/insights/long-critical-network-tree-insight.js +52 -0
  26. package/core/audits/insights/render-blocking-insight.d.ts +11 -0
  27. package/core/audits/insights/render-blocking-insight.js +56 -0
  28. package/core/audits/insights/slow-css-selector-insight.d.ts +11 -0
  29. package/core/audits/insights/slow-css-selector-insight.js +52 -0
  30. package/core/audits/insights/third-parties-insight.d.ts +11 -0
  31. package/core/audits/insights/third-parties-insight.js +52 -0
  32. package/core/audits/insights/viewport-insight.d.ts +11 -0
  33. package/core/audits/insights/viewport-insight.js +53 -0
  34. package/core/computed/metrics/lantern-metric.js +5 -1
  35. package/core/computed/trace-engine-result.d.ts +0 -4
  36. package/core/computed/trace-engine-result.js +0 -26
  37. package/core/config/default-config.js +35 -0
  38. package/core/gather/gatherers/trace-elements.d.ts +8 -0
  39. package/core/gather/gatherers/trace-elements.js +71 -1
  40. package/core/runner.js +2 -0
  41. package/dist/report/bundle.esm.js +38 -3
  42. package/dist/report/flow.js +40 -5
  43. package/dist/report/standalone.js +38 -3
  44. package/package.json +4 -3
  45. package/report/assets/styles.css +35 -0
  46. package/report/renderer/components.js +1 -1
  47. package/report/renderer/details-renderer.d.ts +5 -0
  48. package/report/renderer/details-renderer.js +21 -0
  49. package/report/renderer/performance-category-renderer.js +24 -9
  50. package/shared/localization/locales/en-US.json +213 -0
  51. package/shared/localization/locales/en-XL.json +213 -0
  52. package/types/artifacts.d.ts +1 -1
  53. package/types/lhr/audit-details.d.ts +6 -0
@@ -66,6 +66,11 @@ export class Audit {
66
66
  * @param {LH.Audit.Details.Opportunity['items']|LH.Audit.Details.Table['items']} items
67
67
  */
68
68
  static assertHeadingKeysExist(headings: LH.Audit.Details.Table["headings"] | LH.Audit.Details.Opportunity["headings"], items: LH.Audit.Details.Opportunity["items"] | LH.Audit.Details.Table["items"]): void;
69
+ /**
70
+ * @param {LH.Audit.Details.Checklist['items']} items
71
+ * @return {LH.Audit.Details.Checklist}
72
+ */
73
+ static makeChecklistDetails(items: LH.Audit.Details.Checklist["items"]): LH.Audit.Details.Checklist;
69
74
  /**
70
75
  * @param {LH.Audit.Details.Table['headings']} headings
71
76
  * @param {LH.Audit.Details.Table['items']} results
@@ -140,6 +140,17 @@ class Audit {
140
140
  }
141
141
  }
142
142
 
143
+ /**
144
+ * @param {LH.Audit.Details.Checklist['items']} items
145
+ * @return {LH.Audit.Details.Checklist}
146
+ */
147
+ static makeChecklistDetails(items) {
148
+ return {
149
+ type: 'checklist',
150
+ items,
151
+ };
152
+ }
153
+
143
154
  /**
144
155
  * @param {LH.Audit.Details.Table['headings']} headings
145
156
  * @param {LH.Audit.Details.Table['items']} results
@@ -0,0 +1,3 @@
1
+ # Insight audits
2
+
3
+ When adding new insight audits, you can start off by just running `yarn generate-insight-audits`
@@ -0,0 +1,11 @@
1
+ export default CLSCulpritsInsight;
2
+ declare class CLSCulpritsInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=cls-culprits-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/CLSCulprits.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js', UIStrings);
17
+
18
+ class CLSCulpritsInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'cls-culprits-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'CLSCulprits', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default CLSCulpritsInsight;
@@ -0,0 +1,11 @@
1
+ export default DocumentLatencyInsight;
2
+ declare class DocumentLatencyInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=document-latency-insight.d.ts.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/DocumentLatency.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js', UIStrings);
15
+
16
+ class DocumentLatencyInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'document-latency-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ };
29
+ }
30
+
31
+ /**
32
+ * @param {LH.Artifacts} artifacts
33
+ * @param {LH.Audit.Context} context
34
+ * @return {Promise<LH.Audit.Product>}
35
+ */
36
+ static async audit(artifacts, context) {
37
+ return adaptInsightToAuditProduct(artifacts, context, 'DocumentLatency', (insight) => {
38
+ if (!insight.data) {
39
+ return;
40
+ }
41
+
42
+ return Audit.makeChecklistDetails(insight.data.checklist);
43
+ });
44
+ }
45
+ }
46
+
47
+ export default DocumentLatencyInsight;
@@ -0,0 +1,11 @@
1
+ export default DOMSizeInsight;
2
+ declare class DOMSizeInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=dom-size-insight.d.ts.map
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/DOMSize.js';
8
+
9
+ import {Audit} from '../audit.js';
10
+ import * as i18n from '../../lib/i18n/i18n.js';
11
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
+
13
+ // eslint-disable-next-line max-len
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/DOMSize.js', UIStrings);
15
+
16
+ class DOMSizeInsight extends Audit {
17
+ /**
18
+ * @return {LH.Audit.Meta}
19
+ */
20
+ static get meta() {
21
+ return {
22
+ id: 'dom-size-insight',
23
+ title: str_(UIStrings.title),
24
+ failureTitle: str_(UIStrings.title),
25
+ description: str_(UIStrings.description),
26
+ guidanceLevel: 3,
27
+ requiredArtifacts: ['traces', 'TraceElements'],
28
+ };
29
+ }
30
+
31
+ /**
32
+ * @param {LH.Artifacts} artifacts
33
+ * @param {LH.Audit.Context} context
34
+ * @return {Promise<LH.Audit.Product>}
35
+ */
36
+ static async audit(artifacts, context) {
37
+ return adaptInsightToAuditProduct(artifacts, context, 'DOMSize', (insight) => {
38
+ if (!insight.maxDOMStats?.args.data.maxChildren || !insight.maxDOMStats?.args.data.maxDepth) {
39
+ return;
40
+ }
41
+
42
+ const {totalElements, maxChildren, maxDepth} = insight.maxDOMStats.args.data;
43
+
44
+ /** @type {LH.Audit.Details.Table['headings']} */
45
+ const headings = [
46
+ {key: 'statistic', valueType: 'text', label: str_(UIStrings.statistic)},
47
+ {key: 'node', valueType: 'node', label: str_(UIStrings.element)},
48
+ {key: 'value', valueType: 'numeric', label: str_(UIStrings.value)},
49
+ ];
50
+ /** @type {LH.Audit.Details.Table['items']} */
51
+ const items = [
52
+ {
53
+ statistic: str_(UIStrings.totalElements),
54
+ value: {
55
+ type: 'numeric',
56
+ granularity: 1,
57
+ value: totalElements,
58
+ },
59
+ },
60
+ {
61
+ statistic: str_(UIStrings.maxChildren),
62
+ node: makeNodeItemForNodeId(artifacts.TraceElements, maxChildren.nodeId),
63
+ value: {
64
+ type: 'numeric',
65
+ granularity: 1,
66
+ value: maxChildren.numChildren,
67
+ },
68
+ },
69
+ {
70
+ statistic: str_(UIStrings.maxDOMDepth),
71
+ node: makeNodeItemForNodeId(artifacts.TraceElements, maxDepth.nodeId),
72
+ value: {
73
+ type: 'numeric',
74
+ granularity: 1,
75
+ value: maxDepth.depth,
76
+ },
77
+ },
78
+ ];
79
+ return Audit.makeTableDetails(headings, items);
80
+ });
81
+ }
82
+ }
83
+
84
+ export default DOMSizeInsight;
@@ -0,0 +1,11 @@
1
+ export default FontDisplayInsight;
2
+ declare class FontDisplayInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=font-display-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/FontDisplay.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js', UIStrings);
17
+
18
+ class FontDisplayInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'font-display-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'FontDisplay', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default FontDisplayInsight;
@@ -0,0 +1,11 @@
1
+ export default ForcedReflowInsight;
2
+ declare class ForcedReflowInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=forced-reflow-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ForcedReflow.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js', UIStrings);
17
+
18
+ class ForcedReflowInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'forced-reflow-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'ForcedReflow', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default ForcedReflowInsight;
@@ -0,0 +1,11 @@
1
+ export default ImageDeliveryInsight;
2
+ declare class ImageDeliveryInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=image-delivery-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/ImageDelivery.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/ImageDelivery.js', UIStrings);
17
+
18
+ class ImageDeliveryInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'image-delivery-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'ImageDelivery', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default ImageDeliveryInsight;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @param {LH.Artifacts} artifacts
3
+ * @param {LH.Audit.Context} context
4
+ * @param {T} insightName
5
+ * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
6
+ * @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
7
+ * @return {Promise<LH.Audit.Product>}
8
+ */
9
+ export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T]) => LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
10
+ /**
11
+ * @param {LH.Artifacts.TraceElement[]} traceElements
12
+ * @param {number|null|undefined} nodeId
13
+ * @return {LH.Audit.Details.NodeValue|undefined}
14
+ */
15
+ export function makeNodeItemForNodeId(traceElements: LH.Artifacts.TraceElement[], nodeId: number | null | undefined): LH.Audit.Details.NodeValue | undefined;
16
+ //# sourceMappingURL=insight-audit.d.ts.map
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {NO_NAVIGATION} from '@paulirish/trace_engine/models/trace/types/TraceEvents.js';
8
+
9
+ import {ProcessedTrace} from '../../computed/processed-trace.js';
10
+ import {TraceEngineResult} from '../../computed/trace-engine-result.js';
11
+ import {Audit} from '../audit.js';
12
+
13
+ /**
14
+ * @param {LH.Artifacts} artifacts
15
+ * @param {LH.Audit.Context} context
16
+ * @return {Promise<import('@paulirish/trace_engine/models/trace/insights/types.js').InsightSet|undefined>}
17
+ */
18
+ async function getInsightSet(artifacts, context) {
19
+ const trace = artifacts.traces[Audit.DEFAULT_PASS];
20
+ const processedTrace = await ProcessedTrace.request(trace, context);
21
+ const traceEngineResult = await TraceEngineResult.request({trace}, context);
22
+
23
+ const navigationId = processedTrace.timeOriginEvt.args.data?.navigationId;
24
+ const key = navigationId ?? NO_NAVIGATION;
25
+
26
+ return traceEngineResult.insights.get(key);
27
+ }
28
+
29
+ /**
30
+ * @param {LH.Artifacts} artifacts
31
+ * @param {LH.Audit.Context} context
32
+ * @param {T} insightName
33
+ * @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T]) => LH.Audit.Details|undefined} createDetails
34
+ * @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
35
+ * @return {Promise<LH.Audit.Product>}
36
+ */
37
+ async function adaptInsightToAuditProduct(artifacts, context, insightName, createDetails) {
38
+ const insights = await getInsightSet(artifacts, context);
39
+ if (!insights) {
40
+ return {
41
+ scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
42
+ score: null,
43
+ };
44
+ }
45
+
46
+ const insight = insights.model[insightName];
47
+ const details = createDetails(insight);
48
+ if (!details || (details.type === 'table' && details.headings.length === 0)) {
49
+ return {
50
+ scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
51
+ score: null,
52
+ };
53
+ }
54
+
55
+ return {
56
+ scoreDisplayMode:
57
+ insight.metricSavings ? Audit.SCORING_MODES.METRIC_SAVINGS : Audit.SCORING_MODES.NUMERIC,
58
+ score: insight.shouldShow ? 0 : 1,
59
+ metricSavings: insight.metricSavings,
60
+ warnings: insight.warnings,
61
+ details,
62
+ };
63
+ }
64
+
65
+ /**
66
+ * @param {LH.Artifacts.TraceElement[]} traceElements
67
+ * @param {number|null|undefined} nodeId
68
+ * @return {LH.Audit.Details.NodeValue|undefined}
69
+ */
70
+ function makeNodeItemForNodeId(traceElements, nodeId) {
71
+ if (typeof nodeId !== 'number') {
72
+ return;
73
+ }
74
+
75
+ const traceElement =
76
+ traceElements.find(te => te.traceEventType === 'trace-engine' && te.nodeId === nodeId);
77
+ const node = traceElement?.node;
78
+ if (!node) {
79
+ return;
80
+ }
81
+
82
+ return Audit.makeNodeItem(node);
83
+ }
84
+
85
+ export {
86
+ adaptInsightToAuditProduct,
87
+ makeNodeItemForNodeId,
88
+ };
@@ -0,0 +1,11 @@
1
+ export default InteractionToNextPaintInsight;
2
+ declare class InteractionToNextPaintInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=interaction-to-next-paint-insight.d.ts.map
@@ -0,0 +1,52 @@
1
+ /* eslint-disable no-unused-vars */ // TODO: remove once implemented.
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2025 Google LLC
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js';
10
+
11
+ import {Audit} from '../audit.js';
12
+ import * as i18n from '../../lib/i18n/i18n.js';
13
+ import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
14
+
15
+ // eslint-disable-next-line max-len
16
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js', UIStrings);
17
+
18
+ class InteractionToNextPaintInsight extends Audit {
19
+ /**
20
+ * @return {LH.Audit.Meta}
21
+ */
22
+ static get meta() {
23
+ return {
24
+ id: 'interaction-to-next-paint-insight',
25
+ title: str_(UIStrings.title),
26
+ failureTitle: str_(UIStrings.title),
27
+ description: str_(UIStrings.description),
28
+ guidanceLevel: 3,
29
+ requiredArtifacts: ['traces', 'TraceElements'],
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @param {LH.Artifacts} artifacts
35
+ * @param {LH.Audit.Context} context
36
+ * @return {Promise<LH.Audit.Product>}
37
+ */
38
+ static async audit(artifacts, context) {
39
+ // TODO: implement.
40
+ return adaptInsightToAuditProduct(artifacts, context, 'InteractionToNextPaint', (insight) => {
41
+ /** @type {LH.Audit.Details.Table['headings']} */
42
+ const headings = [
43
+ ];
44
+ /** @type {LH.Audit.Details.Table['items']} */
45
+ const items = [
46
+ ];
47
+ return Audit.makeTableDetails(headings, items);
48
+ });
49
+ }
50
+ }
51
+
52
+ export default InteractionToNextPaintInsight;
@@ -0,0 +1,11 @@
1
+ export default LCPDiscoveryInsight;
2
+ declare class LCPDiscoveryInsight extends Audit {
3
+ /**
4
+ * @param {LH.Artifacts} artifacts
5
+ * @param {LH.Audit.Context} context
6
+ * @return {Promise<LH.Audit.Product>}
7
+ */
8
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
+ }
10
+ import { Audit } from '../audit.js';
11
+ //# sourceMappingURL=lcp-discovery-insight.d.ts.map