lighthouse 12.6.1-dev.20250624 → 12.6.1-dev.20250626

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 (71) hide show
  1. package/core/audits/insights/cache-insight.js +2 -1
  2. package/core/audits/insights/cls-culprits-insight.js +2 -2
  3. package/core/audits/insights/{interaction-to-next-paint-insight.d.ts → inp-breakdown-insight.d.ts} +3 -3
  4. package/core/audits/insights/{interaction-to-next-paint-insight.js → inp-breakdown-insight.js} +10 -10
  5. package/core/audits/insights/insight-audit.js +29 -0
  6. package/core/audits/insights/lcp-breakdown-insight.d.ts +16 -0
  7. package/core/audits/insights/{lcp-phases-insight.js → lcp-breakdown-insight.js} +19 -19
  8. package/core/audits/layout-shifts.js +1 -1
  9. package/core/config/default-config.js +4 -4
  10. package/core/config/experimental-config.js +2 -2
  11. package/core/config/validation.js +4 -0
  12. package/core/gather/gatherers/inspector-issues.js +1 -1
  13. package/core/scoring.d.ts +6 -0
  14. package/dist/report/bundle.esm.js +2 -2
  15. package/dist/report/flow.js +6 -6
  16. package/dist/report/standalone.js +2 -2
  17. package/package.json +5 -5
  18. package/report/renderer/dom.d.ts +1 -0
  19. package/report/renderer/dom.js +2 -0
  20. package/report/renderer/report-ui-features.d.ts +1 -0
  21. package/report/renderer/report-ui-features.js +16 -0
  22. package/shared/localization/locales/ar-XB.json +0 -57
  23. package/shared/localization/locales/ar.json +0 -57
  24. package/shared/localization/locales/bg.json +0 -57
  25. package/shared/localization/locales/ca.json +0 -57
  26. package/shared/localization/locales/cs.json +0 -57
  27. package/shared/localization/locales/da.json +0 -57
  28. package/shared/localization/locales/de.json +0 -57
  29. package/shared/localization/locales/el.json +0 -57
  30. package/shared/localization/locales/en-GB.json +0 -57
  31. package/shared/localization/locales/en-US.json +61 -49
  32. package/shared/localization/locales/en-XL.json +61 -49
  33. package/shared/localization/locales/es-419.json +0 -57
  34. package/shared/localization/locales/es.json +0 -57
  35. package/shared/localization/locales/fi.json +0 -57
  36. package/shared/localization/locales/fil.json +0 -57
  37. package/shared/localization/locales/fr.json +0 -57
  38. package/shared/localization/locales/he.json +0 -57
  39. package/shared/localization/locales/hi.json +0 -57
  40. package/shared/localization/locales/hr.json +0 -57
  41. package/shared/localization/locales/hu.json +0 -57
  42. package/shared/localization/locales/id.json +0 -57
  43. package/shared/localization/locales/it.json +0 -57
  44. package/shared/localization/locales/ja.json +0 -57
  45. package/shared/localization/locales/ko.json +0 -57
  46. package/shared/localization/locales/lt.json +0 -57
  47. package/shared/localization/locales/lv.json +0 -57
  48. package/shared/localization/locales/nl.json +0 -57
  49. package/shared/localization/locales/no.json +0 -57
  50. package/shared/localization/locales/pl.json +0 -57
  51. package/shared/localization/locales/pt-PT.json +0 -57
  52. package/shared/localization/locales/pt.json +0 -57
  53. package/shared/localization/locales/ro.json +0 -57
  54. package/shared/localization/locales/ru.json +0 -57
  55. package/shared/localization/locales/sk.json +0 -57
  56. package/shared/localization/locales/sl.json +0 -57
  57. package/shared/localization/locales/sr-Latn.json +0 -57
  58. package/shared/localization/locales/sr.json +0 -57
  59. package/shared/localization/locales/sv.json +0 -57
  60. package/shared/localization/locales/ta.json +0 -57
  61. package/shared/localization/locales/te.json +0 -57
  62. package/shared/localization/locales/th.json +0 -57
  63. package/shared/localization/locales/tr.json +0 -57
  64. package/shared/localization/locales/uk.json +0 -57
  65. package/shared/localization/locales/vi.json +0 -57
  66. package/shared/localization/locales/zh-HK.json +0 -57
  67. package/shared/localization/locales/zh-TW.json +0 -57
  68. package/shared/localization/locales/zh.json +0 -57
  69. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -1
  70. package/types/lhr/audit-details.d.ts +1 -0
  71. package/core/audits/insights/lcp-phases-insight.d.ts +0 -16
@@ -41,7 +41,7 @@ class CacheInsight extends Audit {
41
41
  /* eslint-disable max-len */
42
42
  {key: 'url', valueType: 'url', label: str_(UIStrings.requestColumn)},
43
43
  {key: 'cacheLifetimeMs', valueType: 'ms', label: str_(UIStrings.cacheTTL), displayUnit: 'duration'},
44
- {key: 'wastedBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
44
+ {key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
45
45
  /* eslint-enable max-len */
46
46
  ];
47
47
  // TODO: this should be the sorting in the model (instead it sorts by transfer size...)
@@ -50,6 +50,7 @@ class CacheInsight extends Audit {
50
50
  const items = values.map(value => ({
51
51
  url: value.request.args.data.url,
52
52
  cacheLifetimeMs: value.ttl * 1000,
53
+ totalBytes: value.request.args.data.encodedDataLength || 0,
53
54
  wastedBytes: value.wastedBytes,
54
55
  }));
55
56
  return Audit.makeTableDetails(headings, items, {
@@ -62,11 +62,11 @@ class CLSCulpritsInsight extends Audit {
62
62
  cause: insightStr_(InsightUIStrings.unsizedImage),
63
63
  });
64
64
  }
65
- for (const request of culprits.fontRequests) {
65
+ for (const request of culprits.webFonts) {
66
66
  const url = request.args.data.url;
67
67
  subItems.push({
68
68
  extra: {type: 'url', value: url},
69
- cause: insightStr_(InsightUIStrings.fontRequest),
69
+ cause: insightStr_(InsightUIStrings.webFont),
70
70
  });
71
71
  }
72
72
  for (const iframe of culprits.iframes) {
@@ -1,5 +1,5 @@
1
- export default InteractionToNextPaintInsight;
2
- declare class InteractionToNextPaintInsight extends Audit {
1
+ export default INPBreakdownInsight;
2
+ declare class INPBreakdownInsight extends Audit {
3
3
  /**
4
4
  * @param {LH.Artifacts} artifacts
5
5
  * @param {LH.Audit.Context} context
@@ -8,4 +8,4 @@ declare class InteractionToNextPaintInsight extends Audit {
8
8
  static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
9
9
  }
10
10
  import { Audit } from '../audit.js';
11
- //# sourceMappingURL=interaction-to-next-paint-insight.d.ts.map
11
+ //# sourceMappingURL=inp-breakdown-insight.d.ts.map
@@ -4,22 +4,22 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js';
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/INPBreakdown.js';
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
11
  import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
- const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/InteractionToNextPaint.js', UIStrings);
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/INPBreakdown.js', UIStrings);
15
15
 
16
- class InteractionToNextPaintInsight extends Audit {
16
+ class INPBreakdownInsight extends Audit {
17
17
  /**
18
18
  * @return {LH.Audit.Meta}
19
19
  */
20
20
  static get meta() {
21
21
  return {
22
- id: 'interaction-to-next-paint-insight',
22
+ id: 'inp-breakdown-insight',
23
23
  title: str_(UIStrings.title),
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
@@ -35,7 +35,7 @@ class InteractionToNextPaintInsight extends Audit {
35
35
  * @return {Promise<LH.Audit.Product>}
36
36
  */
37
37
  static async audit(artifacts, context) {
38
- return adaptInsightToAuditProduct(artifacts, context, 'InteractionToNextPaint', (insight) => {
38
+ return adaptInsightToAuditProduct(artifacts, context, 'INPBreakdown', (insight) => {
39
39
  const event = insight.longestInteractionEvent;
40
40
  if (!event) {
41
41
  // TODO: show UIStrings.noInteractions?
@@ -44,16 +44,16 @@ class InteractionToNextPaintInsight extends Audit {
44
44
 
45
45
  /** @type {LH.Audit.Details.Table['headings']} */
46
46
  const headings = [
47
- {key: 'label', valueType: 'text', label: str_(UIStrings.phase)},
47
+ {key: 'label', valueType: 'text', label: str_(UIStrings.subpart)},
48
48
  {key: 'duration', valueType: 'ms', label: str_(i18n.UIStrings.columnDuration)},
49
49
  ];
50
50
 
51
51
  /** @type {LH.Audit.Details.Table['items']} */
52
52
  const items = [
53
53
  /* eslint-disable max-len */
54
- {phase: 'inputDelay', label: str_(UIStrings.inputDelay), duration: event.inputDelay / 1000},
55
- {phase: 'processingDuration', label: str_(UIStrings.processingDuration), duration: event.mainThreadHandling / 1000},
56
- {phase: 'presentationDelay', label: str_(UIStrings.presentationDelay), duration: event.presentationDelay / 1000},
54
+ {subpart: 'inputDelay', label: str_(UIStrings.inputDelay), duration: event.inputDelay / 1000},
55
+ {subpart: 'processingDuration', label: str_(UIStrings.processingDuration), duration: event.mainThreadHandling / 1000},
56
+ {subpart: 'presentationDelay', label: str_(UIStrings.presentationDelay), duration: event.presentationDelay / 1000},
57
57
  /* eslint-enable max-len */
58
58
  ];
59
59
 
@@ -65,4 +65,4 @@ class InteractionToNextPaintInsight extends Audit {
65
65
  }
66
66
  }
67
67
 
68
- export default InteractionToNextPaintInsight;
68
+ export default INPBreakdownInsight;
@@ -108,8 +108,37 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
108
108
  // TODO: consider adding a `estimatedSavingsText` to InsightModel, which can capture
109
109
  // the exact i18n string used by RPP; and include the same est. timing savings.
110
110
  let displayValue;
111
+
111
112
  if (insight.wastedBytes) {
112
113
  displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes: insight.wastedBytes});
114
+ } else {
115
+ let wastedMs;
116
+
117
+ switch (insight.insightKey) {
118
+ case 'DocumentLatency':
119
+ case 'DuplicatedJavaScript':
120
+ case 'FontDisplay':
121
+ case 'LegacyJavaScript':
122
+ case 'RenderBlocking': {
123
+ wastedMs = metricSavings?.FCP;
124
+ break;
125
+ }
126
+
127
+ case 'LCPDiscovery':
128
+ case 'ModernHTTP': {
129
+ wastedMs = metricSavings?.LCP;
130
+ break;
131
+ }
132
+
133
+ case 'Viewport': {
134
+ wastedMs = metricSavings?.INP;
135
+ break;
136
+ }
137
+ }
138
+
139
+ if (wastedMs) {
140
+ displayValue = str_(i18n.UIStrings.displayValueMsSavings, {wastedMs});
141
+ }
113
142
  }
114
143
 
115
144
  let score;
@@ -0,0 +1,16 @@
1
+ export default LCPBreakdownInsight;
2
+ declare class LCPBreakdownInsight extends Audit {
3
+ /**
4
+ * @param {Required<import('@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js').LCPBreakdownInsightModel>['subparts']} subparts
5
+ * @return {LH.Audit.Details.Table}
6
+ */
7
+ static makeSubpartsTable(subparts: Required<import("@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js").LCPBreakdownInsightModel>["subparts"]): LH.Audit.Details.Table;
8
+ /**
9
+ * @param {LH.Artifacts} artifacts
10
+ * @param {LH.Audit.Context} context
11
+ * @return {Promise<LH.Audit.Product>}
12
+ */
13
+ static audit(artifacts: LH.Artifacts, context: LH.Audit.Context): Promise<LH.Audit.Product>;
14
+ }
15
+ import { Audit } from '../audit.js';
16
+ //# sourceMappingURL=lcp-breakdown-insight.d.ts.map
@@ -4,22 +4,22 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPPhases.js';
7
+ import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js';
8
8
 
9
9
  import {Audit} from '../audit.js';
10
10
  import * as i18n from '../../lib/i18n/i18n.js';
11
11
  import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
12
12
 
13
13
  // eslint-disable-next-line max-len
14
- const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPPhases.js', UIStrings);
14
+ const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js', UIStrings);
15
15
 
16
- class LCPPhasesInsight extends Audit {
16
+ class LCPBreakdownInsight extends Audit {
17
17
  /**
18
18
  * @return {LH.Audit.Meta}
19
19
  */
20
20
  static get meta() {
21
21
  return {
22
- id: 'lcp-phases-insight',
22
+ id: 'lcp-breakdown-insight',
23
23
  title: str_(UIStrings.title),
24
24
  failureTitle: str_(UIStrings.title),
25
25
  description: str_(UIStrings.description),
@@ -30,33 +30,33 @@ class LCPPhasesInsight extends Audit {
30
30
  }
31
31
 
32
32
  /**
33
- * @param {Required<import('@paulirish/trace_engine/models/trace/insights/LCPPhases.js').LCPPhasesInsightModel>['phases']} phases
33
+ * @param {Required<import('@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js').LCPBreakdownInsightModel>['subparts']} subparts
34
34
  * @return {LH.Audit.Details.Table}
35
35
  */
36
- static makePhaseTable(phases) {
37
- const {ttfb, loadDelay, loadTime, renderDelay} = phases;
36
+ static makeSubpartsTable(subparts) {
37
+ const {ttfb, loadDelay, loadDuration, renderDelay} = subparts;
38
38
 
39
39
  /** @type {LH.Audit.Details.Table['headings']} */
40
40
  const headings = [
41
- {key: 'label', valueType: 'text', label: str_(UIStrings.phase)},
41
+ {key: 'label', valueType: 'text', label: str_(UIStrings.subpart)},
42
42
  {key: 'duration', valueType: 'ms', label: str_(i18n.UIStrings.columnDuration)},
43
43
  ];
44
44
 
45
45
  /** @type {LH.Audit.Details.Table['items']} */
46
46
  let items = [
47
47
  /* eslint-disable max-len */
48
- {phase: 'timeToFirstByte', label: str_(UIStrings.timeToFirstByte), duration: ttfb},
49
- {phase: 'resourceLoadDelay', label: str_(UIStrings.resourceLoadDelay), duration: loadDelay},
50
- {phase: 'resourceLoadDuration', label: str_(UIStrings.resourceLoadDuration), duration: loadTime},
51
- {phase: 'elementRenderDelay', label: str_(UIStrings.elementRenderDelay), duration: renderDelay},
48
+ {subpart: 'timeToFirstByte', label: str_(UIStrings.timeToFirstByte), duration: ttfb.range / 1000},
49
+ {subpart: 'resourceLoadDelay', label: str_(UIStrings.resourceLoadDelay), duration: (loadDelay?.range ?? 0) / 1000},
50
+ {subpart: 'resourceLoadDuration', label: str_(UIStrings.resourceLoadDuration), duration: (loadDuration?.range ?? 0) / 1000},
51
+ {subpart: 'elementRenderDelay', label: str_(UIStrings.elementRenderDelay), duration: renderDelay.range / 1000},
52
52
  /* eslint-enable max-len */
53
53
  ];
54
54
 
55
55
  if (loadDelay === undefined) {
56
- items = items.filter(item => item.phase !== 'resourceLoadDelay');
56
+ items = items.filter(item => item.subpart !== 'resourceLoadDelay');
57
57
  }
58
- if (loadTime === undefined) {
59
- items = items.filter(item => item.phase !== 'resourceLoadDuration');
58
+ if (loadDuration === undefined) {
59
+ items = items.filter(item => item.subpart !== 'resourceLoadDuration');
60
60
  }
61
61
 
62
62
  return Audit.makeTableDetails(headings, items);
@@ -68,17 +68,17 @@ class LCPPhasesInsight extends Audit {
68
68
  * @return {Promise<LH.Audit.Product>}
69
69
  */
70
70
  static async audit(artifacts, context) {
71
- return adaptInsightToAuditProduct(artifacts, context, 'LCPPhases', (insight) => {
72
- if (!insight.phases) {
71
+ return adaptInsightToAuditProduct(artifacts, context, 'LCPBreakdown', (insight) => {
72
+ if (!insight.subparts) {
73
73
  return;
74
74
  }
75
75
 
76
76
  return Audit.makeListDetails([
77
- LCPPhasesInsight.makePhaseTable(insight.phases),
77
+ LCPBreakdownInsight.makeSubpartsTable(insight.subparts),
78
78
  makeNodeItemForNodeId(artifacts.TraceElements, insight.lcpEvent?.args.data?.nodeId),
79
79
  ].filter(table => table !== undefined));
80
80
  });
81
81
  }
82
82
  }
83
83
 
84
- export default LCPPhasesInsight;
84
+ export default LCPBreakdownInsight;
@@ -105,7 +105,7 @@ class LayoutShifts extends Audit {
105
105
  cause: str_(UIStrings.rootCauseUnsizedMedia),
106
106
  });
107
107
  }
108
- for (const request of rootCauses.fontRequests) {
108
+ for (const request of rootCauses.webFonts) {
109
109
  const url = request.args.data.url;
110
110
  subItems.push({
111
111
  extra: {type: 'url', value: url},
@@ -319,9 +319,9 @@ const defaultConfig = {
319
319
  'insights/font-display-insight',
320
320
  'insights/forced-reflow-insight',
321
321
  'insights/image-delivery-insight',
322
- 'insights/interaction-to-next-paint-insight',
322
+ 'insights/inp-breakdown-insight',
323
+ 'insights/lcp-breakdown-insight',
323
324
  'insights/lcp-discovery-insight',
324
- 'insights/lcp-phases-insight',
325
325
  'insights/legacy-javascript-insight',
326
326
  'insights/modern-http-insight',
327
327
  'insights/network-dependency-tree-insight',
@@ -421,9 +421,9 @@ const defaultConfig = {
421
421
  {id: 'font-display-insight', weight: 0, group: 'hidden'},
422
422
  {id: 'forced-reflow-insight', weight: 0, group: 'hidden'},
423
423
  {id: 'image-delivery-insight', weight: 0, group: 'hidden'},
424
- {id: 'interaction-to-next-paint-insight', weight: 0, group: 'hidden'},
424
+ {id: 'inp-breakdown-insight', weight: 0, group: 'hidden'},
425
+ {id: 'lcp-breakdown-insight', weight: 0, group: 'hidden'},
425
426
  {id: 'lcp-discovery-insight', weight: 0, group: 'hidden'},
426
- {id: 'lcp-phases-insight', weight: 0, group: 'hidden'},
427
427
  {id: 'legacy-javascript-insight', weight: 0, group: 'hidden'},
428
428
  {id: 'modern-http-insight', weight: 0, group: 'hidden'},
429
429
  {id: 'network-dependency-tree-insight', weight: 0, group: 'hidden'},
@@ -35,9 +35,9 @@ const config = {
35
35
  {id: 'font-display-insight', weight: 0, group: 'insights'},
36
36
  {id: 'forced-reflow-insight', weight: 0, group: 'insights'},
37
37
  {id: 'image-delivery-insight', weight: 0, group: 'insights'},
38
- {id: 'interaction-to-next-paint-insight', weight: 0, group: 'insights'},
38
+ {id: 'inp-breakdown-insight', weight: 0, group: 'insights'},
39
+ {id: 'lcp-breakdown-insight', weight: 0, group: 'insights'},
39
40
  {id: 'lcp-discovery-insight', weight: 0, group: 'insights'},
40
- {id: 'lcp-phases-insight', weight: 0, group: 'insights'},
41
41
  {id: 'legacy-javascript-insight', weight: 0, group: 'insights'},
42
42
  {id: 'modern-http-insight', weight: 0, group: 'insights'},
43
43
  {id: 'network-dependency-tree-insight', weight: 0, group: 'insights'},
@@ -36,6 +36,10 @@ function isValidArtifactDependency(dependent, dependency) {
36
36
  * @param {string} pluginName
37
37
  */
38
38
  function assertValidPluginName(config, pluginName) {
39
+ const parts = pluginName.split('/');
40
+ if (parts.length === 2) {
41
+ pluginName = parts[1];
42
+ }
39
43
  if (!pluginName.startsWith('lighthouse-plugin-')) {
40
44
  throw new Error(`plugin name '${pluginName}' does not start with 'lighthouse-plugin-'`);
41
45
  }
@@ -81,7 +81,7 @@ class InspectorIssues extends BaseGatherer {
81
81
  propertyRuleIssue: [],
82
82
  quirksModeIssue: [],
83
83
  cookieIssue: [],
84
- selectElementAccessibilityIssue: [],
84
+ elementAccessibilityIssue: [],
85
85
  sharedArrayBufferIssue: [],
86
86
  sharedDictionaryIssue: [],
87
87
  stylesheetLoadingIssue: [],
package/core/scoring.d.ts CHANGED
@@ -187,6 +187,7 @@ export class ReportScoring {
187
187
  line: number;
188
188
  column: number;
189
189
  } | undefined;
190
+ functionName?: string | import("./index.js").IcuMessage | undefined;
190
191
  } | {
191
192
  type: "link";
192
193
  text: string | import("./index.js").IcuMessage;
@@ -330,6 +331,7 @@ export class ReportScoring {
330
331
  line: number;
331
332
  column: number;
332
333
  } | undefined;
334
+ functionName?: string | import("./index.js").IcuMessage | undefined;
333
335
  } | {
334
336
  type: "link";
335
337
  text: string | import("./index.js").IcuMessage;
@@ -464,6 +466,7 @@ export class ReportScoring {
464
466
  line: number;
465
467
  column: number;
466
468
  } | undefined;
469
+ functionName?: string | import("./index.js").IcuMessage | undefined;
467
470
  } | {
468
471
  type: "link";
469
472
  text: string | import("./index.js").IcuMessage;
@@ -496,6 +499,7 @@ export class ReportScoring {
496
499
  line: number;
497
500
  column: number;
498
501
  } | undefined;
502
+ functionName?: string | import("./index.js").IcuMessage | undefined;
499
503
  } | {
500
504
  type: "link";
501
505
  text: string | import("./index.js").IcuMessage;
@@ -555,6 +559,7 @@ export class ReportScoring {
555
559
  line: number;
556
560
  column: number;
557
561
  } | undefined;
562
+ functionName?: string | import("./index.js").IcuMessage | undefined;
558
563
  } | {
559
564
  type: "link";
560
565
  text: string | import("./index.js").IcuMessage;
@@ -660,6 +665,7 @@ export class ReportScoring {
660
665
  line: number;
661
666
  column: number;
662
667
  } | undefined;
668
+ functionName?: string | import("./index.js").IcuMessage | undefined;
663
669
  } | {
664
670
  type: "link";
665
671
  text: string | import("./index.js").IcuMessage;