lighthouse 12.0.0-dev.20240611 → 12.0.0-dev.20240613

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 (111) hide show
  1. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  2. package/core/audits/byte-efficiency/byte-efficiency-audit.js +2 -2
  3. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
  4. package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
  5. package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
  6. package/core/audits/dobetterweb/uses-http2.js +2 -2
  7. package/core/audits/long-tasks.d.ts +1 -1
  8. package/core/audits/long-tasks.js +1 -1
  9. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  10. package/core/computed/document-urls.js +3 -2
  11. package/core/computed/load-simulator.d.ts +4 -4
  12. package/core/computed/load-simulator.js +3 -3
  13. package/core/computed/main-resource.js +3 -2
  14. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
  15. package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
  16. package/core/computed/metrics/lantern-interactive.d.ts +4 -4
  17. package/core/computed/metrics/lantern-interactive.js +3 -3
  18. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
  19. package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  20. package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
  21. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  22. package/core/computed/metrics/lantern-metric.d.ts +4 -3
  23. package/core/computed/metrics/lantern-metric.js +4 -4
  24. package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
  25. package/core/computed/metrics/lantern-speed-index.js +3 -3
  26. package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
  27. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  28. package/core/computed/metrics/total-blocking-time.js +3 -1
  29. package/core/computed/network-analysis.js +2 -2
  30. package/core/computed/page-dependency-graph.d.ts +2 -2
  31. package/core/computed/page-dependency-graph.js +6 -6
  32. package/core/computed/tbt-impact-tasks.js +3 -2
  33. package/core/config/constants.js +1 -1
  34. package/core/lib/asset-saver.js +2 -2
  35. package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
  36. package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
  37. package/core/lib/lantern/BaseNode.test.js +385 -0
  38. package/core/lib/lantern/{cpu-node.d.ts → CpuNode.d.ts} +8 -9
  39. package/core/lib/lantern/{cpu-node.js → CpuNode.js} +4 -5
  40. package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
  41. package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +17 -17
  42. package/core/lib/lantern/{metric.js → Metric.js} +10 -12
  43. package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +4 -5
  44. package/core/lib/lantern/{network-node.js → NetworkNode.js} +4 -5
  45. package/core/lib/lantern/{page-dependency-graph.d.ts → PageDependencyGraph.d.ts} +5 -5
  46. package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +11 -10
  47. package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
  48. package/core/lib/lantern/{tbt-utils.d.ts → TBTUtils.d.ts} +1 -1
  49. package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
  50. package/core/lib/lantern/TBTUtils.test.js +130 -0
  51. package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts} +3 -3
  52. package/core/lib/lantern/{trace-engine-computation-data.js → TraceEngineComputationData.js} +5 -7
  53. package/core/lib/lantern/lantern.d.ts +16 -46
  54. package/core/lib/lantern/lantern.js +16 -40
  55. package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
  56. package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +8 -10
  57. package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
  58. package/core/lib/lantern/metrics/{interactive.d.ts → Interactive.d.ts} +4 -5
  59. package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +10 -13
  60. package/core/lib/lantern/metrics/Interactive.test.js +56 -0
  61. package/core/lib/lantern/metrics/{largest-contentful-paint.d.ts → LargestContentfulPaint.d.ts} +5 -6
  62. package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +9 -12
  63. package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
  64. package/core/lib/lantern/metrics/{max-potential-fid.d.ts → MaxPotentialFID.d.ts} +5 -6
  65. package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +8 -9
  66. package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
  67. package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
  68. package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +5 -6
  69. package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +7 -9
  70. package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
  71. package/core/lib/lantern/metrics/{total-blocking-time.d.ts → TotalBlockingTime.d.ts} +5 -6
  72. package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +9 -12
  73. package/core/lib/lantern/metrics/__snapshots__/first-contentful-paint-test.js.snap +11 -0
  74. package/core/lib/lantern/metrics/__snapshots__/interactive-test.js.snap +17 -0
  75. package/core/lib/lantern/metrics/metrics.d.ts +9 -0
  76. package/core/lib/lantern/metrics/metrics.js +16 -0
  77. package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +5 -5
  78. package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +3 -3
  79. package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
  80. package/core/lib/lantern/simulation/Constants.d.ts +52 -0
  81. package/core/lib/lantern/simulation/Constants.js +48 -0
  82. package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +2 -2
  83. package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +1 -1
  84. package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
  85. package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +2 -2
  86. package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +1 -1
  87. package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
  88. package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
  89. package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
  90. package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +13 -15
  91. package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +25 -26
  92. package/core/lib/lantern/simulation/Simulator.test.js +434 -0
  93. package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
  94. package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
  95. package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
  96. package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
  97. package/core/lib/lantern/simulation/simulation.d.ts +21 -0
  98. package/core/lib/lantern/simulation/simulation.js +28 -0
  99. package/core/lib/lantern/types/lantern.d.ts +5 -5
  100. package/core/lib/lantern-trace-saver.d.ts +4 -4
  101. package/core/lib/lantern-trace-saver.js +2 -2
  102. package/core/lib/navigation-error.js +3 -3
  103. package/core/lib/network-recorder.js +2 -2
  104. package/core/lib/network-request.d.ts +1 -1
  105. package/core/lib/network-request.js +1 -1
  106. package/package.json +2 -2
  107. package/tsconfig.json +10 -8
  108. package/types/artifacts.d.ts +3 -4
  109. package/types/gatherer.d.ts +1 -1
  110. /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
  111. /package/core/lib/lantern/{tbt-utils.js → TBTUtils.js} +0 -0
@@ -4,14 +4,15 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as Lantern from '../lib/lantern/types/lantern.js';
7
+ import * as Lantern from '../lib/lantern/lantern.js';
8
8
  import {makeComputedArtifact} from './computed-artifact.js';
9
9
  import {MainThreadTasks} from './main-thread-tasks.js';
10
10
  import {FirstContentfulPaint} from './metrics/first-contentful-paint.js';
11
11
  import {Interactive} from './metrics/interactive.js';
12
12
  import {TotalBlockingTime} from './metrics/total-blocking-time.js';
13
13
  import {ProcessedTrace} from './processed-trace.js';
14
- import {calculateTbtImpactForEvent} from '../lib/lantern/tbt-utils.js';
14
+
15
+ const {calculateTbtImpactForEvent} = Lantern.TBTUtils;
15
16
 
16
17
  class TBTImpactTasks {
17
18
  /**
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as Lantern from '../lib/lantern/lantern.js';
8
8
 
9
- const throttling = Lantern.constants.throttling;
9
+ const throttling = Lantern.Simulation.Constants.throttling;
10
10
 
11
11
  /**
12
12
  * @type {Required<LH.SharedFlagsSettings['screenEmulation']>}
@@ -12,7 +12,7 @@ import {createGzip, gunzipSync} from 'zlib';
12
12
 
13
13
  import log from 'lighthouse-logger';
14
14
 
15
- import {Simulator} from './lantern/simulator/simulator.js';
15
+ import * as Lantern from './lantern/lantern.js';
16
16
  import lanternTraceSaver from './lantern-trace-saver.js';
17
17
  import {MetricTraceEvents} from './traces/metric-trace-events.js';
18
18
  import {NetworkAnalysis} from '../computed/network-analysis.js';
@@ -449,7 +449,7 @@ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename, options = {}) {
449
449
  async function saveLanternDebugTraces(pathWithBasename) {
450
450
  if (!process.env.LANTERN_DEBUG) return;
451
451
 
452
- for (const [label, nodeTimings] of Simulator.ALL_NODE_TIMINGS) {
452
+ for (const [label, nodeTimings] of Lantern.Simulation.Simulator.ALL_NODE_TIMINGS) {
453
453
  if (lanternTraceSaver.simulationNamesToIgnore.includes(label)) continue;
454
454
 
455
455
  const traceFilename = `${pathWithBasename}-${label}${traceSuffix}`;
@@ -2,7 +2,7 @@
2
2
  * A union of all types derived from BaseNode, allowing type check discrimination
3
3
  * based on `node.type`. If a new node type is created, it should be added here.
4
4
  */
5
- export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>;
5
+ export type Node<T = any> = import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>;
6
6
  /**
7
7
  * @license
8
8
  * Copyright 2017 Google LLC
@@ -12,7 +12,7 @@ export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./netwo
12
12
  * A union of all types derived from BaseNode, allowing type check discrimination
13
13
  * based on `node.type`. If a new node type is created, it should be added here.
14
14
  * @template [T=any]
15
- * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
15
+ * @typedef {import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>} Node
16
16
  */
17
17
  /**
18
18
  * @fileoverview This class encapsulates logic for handling resources and tasks used to model the
@@ -30,6 +30,10 @@ export type Node<T = any> = import('./cpu-node.js').CPUNode<T> | import('./netwo
30
30
  * @template [T=any]
31
31
  */
32
32
  export class BaseNode<T = any> {
33
+ static TYPES: {
34
+ NETWORK: 'network';
35
+ CPU: 'cpu';
36
+ };
33
37
  /**
34
38
  * Returns whether the given node has a cycle in its dependent graph by performing a DFS.
35
39
  * @param {Node} node
@@ -156,10 +160,4 @@ export class BaseNode<T = any> {
156
160
  */
157
161
  canDependOn(node: Node): boolean;
158
162
  }
159
- export namespace BaseNode {
160
- namespace TYPES {
161
- const NETWORK: 'network';
162
- const CPU: 'cpu';
163
- }
164
- }
165
- //# sourceMappingURL=base-node.d.ts.map
163
+ //# sourceMappingURL=BaseNode.d.ts.map
@@ -8,7 +8,7 @@
8
8
  * A union of all types derived from BaseNode, allowing type check discrimination
9
9
  * based on `node.type`. If a new node type is created, it should be added here.
10
10
  * @template [T=any]
11
- * @typedef {import('./cpu-node.js').CPUNode<T> | import('./network-node.js').NetworkNode<T>} Node
11
+ * @typedef {import('./CpuNode.js').CPUNode<T> | import('./NetworkNode.js').NetworkNode<T>} Node
12
12
  */
13
13
 
14
14
  /**
@@ -28,6 +28,11 @@
28
28
  * @template [T=any]
29
29
  */
30
30
  class BaseNode {
31
+ static TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({
32
+ NETWORK: 'network',
33
+ CPU: 'cpu',
34
+ });
35
+
31
36
  /**
32
37
  * @param {string} id
33
38
  */
@@ -361,9 +366,4 @@ class BaseNode {
361
366
  }
362
367
  }
363
368
 
364
- BaseNode.TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({
365
- NETWORK: 'network',
366
- CPU: 'cpu',
367
- });
368
-
369
369
  export {BaseNode};
@@ -0,0 +1,385 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2017 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import assert from 'assert/strict';
8
+
9
+ import * as Lantern from './lantern.js';
10
+
11
+ const {BaseNode, NetworkNode} = Lantern;
12
+
13
+ function sortedById(nodeArray) {
14
+ return nodeArray.sort((node1, node2) => node1.id.localeCompare(node2.id));
15
+ }
16
+
17
+ function createComplexGraph() {
18
+ // B F
19
+ // / \ /
20
+ // A D - E
21
+ // \ / \
22
+ // C G - H
23
+
24
+ const nodeA = new BaseNode('A');
25
+ const nodeB = new BaseNode('B');
26
+ const nodeC = new BaseNode('C');
27
+ const nodeD = new BaseNode('D');
28
+ const nodeE = new BaseNode('E');
29
+ const nodeF = new BaseNode('F');
30
+ const nodeG = new BaseNode('G');
31
+ const nodeH = new BaseNode('H');
32
+
33
+ nodeA.addDependent(nodeB);
34
+ nodeA.addDependent(nodeC);
35
+ nodeB.addDependent(nodeD);
36
+ nodeC.addDependent(nodeD);
37
+ nodeD.addDependent(nodeE);
38
+ nodeE.addDependent(nodeF);
39
+ nodeE.addDependent(nodeG);
40
+ nodeG.addDependent(nodeH);
41
+
42
+ return {
43
+ nodeA,
44
+ nodeB,
45
+ nodeC,
46
+ nodeD,
47
+ nodeE,
48
+ nodeF,
49
+ nodeG,
50
+ nodeH,
51
+ };
52
+ }
53
+ describe('DependencyGraph/Node', () => {
54
+ describe('#constructor', () => {
55
+ it('should set the ID', () => {
56
+ const node = new BaseNode('foo');
57
+ assert.equal(node.id, 'foo');
58
+ });
59
+ });
60
+
61
+ describe('.addDependent', () => {
62
+ it('should add the correct edge', () => {
63
+ const nodeA = new BaseNode(1);
64
+ const nodeB = new BaseNode(2);
65
+ nodeA.addDependent(nodeB);
66
+
67
+ assert.deepEqual(nodeA.getDependents(), [nodeB]);
68
+ assert.deepEqual(nodeB.getDependencies(), [nodeA]);
69
+ });
70
+ });
71
+
72
+ describe('.addDependency', () => {
73
+ it('should add the correct edge', () => {
74
+ const nodeA = new BaseNode(1);
75
+ const nodeB = new BaseNode(2);
76
+ nodeA.addDependency(nodeB);
77
+
78
+ assert.deepEqual(nodeA.getDependencies(), [nodeB]);
79
+ assert.deepEqual(nodeB.getDependents(), [nodeA]);
80
+ });
81
+
82
+ it('throw when trying to add a dependency on itself', () => {
83
+ const nodeA = new BaseNode(1);
84
+ expect(() => nodeA.addDependency(nodeA)).toThrow();
85
+ });
86
+ });
87
+
88
+ describe('.isDependentOn', () => {
89
+ it('should identify the dependency relationships', () => {
90
+ const graph = createComplexGraph();
91
+ const nodes = Object.values(graph);
92
+ const {nodeA, nodeB, nodeD, nodeF, nodeH} = graph;
93
+
94
+ for (const node of nodes) {
95
+ expect(nodeA.isDependentOn(node)).toBe(node === nodeA);
96
+ expect(nodeB.isDependentOn(node)).toBe(node === nodeA || node === nodeB);
97
+ expect(nodeH.isDependentOn(node)).toBe(node !== nodeF);
98
+ }
99
+
100
+ expect(nodeD.isDependentOn(nodeA)).toBe(true);
101
+ expect(nodeD.isDependentOn(nodeB)).toBe(true);
102
+ expect(nodeD.isDependentOn(nodeD)).toBe(true);
103
+
104
+ expect(nodeD.isDependentOn(nodeH)).toBe(false);
105
+ expect(nodeH.isDependentOn(nodeD)).toBe(true);
106
+
107
+ expect(nodeF.isDependentOn(nodeH)).toBe(false);
108
+ expect(nodeH.isDependentOn(nodeF)).toBe(false);
109
+ });
110
+ });
111
+
112
+ describe('.getRootNode', () => {
113
+ it('should return the root node', () => {
114
+ const graph = createComplexGraph();
115
+
116
+ assert.equal(graph.nodeA.getRootNode(), graph.nodeA);
117
+ assert.equal(graph.nodeB.getRootNode(), graph.nodeA);
118
+ assert.equal(graph.nodeD.getRootNode(), graph.nodeA);
119
+ assert.equal(graph.nodeF.getRootNode(), graph.nodeA);
120
+ });
121
+ });
122
+
123
+ describe('.cloneWithoutRelationships', () => {
124
+ it('should create a copy', () => {
125
+ const node = new BaseNode(1);
126
+ const neighbor = new BaseNode(2);
127
+ node.addDependency(neighbor);
128
+ const clone = node.cloneWithoutRelationships();
129
+
130
+ assert.equal(clone.id, 1);
131
+ assert.notEqual(node, clone);
132
+ assert.equal(clone.getDependencies().length, 0);
133
+ });
134
+
135
+ it('should copy isMainDocument', () => {
136
+ const node = new BaseNode(1);
137
+ node.setIsMainDocument(true);
138
+ const networkNode = new NetworkNode({});
139
+ networkNode.setIsMainDocument(true);
140
+
141
+ assert.ok(node.cloneWithoutRelationships().isMainDocument());
142
+ assert.ok(networkNode.cloneWithoutRelationships().isMainDocument());
143
+ });
144
+ });
145
+
146
+ describe('.cloneWithRelationships', () => {
147
+ it('should create a copy of a basic graph', () => {
148
+ const node = new BaseNode(1);
149
+ const neighbor = new BaseNode(2);
150
+ node.addDependency(neighbor);
151
+ const clone = node.cloneWithRelationships();
152
+
153
+ assert.equal(clone.id, 1);
154
+ assert.notEqual(node, clone);
155
+
156
+ const dependencies = clone.getDependencies();
157
+ assert.equal(dependencies.length, 1);
158
+
159
+ const neighborClone = dependencies[0];
160
+ assert.equal(neighborClone.id, neighbor.id);
161
+ assert.notEqual(neighborClone, neighbor);
162
+ assert.equal(neighborClone.getDependents()[0], clone);
163
+ });
164
+
165
+ it('should create a copy of a complex graph', () => {
166
+ const graph = createComplexGraph();
167
+ const clone = graph.nodeA.cloneWithRelationships();
168
+
169
+ const clonedIdMap = new Map();
170
+ clone.traverse(node => clonedIdMap.set(node.id, node));
171
+ assert.equal(clonedIdMap.size, 8);
172
+
173
+ graph.nodeA.traverse(node => {
174
+ const clone = clonedIdMap.get(node.id);
175
+ assert.equal(clone.id, node.id);
176
+ assert.notEqual(clone, node);
177
+
178
+ const actualDependents = sortedById(clone.getDependents());
179
+ const expectedDependents = sortedById(node.getDependents());
180
+ actualDependents.forEach((cloneDependent, index) => {
181
+ const originalDependent = expectedDependents[index];
182
+ assert.equal(cloneDependent.id, originalDependent.id);
183
+ assert.notEqual(cloneDependent, originalDependent);
184
+ });
185
+ });
186
+ });
187
+
188
+ it('should create a copy of a graph with long dependency chains', () => {
189
+ // C - D - E - F
190
+ // / \
191
+ // A - - - - - - - B
192
+ const nodeA = new BaseNode('A');
193
+ const nodeB = new BaseNode('B');
194
+ const nodeC = new BaseNode('C');
195
+ const nodeD = new BaseNode('D');
196
+ const nodeE = new BaseNode('E');
197
+ const nodeF = new BaseNode('F');
198
+
199
+ nodeA.addDependent(nodeB);
200
+ nodeF.addDependent(nodeB);
201
+
202
+ nodeA.addDependent(nodeC);
203
+ nodeC.addDependent(nodeD);
204
+ nodeD.addDependent(nodeE);
205
+ nodeE.addDependent(nodeF);
206
+
207
+ const clone = nodeA.cloneWithRelationships();
208
+
209
+ const clonedIdMap = new Map();
210
+ clone.traverse(node => clonedIdMap.set(node.id, node));
211
+ assert.equal(clonedIdMap.size, 6);
212
+ });
213
+
214
+ it('should create a copy when not starting at root node', () => {
215
+ const graph = createComplexGraph();
216
+ const cloneD = graph.nodeD.cloneWithRelationships();
217
+ assert.equal(cloneD.id, 'D');
218
+ assert.equal(cloneD.getRootNode().id, 'A');
219
+ });
220
+
221
+ it('should create a partial copy of a complex graph', () => {
222
+ const graph = createComplexGraph();
223
+ // create a clone with F and all its dependencies
224
+ const clone = graph.nodeA.cloneWithRelationships(node => node.id === 'F');
225
+
226
+ const clonedIdMap = new Map();
227
+ clone.traverse(node => clonedIdMap.set(node.id, node));
228
+
229
+ assert.equal(clonedIdMap.size, 6);
230
+ assert.ok(clonedIdMap.has('F'), 'did not include target node');
231
+ assert.ok(clonedIdMap.has('E'), 'did not include dependency');
232
+ assert.ok(clonedIdMap.has('B'), 'did not include branched dependency');
233
+ assert.ok(clonedIdMap.has('C'), 'did not include branched dependency');
234
+ assert.equal(clonedIdMap.get('G'), undefined);
235
+ assert.equal(clonedIdMap.get('H'), undefined);
236
+ });
237
+
238
+ it('should throw if original node is not in cloned graph', () => {
239
+ const graph = createComplexGraph();
240
+ assert.throws(
241
+ // clone from root to nodeB, but called on nodeD
242
+ _ => graph.nodeD.cloneWithRelationships(node => node.id === 'B'),
243
+ /^Error: Cloned graph missing node$/
244
+ );
245
+ });
246
+ });
247
+
248
+ describe('.traverse', () => {
249
+ it('should visit every dependent node', () => {
250
+ const graph = createComplexGraph();
251
+ const ids = [];
252
+ graph.nodeA.traverse(node => ids.push(node.id));
253
+
254
+ assert.deepEqual(ids, ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']);
255
+ });
256
+
257
+ it('should include a shortest traversal path to every dependent node', () => {
258
+ const graph = createComplexGraph();
259
+ const paths = [];
260
+ graph.nodeA.traverse((node, traversalPath) => {
261
+ assert.strictEqual(node.id, traversalPath[0].id);
262
+ paths.push(traversalPath.map(node => node.id));
263
+ });
264
+
265
+ assert.deepStrictEqual(paths, [
266
+ ['A'],
267
+ ['B', 'A'],
268
+ ['C', 'A'],
269
+ ['D', 'B', 'A'],
270
+ ['E', 'D', 'B', 'A'],
271
+ ['F', 'E', 'D', 'B', 'A'],
272
+ ['G', 'E', 'D', 'B', 'A'],
273
+ ['H', 'G', 'E', 'D', 'B', 'A'],
274
+ ]);
275
+ });
276
+
277
+ it('should respect getNext', () => {
278
+ const graph = createComplexGraph();
279
+ const ids = [];
280
+ graph.nodeF.traverse(
281
+ node => ids.push(node.id),
282
+ node => node.getDependencies()
283
+ );
284
+
285
+ assert.deepEqual(ids, ['F', 'E', 'D', 'B', 'C', 'A']);
286
+ });
287
+ });
288
+
289
+ describe('#hasCycle', () => {
290
+ it('should return false for DAGs', () => {
291
+ const graph = createComplexGraph();
292
+ assert.equal(BaseNode.hasCycle(graph.nodeA), false);
293
+ });
294
+
295
+ it('should return false for triangular DAGs', () => {
296
+ // B
297
+ // / \
298
+ // A - C
299
+ const nodeA = new BaseNode('A');
300
+ const nodeB = new BaseNode('B');
301
+ const nodeC = new BaseNode('C');
302
+
303
+ nodeA.addDependent(nodeC);
304
+ nodeA.addDependent(nodeB);
305
+ nodeB.addDependent(nodeC);
306
+
307
+ assert.equal(BaseNode.hasCycle(nodeA), false);
308
+ });
309
+
310
+ it('should return true for basic cycles', () => {
311
+ // A - B - C - A!
312
+ const nodeA = new BaseNode('A');
313
+ const nodeB = new BaseNode('B');
314
+ const nodeC = new BaseNode('C');
315
+
316
+ nodeA.addDependent(nodeB);
317
+ nodeB.addDependent(nodeC);
318
+ nodeC.addDependent(nodeA);
319
+
320
+ assert.equal(BaseNode.hasCycle(nodeA), true);
321
+ });
322
+
323
+ it('should return true for children', () => {
324
+ // A!
325
+ // /
326
+ // A - B - C
327
+ const nodeA = new BaseNode('A');
328
+ const nodeB = new BaseNode('B');
329
+ const nodeC = new BaseNode('C');
330
+
331
+ nodeA.addDependent(nodeB);
332
+ nodeB.addDependent(nodeC);
333
+ nodeB.addDependent(nodeA);
334
+
335
+ assert.equal(BaseNode.hasCycle(nodeC), true);
336
+ });
337
+
338
+ it('should return true for complex cycles', () => {
339
+ // B - D - F - G - C!
340
+ // / /
341
+ // A - - C - E - H
342
+ const nodeA = new BaseNode('A');
343
+ const nodeB = new BaseNode('B');
344
+ const nodeC = new BaseNode('C');
345
+ const nodeD = new BaseNode('D');
346
+ const nodeE = new BaseNode('E');
347
+ const nodeF = new BaseNode('F');
348
+ const nodeG = new BaseNode('G');
349
+ const nodeH = new BaseNode('H');
350
+
351
+ nodeA.addDependent(nodeB);
352
+ nodeA.addDependent(nodeC);
353
+ nodeB.addDependent(nodeD);
354
+ nodeC.addDependent(nodeE);
355
+ nodeC.addDependent(nodeF);
356
+ nodeD.addDependent(nodeF);
357
+ nodeE.addDependent(nodeH);
358
+ nodeF.addDependent(nodeG);
359
+ nodeG.addDependent(nodeC);
360
+
361
+ assert.equal(BaseNode.hasCycle(nodeA), true);
362
+ assert.equal(BaseNode.hasCycle(nodeB), true);
363
+ assert.equal(BaseNode.hasCycle(nodeC), true);
364
+ assert.equal(BaseNode.hasCycle(nodeD), true);
365
+ assert.equal(BaseNode.hasCycle(nodeE), true);
366
+ assert.equal(BaseNode.hasCycle(nodeF), true);
367
+ assert.equal(BaseNode.hasCycle(nodeG), true);
368
+ assert.equal(BaseNode.hasCycle(nodeH), true);
369
+ });
370
+
371
+ it('works for very large graphs', () => {
372
+ const root = new BaseNode('root');
373
+
374
+ let lastNode = root;
375
+ for (let i = 0; i < 10000; i++) {
376
+ const nextNode = new BaseNode(`child${i}`);
377
+ lastNode.addDependent(nextNode);
378
+ lastNode = nextNode;
379
+ }
380
+
381
+ lastNode.addDependent(root);
382
+ assert.equal(BaseNode.hasCycle(root), true);
383
+ });
384
+ });
385
+ });
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * @template [T=any]
3
- * @extends {BaseNode<T>}
3
+ * @extends {Lantern.BaseNode<T>}
4
4
  */
5
- export class CPUNode<T = any> extends BaseNode<T> {
5
+ export class CPUNode<T = any> extends Lantern.BaseNode<T> {
6
6
  /**
7
7
  * @param {Lantern.TraceEvent} parentEvent
8
8
  * @param {Lantern.TraceEvent[]=} childEvents
9
9
  * @param {number=} correctedEndTs
10
10
  */
11
11
  constructor(parentEvent: Lantern.TraceEvent, childEvents?: Lantern.TraceEvent[] | undefined, correctedEndTs?: number | undefined);
12
- _event: Lantern.TraceEvent;
13
- _childEvents: Lantern.TraceEvent[];
12
+ _event: import("./types/lantern.js").TraceEvent;
13
+ _childEvents: import("./types/lantern.js").TraceEvent[];
14
14
  _correctedEndTs: number | undefined;
15
15
  get type(): "cpu";
16
16
  /**
@@ -20,11 +20,11 @@ export class CPUNode<T = any> extends BaseNode<T> {
20
20
  /**
21
21
  * @return {Lantern.TraceEvent}
22
22
  */
23
- get event(): Lantern.TraceEvent;
23
+ get event(): import("./types/lantern.js").TraceEvent;
24
24
  /**
25
25
  * @return {Lantern.TraceEvent[]}
26
26
  */
27
- get childEvents(): Lantern.TraceEvent[];
27
+ get childEvents(): import("./types/lantern.js").TraceEvent[];
28
28
  /**
29
29
  * Returns true if this node contains a Layout task.
30
30
  * @return {boolean}
@@ -39,6 +39,5 @@ export class CPUNode<T = any> extends BaseNode<T> {
39
39
  */
40
40
  cloneWithoutRelationships(): CPUNode;
41
41
  }
42
- import { BaseNode } from './base-node.js';
43
- import * as Lantern from './types/lantern.js';
44
- //# sourceMappingURL=cpu-node.d.ts.map
42
+ import * as Lantern from './lantern.js';
43
+ //# sourceMappingURL=CpuNode.d.ts.map
@@ -4,14 +4,13 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as Lantern from './types/lantern.js';
8
- import {BaseNode} from './base-node.js';
7
+ import * as Lantern from './lantern.js';
9
8
 
10
9
  /**
11
10
  * @template [T=any]
12
- * @extends {BaseNode<T>}
11
+ * @extends {Lantern.BaseNode<T>}
13
12
  */
14
- class CPUNode extends BaseNode {
13
+ class CPUNode extends Lantern.BaseNode {
15
14
  /**
16
15
  * @param {Lantern.TraceEvent} parentEvent
17
16
  * @param {Lantern.TraceEvent[]=} childEvents
@@ -27,7 +26,7 @@ class CPUNode extends BaseNode {
27
26
  }
28
27
 
29
28
  get type() {
30
- return BaseNode.TYPES.CPU;
29
+ return Lantern.BaseNode.TYPES.CPU;
31
30
  }
32
31
 
33
32
  /**
@@ -5,4 +5,4 @@
5
5
  */
6
6
  export class LanternError extends Error {
7
7
  }
8
- //# sourceMappingURL=lantern-error.d.ts.map
8
+ //# sourceMappingURL=LanternError.d.ts.map
@@ -1,22 +1,22 @@
1
- export type Node = import('./base-node.js').Node;
2
- export type NetworkNode = import('./network-node.js').NetworkNode;
3
- export type Simulator = import('./simulator/simulator.js').Simulator;
1
+ export type Node = import('./BaseNode.js').Node;
2
+ export type NetworkNode = import('./NetworkNode.js').NetworkNode;
3
+ export type Simulator = import('./simulation/Simulator.js').Simulator;
4
4
  export type Extras = {
5
5
  optimistic: boolean;
6
- fcpResult?: Lantern.Metric | undefined;
7
- lcpResult?: Lantern.Metric | undefined;
8
- interactiveResult?: Lantern.Metric | undefined;
6
+ fcpResult?: Lantern.Metrics.Result | undefined;
7
+ lcpResult?: Lantern.Metrics.Result | undefined;
8
+ interactiveResult?: Lantern.Metrics.Result | undefined;
9
9
  observedSpeedIndex?: number | undefined;
10
10
  };
11
- /** @typedef {import('./base-node.js').Node} Node */
12
- /** @typedef {import('./network-node.js').NetworkNode} NetworkNode */
13
- /** @typedef {import('./simulator/simulator.js').Simulator} Simulator */
11
+ /** @typedef {import('./BaseNode.js').Node} Node */
12
+ /** @typedef {import('./NetworkNode.js').NetworkNode} NetworkNode */
13
+ /** @typedef {import('./simulation/Simulator.js').Simulator} Simulator */
14
14
  /**
15
15
  * @typedef Extras
16
16
  * @property {boolean} optimistic
17
- * @property {Lantern.Metric=} fcpResult
18
- * @property {Lantern.Metric=} lcpResult
19
- * @property {Lantern.Metric=} interactiveResult
17
+ * @property {Lantern.Metrics.Result=} fcpResult
18
+ * @property {Lantern.Metrics.Result=} lcpResult
19
+ * @property {Lantern.Metrics.Result=} interactiveResult
20
20
  * @property {number=} observedSpeedIndex
21
21
  */
22
22
  export class Metric {
@@ -29,7 +29,7 @@ export class Metric {
29
29
  /**
30
30
  * @return {Lantern.Simulation.MetricCoefficients}
31
31
  */
32
- static get COEFFICIENTS(): Lantern.Simulation.MetricCoefficients;
32
+ static get COEFFICIENTS(): import("./types/lantern.js").Simulation.MetricCoefficients;
33
33
  /**
34
34
  * Returns the coefficients, scaled by the throttling settings if needed by the metric.
35
35
  * Some lantern metrics (speed-index) use components in their estimate that are not
@@ -61,9 +61,9 @@ export class Metric {
61
61
  /**
62
62
  * @param {Lantern.Simulation.MetricComputationDataInput} data
63
63
  * @param {Omit<Extras, 'optimistic'>=} extras
64
- * @return {Promise<Lantern.Metric>}
64
+ * @return {Promise<Lantern.Metrics.Result>}
65
65
  */
66
- static compute(data: Lantern.Simulation.MetricComputationDataInput, extras?: Omit<Extras, 'optimistic'> | undefined): Promise<Lantern.Metric>;
66
+ static compute(data: Lantern.Simulation.MetricComputationDataInput, extras?: Omit<Extras, 'optimistic'> | undefined): Promise<Lantern.Metrics.Result>;
67
67
  }
68
- import * as Lantern from './types/lantern.js';
69
- //# sourceMappingURL=metric.d.ts.map
68
+ import * as Lantern from './lantern.js';
69
+ //# sourceMappingURL=Metric.d.ts.map