@@ -7,9 +7,11 @@ import {
7
7
} from "har-format" ;
8
8
import { roundNumber } from "../helpers/misc" ;
9
9
import { toInt } from "../helpers/parse" ;
10
+ import { HarTransformerOptions } from "../typing/options" ;
10
11
import {
11
12
Mark ,
12
13
TimingType ,
14
+ UserTiming ,
13
15
WaterfallData ,
14
16
WaterfallDocs ,
15
17
WaterfallEntryIndicator ,
@@ -28,16 +30,17 @@ import {
28
30
29
31
/**
30
32
* Transforms the full HAR doc, including all pages
31
- * @param {Har } harData - raw hhar object
33
+ * @param {Har } harData - raw HAR object
34
+ * @param {HarTransformerOptions } options - HAR-parser-specific options
32
35
* @returns WaterfallDocs
33
36
*/
34
- export function transformDoc ( harData : Har | Log ) : WaterfallDocs {
37
+ export function transformDoc ( harData : Har | Log , options : HarTransformerOptions ) : WaterfallDocs {
35
38
// make sure it's the *.log base node
36
39
let data = ( harData [ "log" ] !== undefined ? harData [ "log" ] : harData ) as Log ;
37
40
const pages = getPages ( data ) ;
38
41
39
42
return {
40
- pages : pages . map ( ( _page , i ) => this . transformPage ( data , i ) ) ,
43
+ pages : pages . map ( ( _page , i ) => this . transformPage ( data , i , options ) ) ,
41
44
} ;
42
45
}
43
46
@@ -65,7 +68,7 @@ function toWaterFallEntry(entry: Entry, index: number, startRelative: number, is
65
68
}
66
69
67
70
/** retuns the page or a mock page object */
68
- function getPages ( data : Log ) {
71
+ const getPages = ( data : Log ) => {
69
72
if ( data . pages && data . pages . length > 0 ) {
70
73
return data . pages ;
71
74
}
@@ -80,15 +83,18 @@ function getPages(data: Log) {
80
83
startedDateTime : statedTime ,
81
84
title : "n/a" ,
82
85
} as Page ] ;
83
- }
86
+ } ;
84
87
85
88
/**
86
89
* Transforms a HAR object into the format needed to render the PerfCascade
87
90
* @param {Har } harData - HAR document
88
91
* @param {number=0 } pageIndex - page to parse (for multi-page HAR)
92
+ * @param {HarTransformerOptions } options - HAR-parser-specific options
89
93
* @returns WaterfallData
90
94
*/
91
- export function transformPage ( harData : Har | Log , pageIndex : number = 0 ) : WaterfallData {
95
+ export function transformPage ( harData : Har | Log ,
96
+ pageIndex : number = 0 ,
97
+ options : HarTransformerOptions ) : WaterfallData {
92
98
// make sure it's the *.log base node
93
99
let data = ( harData [ "log" ] !== undefined ? harData [ "log" ] : harData ) as Log ;
94
100
@@ -116,17 +122,7 @@ export function transformPage(harData: Har | Log, pageIndex: number = 0): Waterf
116
122
return toWaterFallEntry ( entry , index , startRelative , isTLS ) ;
117
123
} ) ;
118
124
119
- const marks = Object . keys ( pageTimings )
120
- . filter ( ( k : keyof PageTiming ) => ( typeof pageTimings [ k ] === "number" && pageTimings [ k ] >= 0 ) )
121
- . sort ( ( a : string , b : string ) => pageTimings [ a ] > pageTimings [ b ] ? 1 : - 1 )
122
- . map ( ( k ) => {
123
- const startRelative : number = pageTimings [ k ] ;
124
- doneTime = Math . max ( doneTime , startRelative ) ;
125
- return {
126
- "name" : `${ k . replace ( / ^ [ _ ] / , "" ) } (${ roundNumber ( startRelative , 0 ) } ms)` ,
127
- "startTime" : startRelative ,
128
- } as Mark ;
129
- } ) ;
125
+ const marks = getMarks ( pageTimings , currPage , options ) ;
130
126
131
127
// Add 100ms margin to make room for labels
132
128
doneTime += 100 ;
@@ -136,19 +132,89 @@ export function transformPage(harData: Har | Log, pageIndex: number = 0): Waterf
136
132
durationMs : doneTime ,
137
133
entries,
138
134
marks,
139
- lines : [ ] ,
140
135
title : currPage . title ,
141
136
} ;
142
137
}
143
138
139
+ /**
140
+ * Extract all `Mark`s based on `PageTiming` and `UserTiming`
141
+ * @param {PageTiming } pageTimings - HARs `PageTiming` object
142
+ * @param {Page } currPage - active page
143
+ * @param {HarTransformerOptions } options - HAR-parser-specific options
144
+ */
145
+ const getMarks = ( pageTimings : PageTiming , currPage : Page , options : HarTransformerOptions ) => {
146
+ const sortFn = ( a : Mark , b : Mark ) => a . startTime - b . startTime ;
147
+ const marks = Object . keys ( pageTimings )
148
+ . filter ( ( k : keyof PageTiming ) => ( typeof pageTimings [ k ] === "number" && pageTimings [ k ] >= 0 ) )
149
+ . map ( ( k ) => ( {
150
+ name : `${ k . replace ( / ^ [ _ ] / , "" ) } (${ roundNumber ( pageTimings [ k ] , 0 ) } ms)` ,
151
+ startTime : pageTimings [ k ] ,
152
+ } as Mark ) ) ;
153
+
154
+ if ( ! options . showUserTiming ) {
155
+ return marks . sort ( sortFn ) ;
156
+ }
157
+
158
+ return getUserTimimngs ( currPage , options )
159
+ . concat ( marks )
160
+ . sort ( sortFn ) ;
161
+ } ;
162
+
163
+ /**
164
+ * Extract all `Mark`s based on `UserTiming`
165
+ * @param {Page } currPage - active page
166
+ * @param {HarTransformerOptions } options - HAR-parser-specific options
167
+ */
168
+ const getUserTimimngs = ( currPage : Page , options : HarTransformerOptions ) => {
169
+ let baseFilter = options . showUserTimingEndMarker ?
170
+ ( k : string ) => k . indexOf ( "_userTime." ) === 0 :
171
+ ( k : string ) => k . indexOf ( "_userTime." ) === 0 && k . indexOf ( "_userTime.endTimer-" ) !== 0 ;
172
+ let filterFn = baseFilter ;
173
+
174
+ if ( Array . isArray ( options . showUserTiming ) ) {
175
+ let findTimings = options . showUserTiming ;
176
+ filterFn = ( k : string ) => (
177
+ baseFilter ( k ) &&
178
+ findTimings . indexOf ( k . replace ( / ^ _ u s e r T i m e \. / , "" ) ) >= 0
179
+ ) ;
180
+ }
181
+
182
+ const findName = / ^ _ u s e r T i m e \. ( (?: s t a r t T i m e r - ) ? ( .+ ) ) $ / ;
183
+
184
+ const extractUserTiming = ( k : string ) => {
185
+ let name : string ;
186
+ let fullName : string ;
187
+ let duration : number ;
188
+ [ , fullName , name ] = findName . exec ( k ) ;
189
+
190
+ if ( fullName !== name && currPage [ `_userTime.endTimer-${ name } ` ] ) {
191
+ duration = currPage [ `_userTime.endTimer-${ name } ` ] - currPage [ k ] ;
192
+ return {
193
+ name : fullName ,
194
+ duration,
195
+ startTime : currPage [ k ] ,
196
+ // x: currPage[k],
197
+ } as UserTiming ;
198
+ }
199
+ return {
200
+ name : fullName ,
201
+ startTime : currPage [ k ] ,
202
+ } as UserTiming ;
203
+ } ;
204
+
205
+ return Object . keys ( currPage )
206
+ . filter ( filterFn )
207
+ . map ( extractUserTiming ) ;
208
+ } ;
209
+
144
210
/**
145
211
* Create `WaterfallEntry`s to represent the subtimings of a request
146
212
* ("blocked", "dns", "connect", "send", "wait", "receive")
147
213
* @param {number } startRelative - Number of milliseconds since page load started (`page.startedDateTime`)
148
214
* @param {Entry } harEntry
149
215
* @returns Array
150
216
*/
151
- function buildDetailTimingBlocks ( startRelative : number , harEntry : Entry ) : WaterfallEntryTiming [ ] {
217
+ const buildDetailTimingBlocks = ( startRelative : number , harEntry : Entry ) : WaterfallEntryTiming [ ] => {
152
218
let t = harEntry . timings ;
153
219
return [ "blocked" , "dns" , "connect" , "send" , "wait" , "receive" ] . reduce ( ( collect : WaterfallEntryTiming [ ] ,
154
220
key : TimingType ) => {
@@ -172,7 +238,7 @@ function buildDetailTimingBlocks(startRelative: number, harEntry: Entry): Waterf
172
238
173
239
return collect . concat ( [ createWaterfallEntryTiming ( key , Math . round ( time . start ) , Math . round ( time . end ) ) ] ) ;
174
240
} , [ ] ) ;
175
- }
241
+ } ;
176
242
177
243
/**
178
244
* Returns Object containing start and end time of `collect`
@@ -183,7 +249,7 @@ function buildDetailTimingBlocks(startRelative: number, harEntry: Entry): Waterf
183
249
* @param {number } startRelative - Number of milliseconds since page load started (`page.startedDateTime`)
184
250
* @returns {Object }
185
251
*/
186
- function getTimePair ( key : string , harEntry : Entry , collect : WaterfallEntryTiming [ ] , startRelative : number ) {
252
+ const getTimePair = ( key : string , harEntry : Entry , collect : WaterfallEntryTiming [ ] , startRelative : number ) => {
187
253
let wptKey ;
188
254
switch ( key ) {
189
255
case "wait" : wptKey = "ttfb" ; break ;
@@ -209,7 +275,7 @@ function getTimePair(key: string, harEntry: Entry, collect: WaterfallEntryTiming
209
275
* @param {WaterfallEntryIndicator[] } indicators
210
276
* @returns WaterfallResponseDetails
211
277
*/
212
- function createResponseDetails ( entry : Entry , indicators : WaterfallEntryIndicator [ ] ) : WaterfallResponseDetails {
278
+ const createResponseDetails = ( entry : Entry , indicators : WaterfallEntryIndicator [ ] ) : WaterfallResponseDetails => {
213
279
const requestType = mimeToRequestType ( entry . response . content . mimeType ) ;
214
280
return {
215
281
icon : makeMimeTypeIcon ( entry . response . status , entry . response . statusText , requestType , entry . response . redirectURL ) ,
0 commit comments