browsertime 16.17.0 → 17.0.0-beta.1
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.
- package/CHANGELOG.md +44 -0
- package/bin/browsertime.js +43 -43
- package/bin/browsertimeWebPageReplay.js +10 -9
- package/browserscripts/pageinfo/generator.js +1 -1
- package/index.js +14 -13
- package/lib/android/gnirehtet.js +14 -15
- package/lib/android/index.js +92 -89
- package/lib/android/root.js +6 -9
- package/lib/chrome/chromeDevtoolsProtocol.js +46 -45
- package/lib/chrome/har.js +12 -13
- package/lib/chrome/longTaskMetrics.js +3 -5
- package/lib/chrome/parseCpuTrace.js +13 -10
- package/lib/chrome/settings/chromeAndroidOptions.js +1 -3
- package/lib/chrome/settings/chromeDesktopOptions.js +1 -3
- package/lib/chrome/settings/traceCategories.js +1 -3
- package/lib/chrome/traceCategoriesParser.js +35 -36
- package/lib/chrome/webdriver/builder.js +18 -26
- package/lib/chrome/webdriver/chromium.js +56 -46
- package/lib/chrome/webdriver/setupChromiumOptions.js +32 -27
- package/lib/connectivity/humble.js +13 -14
- package/lib/connectivity/index.js +74 -77
- package/lib/connectivity/trafficShapeParser.js +31 -35
- package/lib/core/engine/collector.js +22 -22
- package/lib/core/engine/command/addText.js +24 -27
- package/lib/core/engine/command/android.js +7 -11
- package/lib/core/engine/command/cache.js +3 -4
- package/lib/core/engine/command/chromeDevToolsProtocol.js +20 -20
- package/lib/core/engine/command/click.js +48 -49
- package/lib/core/engine/command/debug.js +3 -4
- package/lib/core/engine/command/javaScript.js +18 -19
- package/lib/core/engine/command/measure.js +31 -37
- package/lib/core/engine/command/meta.js +1 -4
- package/lib/core/engine/command/mouse/clickAndHold.js +36 -39
- package/lib/core/engine/command/mouse/contextClick.js +17 -18
- package/lib/core/engine/command/mouse/doubleClick.js +17 -19
- package/lib/core/engine/command/mouse/index.js +5 -9
- package/lib/core/engine/command/mouse/mouseMove.js +19 -23
- package/lib/core/engine/command/mouse/singleClick.js +15 -19
- package/lib/core/engine/command/navigation.js +12 -14
- package/lib/core/engine/command/screenshot.js +1 -4
- package/lib/core/engine/command/scroll.js +4 -7
- package/lib/core/engine/command/select.js +26 -26
- package/lib/core/engine/command/set.js +25 -23
- package/lib/core/engine/command/stopWatch.js +5 -8
- package/lib/core/engine/command/switch.js +18 -20
- package/lib/core/engine/command/util/lcpHighlightScript.js +1 -2
- package/lib/core/engine/command/util/lsHighlightScript.js +1 -2
- package/lib/core/engine/command/wait.js +18 -18
- package/lib/core/engine/index.js +82 -72
- package/lib/core/engine/iteration.js +83 -79
- package/lib/core/engine/run.js +5 -9
- package/lib/core/pageCompleteChecks/defaultPageCompleteCheck.js +1 -2
- package/lib/core/pageCompleteChecks/pageCompleteCheckByInactivity.js +1 -3
- package/lib/core/pageCompleteChecks/spaInactivity.js +1 -3
- package/lib/core/seleniumRunner.js +92 -100
- package/lib/core/webdriver/index.js +24 -21
- package/lib/edge/webdriver/builder.js +21 -26
- package/lib/extensionserver/httpServer.js +17 -21
- package/lib/extensionserver/index.js +8 -12
- package/lib/extensionserver/setup.js +12 -12
- package/lib/firefox/geckoProfiler.js +27 -21
- package/lib/firefox/getHAR.js +7 -8
- package/lib/firefox/memoryReport.js +9 -11
- package/lib/firefox/perfStats.js +5 -7
- package/lib/firefox/settings/disableSafeBrowsingPreferences.js +1 -3
- package/lib/firefox/settings/disableTrackingProtectionPreferences.js +1 -3
- package/lib/firefox/settings/firefoxPreferences.js +2 -4
- package/lib/firefox/settings/geckoProfilerDefaults.js +5 -9
- package/lib/firefox/webdriver/builder.js +66 -63
- package/lib/firefox/webdriver/firefox.js +44 -49
- package/lib/safari/webdriver/builder.js +4 -5
- package/lib/safari/webdriver/safari.js +4 -8
- package/lib/screenshot/defaults.js +1 -3
- package/lib/screenshot/index.js +24 -21
- package/lib/support/browserScript.js +65 -56
- package/lib/support/cli.js +120 -87
- package/lib/support/dns.js +6 -7
- package/lib/support/engineUtils.js +85 -38
- package/lib/support/errors.js +4 -13
- package/lib/support/fileUtil.js +81 -68
- package/lib/support/filters.js +15 -20
- package/lib/support/getViewPort.js +6 -7
- package/lib/support/har/index.js +208 -216
- package/lib/support/images/index.js +54 -26
- package/lib/support/logging.js +20 -17
- package/lib/support/pathToFolder.js +18 -23
- package/lib/support/preURL.js +5 -6
- package/lib/support/processes.js +4 -6
- package/lib/support/setResourceTimingBufferSize.js +2 -4
- package/lib/support/statistics.js +58 -56
- package/lib/support/stop.js +7 -8
- package/lib/support/storageManager.js +44 -44
- package/lib/support/tcpdump.js +22 -16
- package/lib/support/userTiming.js +7 -13
- package/lib/support/util.js +204 -224
- package/lib/support/xvfb.js +11 -13
- package/lib/video/defaults.js +6 -10
- package/lib/video/postprocessing/finetune/addTextToVideo.js +15 -15
- package/lib/video/postprocessing/finetune/convertFps.js +14 -8
- package/lib/video/postprocessing/finetune/getFont.js +7 -9
- package/lib/video/postprocessing/finetune/getTimingMetrics.js +19 -18
- package/lib/video/postprocessing/finetune/index.js +40 -36
- package/lib/video/postprocessing/finetune/removeOrange.js +10 -11
- package/lib/video/postprocessing/visualmetrics/extraMetrics.js +17 -13
- package/lib/video/postprocessing/visualmetrics/getVideoMetrics.js +12 -13
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +117 -128
- package/lib/video/screenRecording/android/recorder.js +12 -17
- package/lib/video/screenRecording/desktop/convert.js +13 -11
- package/lib/video/screenRecording/desktop/desktopRecorder.js +29 -24
- package/lib/video/screenRecording/desktop/ffmpegRecorder.js +60 -63
- package/lib/video/screenRecording/desktop/osx/getSPDisplaysDataType.js +4 -6
- package/lib/video/screenRecording/desktop/osx/getScreen.js +9 -10
- package/lib/video/screenRecording/firefox/firefoxWindowRecorder.js +54 -54
- package/lib/video/screenRecording/ios/convertToMp4.js +10 -11
- package/lib/video/screenRecording/ios/iosRecorder.js +23 -21
- package/lib/video/screenRecording/iosSimulator/convertToMp4.js +10 -11
- package/lib/video/screenRecording/iosSimulator/recorder.js +10 -9
- package/lib/video/screenRecording/recorder.js +8 -9
- package/lib/video/screenRecording/setOrangeBackground.js +5 -6
- package/lib/video/video.js +28 -34
- package/package.json +19 -17
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const PerfStats = require('../perfStats.js');
|
|
18
|
-
|
|
1
|
+
import { rename as _rename } from 'node:fs';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import intel from 'intel';
|
|
5
|
+
import get from 'lodash.get';
|
|
6
|
+
import { getEmptyHAR, mergeHars } from '../../support/har/index.js';
|
|
7
|
+
import pathToFolder from '../../support/pathToFolder.js';
|
|
8
|
+
import { isAndroidConfigured, Android } from '../../android/index.js';
|
|
9
|
+
import { adjustVisualProgressTimestamps } from '../../support/util.js';
|
|
10
|
+
import { findFiles } from '../../support/fileUtil.js';
|
|
11
|
+
import getHAR from '../getHAR.js';
|
|
12
|
+
import GeckoProfiler from '../geckoProfiler.js';
|
|
13
|
+
import { MemoryReport } from '../memoryReport.js';
|
|
14
|
+
import { PerfStats } from '../perfStats.js';
|
|
15
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
16
|
+
const rename = promisify(_rename);
|
|
19
17
|
class Firefox {
|
|
20
18
|
constructor(storageManager, options) {
|
|
21
19
|
// Lets keep this and hope that we in the future will have HAR for FF again
|
|
@@ -41,7 +39,7 @@ class Firefox {
|
|
|
41
39
|
this.android = new Android(this.options);
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
if (this.
|
|
42
|
+
if (isAndroidConfigured(this.options) && this.options.androidPower) {
|
|
45
43
|
await this.android.startPowerTesting();
|
|
46
44
|
}
|
|
47
45
|
}
|
|
@@ -75,7 +73,7 @@ class Firefox {
|
|
|
75
73
|
* Before each URL/test runs.
|
|
76
74
|
*/
|
|
77
75
|
async beforeEachURL(runner) {
|
|
78
|
-
if (this.
|
|
76
|
+
if (isAndroidConfigured(this.options) && this.options.androidPower) {
|
|
79
77
|
await this.android.resetPowerUsage();
|
|
80
78
|
}
|
|
81
79
|
|
|
@@ -105,7 +103,7 @@ class Firefox {
|
|
|
105
103
|
async afterPageCompleteCheck(runner, index, url, alias) {
|
|
106
104
|
const result = { url, alias };
|
|
107
105
|
|
|
108
|
-
if (this.
|
|
106
|
+
if (isAndroidConfigured(this.options) && this.options.androidPower) {
|
|
109
107
|
result.power = await this.android.measurePowerUsage(
|
|
110
108
|
this.firefoxConfig.android.package
|
|
111
109
|
);
|
|
@@ -148,7 +146,7 @@ class Firefox {
|
|
|
148
146
|
);
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
if (this.skipHar || this.options
|
|
149
|
+
if (this.skipHar || isAndroidConfigured(this.options)) {
|
|
152
150
|
return result;
|
|
153
151
|
} else {
|
|
154
152
|
const har = await getHAR(runner, this.includeResponseBodies);
|
|
@@ -178,15 +176,15 @@ class Firefox {
|
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
async postWork(index, results) {
|
|
181
|
-
for (
|
|
179
|
+
for (const result of results) {
|
|
182
180
|
if (this.firefoxConfig.collectMozLog) {
|
|
183
|
-
const files = await
|
|
181
|
+
const files = await findFiles(this.baseDir, 'moz_log.txt');
|
|
184
182
|
for (const file of files) {
|
|
185
183
|
await rename(
|
|
186
184
|
`${this.baseDir}/${file}`,
|
|
187
|
-
|
|
185
|
+
join(
|
|
188
186
|
this.baseDir,
|
|
189
|
-
pathToFolder(
|
|
187
|
+
pathToFolder(result.url, this.options),
|
|
190
188
|
`${file}-${index}.txt`
|
|
191
189
|
)
|
|
192
190
|
);
|
|
@@ -195,7 +193,7 @@ class Firefox {
|
|
|
195
193
|
|
|
196
194
|
if (this.firefoxConfig.geckoProfiler && this.options.visualMetrics) {
|
|
197
195
|
const profileFilename = `geckoProfile-${index}.json.gz`;
|
|
198
|
-
const profileSubdir = pathToFolder(
|
|
196
|
+
const profileSubdir = pathToFolder(result.url, this.options);
|
|
199
197
|
|
|
200
198
|
try {
|
|
201
199
|
const geckoProfile = JSON.parse(
|
|
@@ -209,9 +207,9 @@ class Firefox {
|
|
|
209
207
|
// by adding the time to first frame, time to orange screen to the unix timestamp of
|
|
210
208
|
// video recording start time
|
|
211
209
|
const firstFrameStartTime =
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
result.recordingStartTime +
|
|
211
|
+
result.videoRecordingStart +
|
|
212
|
+
result.timeToFirstFrame;
|
|
215
213
|
|
|
216
214
|
for (let progress of [
|
|
217
215
|
'VisualProgress',
|
|
@@ -219,26 +217,25 @@ class Firefox {
|
|
|
219
217
|
'PerceptualSpeedIndexProgress'
|
|
220
218
|
]) {
|
|
221
219
|
// You can configure to not use content and perceptual.
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
);
|
|
220
|
+
if (result.visualMetrics[progress]) {
|
|
221
|
+
result.visualMetrics[progress] = adjustVisualProgressTimestamps(
|
|
222
|
+
result.visualMetrics[progress],
|
|
223
|
+
geckoProfile.meta.startTime,
|
|
224
|
+
firstFrameStartTime
|
|
225
|
+
);
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
|
-
geckoProfile.meta.visualMetrics =
|
|
228
|
+
geckoProfile.meta.visualMetrics = result.visualMetrics;
|
|
232
229
|
|
|
233
230
|
await this.storageManager.writeJson(
|
|
234
|
-
|
|
231
|
+
join(profileSubdir, `geckoProfile-${index}.json`),
|
|
235
232
|
geckoProfile,
|
|
236
233
|
true
|
|
237
234
|
);
|
|
238
|
-
} catch (
|
|
235
|
+
} catch (error) {
|
|
239
236
|
log.error(
|
|
240
237
|
`Could not rewrite visual progress using startimes and add visual metrics to ${profileFilename}`,
|
|
241
|
-
|
|
238
|
+
error
|
|
242
239
|
);
|
|
243
240
|
}
|
|
244
241
|
}
|
|
@@ -252,24 +249,22 @@ class Firefox {
|
|
|
252
249
|
if (this.skipHar) {
|
|
253
250
|
return;
|
|
254
251
|
}
|
|
255
|
-
this.hars.push(
|
|
252
|
+
this.hars.push(getEmptyHAR(url, 'Firefox'));
|
|
256
253
|
}
|
|
257
254
|
|
|
258
255
|
/**
|
|
259
256
|
* Get the HAR file for all the runs.
|
|
260
257
|
*/
|
|
261
258
|
async getHARs() {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return {};
|
|
266
|
-
}
|
|
259
|
+
return !this.skipHar && this.hars.length > 0
|
|
260
|
+
? { har: mergeHars(this.hars) }
|
|
261
|
+
: {};
|
|
267
262
|
}
|
|
268
263
|
/**
|
|
269
264
|
* Before the browser is stopped/closed.
|
|
270
265
|
*/
|
|
271
266
|
async beforeBrowserStop() {
|
|
272
|
-
if (this.
|
|
267
|
+
if (isAndroidConfigured(this.options) && this.options.androidPower) {
|
|
273
268
|
await this.android.stopPowerTesting();
|
|
274
269
|
}
|
|
275
270
|
}
|
|
@@ -280,4 +275,4 @@ class Firefox {
|
|
|
280
275
|
async afterBrowserStopped() {}
|
|
281
276
|
}
|
|
282
277
|
|
|
283
|
-
|
|
278
|
+
export default Firefox;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
const s = require('selenium-webdriver/safari');
|
|
1
|
+
import { Options } from 'selenium-webdriver/safari.js';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
export async function configureBuilder(builder, baseDir, options) {
|
|
5
4
|
const safariOptions = options.safari || {};
|
|
6
5
|
builder
|
|
7
6
|
.getCapabilities()
|
|
@@ -43,8 +42,8 @@ module.exports.configureBuilder = async function (builder, baseDir, options) {
|
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
if (safariOptions.useTechnologyPreview) {
|
|
46
|
-
let o = new
|
|
45
|
+
let o = new Options();
|
|
47
46
|
o = o.setTechnologyPreview(true);
|
|
48
47
|
builder.setSafariOptions(o);
|
|
49
48
|
}
|
|
50
|
-
}
|
|
49
|
+
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
// const log = require('intel').getLogger('browsertime.safari');
|
|
4
|
-
|
|
2
|
+
import { execaCommand as command } from 'execa';
|
|
5
3
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
6
4
|
|
|
7
|
-
class Safari {
|
|
5
|
+
export default class Safari {
|
|
8
6
|
constructor(storageManager, options) {
|
|
9
7
|
this.options = options;
|
|
10
8
|
this.safariOptions = options.safari || {};
|
|
@@ -15,7 +13,7 @@ class Safari {
|
|
|
15
13
|
*/
|
|
16
14
|
async beforeBrowserStart() {
|
|
17
15
|
if (this.safariOptions.ios) {
|
|
18
|
-
this.driverProcess =
|
|
16
|
+
this.driverProcess = command(
|
|
19
17
|
'safaridriver -p ' + this.options.safariDriverPort,
|
|
20
18
|
{
|
|
21
19
|
shell: true
|
|
@@ -86,7 +84,7 @@ class Safari {
|
|
|
86
84
|
|
|
87
85
|
async afterBrowserStopped() {
|
|
88
86
|
if (this.safariOptions.useSimulator) {
|
|
89
|
-
await
|
|
87
|
+
await command(
|
|
90
88
|
'xcrun simctl terminate ' +
|
|
91
89
|
this.safariOptions.deviceUDID +
|
|
92
90
|
' com.apple.mobilesafari',
|
|
@@ -101,5 +99,3 @@ class Safari {
|
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
}
|
|
104
|
-
|
|
105
|
-
module.exports = Safari;
|
package/lib/screenshot/index.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import merge from 'lodash.merge';
|
|
3
|
+
import intel from 'intel';
|
|
4
|
+
import defaultConfig from './defaults.js';
|
|
5
|
+
import {
|
|
6
|
+
savePngWithoutResize,
|
|
7
|
+
savePng,
|
|
8
|
+
saveJpg
|
|
9
|
+
} from '../support/images/index.js';
|
|
5
10
|
const SCREENSHOT_DIR = 'screenshots';
|
|
6
|
-
const
|
|
7
|
-
const log = require('intel').getLogger('browsertime.screenshot');
|
|
8
|
-
|
|
9
|
-
let jimp;
|
|
10
|
-
try {
|
|
11
|
-
jimp = require('jimp');
|
|
12
|
-
} catch (e) {
|
|
13
|
-
jimp = null;
|
|
14
|
-
}
|
|
15
|
-
|
|
11
|
+
const log = intel.getLogger('browsertime.screenshot');
|
|
16
12
|
class ScreenshotManager {
|
|
17
13
|
constructor(storageManager, options) {
|
|
18
14
|
this.storageManager = storageManager;
|
|
@@ -22,18 +18,25 @@ class ScreenshotManager {
|
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
async save(name, data, url, index) {
|
|
21
|
+
let jimp;
|
|
22
|
+
try {
|
|
23
|
+
jimp = await import('jimp');
|
|
24
|
+
} catch {
|
|
25
|
+
jimp = undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
25
28
|
if (!jimp) {
|
|
26
29
|
if (this.config.type === 'jpg') {
|
|
27
30
|
log.info(
|
|
28
31
|
'Missing sharp dependency so you can only save images as png at viewport size'
|
|
29
32
|
);
|
|
30
33
|
}
|
|
31
|
-
const pathAndName = await
|
|
34
|
+
const pathAndName = await savePngWithoutResize(
|
|
32
35
|
name,
|
|
33
36
|
data,
|
|
34
37
|
url,
|
|
35
38
|
this.storageManager,
|
|
36
|
-
|
|
39
|
+
join(SCREENSHOT_DIR, `${index}`),
|
|
37
40
|
this.options
|
|
38
41
|
);
|
|
39
42
|
this.savedScreenshots.push(
|
|
@@ -41,26 +44,26 @@ class ScreenshotManager {
|
|
|
41
44
|
);
|
|
42
45
|
}
|
|
43
46
|
if (this.config.type === 'png') {
|
|
44
|
-
const pathAndName = await
|
|
47
|
+
const pathAndName = await savePng(
|
|
45
48
|
name,
|
|
46
49
|
data,
|
|
47
50
|
url,
|
|
48
51
|
this.storageManager,
|
|
49
52
|
this.config,
|
|
50
|
-
|
|
53
|
+
join(SCREENSHOT_DIR, `${index}`),
|
|
51
54
|
this.options
|
|
52
55
|
);
|
|
53
56
|
this.savedScreenshots.push(
|
|
54
57
|
pathAndName.replace(this.storageManager.directory + '/', '')
|
|
55
58
|
);
|
|
56
59
|
} else {
|
|
57
|
-
const pathAndName = await
|
|
60
|
+
const pathAndName = await saveJpg(
|
|
58
61
|
name,
|
|
59
62
|
data,
|
|
60
63
|
url,
|
|
61
64
|
this.storageManager,
|
|
62
65
|
this.config,
|
|
63
|
-
|
|
66
|
+
join(SCREENSHOT_DIR, `${index}`),
|
|
64
67
|
this.options
|
|
65
68
|
);
|
|
66
69
|
this.savedScreenshots.push(
|
|
@@ -74,4 +77,4 @@ class ScreenshotManager {
|
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
export default ScreenshotManager;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import intel from 'intel';
|
|
7
|
+
import { onlyFiles, onlyWithExtension, onlyDirectories } from './filters.js';
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
7
9
|
const readdir = promisify(fs.readdir);
|
|
8
10
|
const readFile = promisify(fs.readFile);
|
|
9
11
|
const stat = promisify(fs.stat);
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
13
|
const rootFolder = path.resolve(__dirname, '..', '..', 'browserscripts');
|
|
11
|
-
const log =
|
|
14
|
+
const log = intel.getLogger('browsertime');
|
|
12
15
|
|
|
13
16
|
function toFullPath(filename, root) {
|
|
14
17
|
return path.join(root, filename);
|
|
@@ -20,12 +23,14 @@ function toFullPath(filename, root) {
|
|
|
20
23
|
* @param {*} dirpath
|
|
21
24
|
*/
|
|
22
25
|
async function scriptsFromDirectory(dirpath) {
|
|
23
|
-
const dir =
|
|
26
|
+
const dir = await readdir(dirpath);
|
|
27
|
+
|
|
28
|
+
const cleaned = dir
|
|
24
29
|
.map(name => toFullPath(name, dirpath))
|
|
25
|
-
.filter(await
|
|
26
|
-
.filter(
|
|
30
|
+
.filter(await onlyFiles)
|
|
31
|
+
.filter(onlyWithExtension('.js'));
|
|
27
32
|
const result = {};
|
|
28
|
-
for (const filepath of
|
|
33
|
+
for (const filepath of cleaned) {
|
|
29
34
|
const name = path.basename(filepath, '.js');
|
|
30
35
|
const script = await readFile(filepath, 'utf8');
|
|
31
36
|
result[name] = generateScriptObject(name, filepath, script);
|
|
@@ -34,12 +39,13 @@ async function scriptsFromDirectory(dirpath) {
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
async function getScriptsForCategories(categories) {
|
|
37
|
-
const
|
|
42
|
+
const directories = await readdir(rootFolder);
|
|
43
|
+
const cleaned = directories
|
|
38
44
|
.filter(name => categories.find(n => n === name))
|
|
39
45
|
.map(name => toFullPath(name, rootFolder))
|
|
40
|
-
.filter(await
|
|
46
|
+
.filter(await onlyDirectories);
|
|
41
47
|
const result = {};
|
|
42
|
-
for (const dir of
|
|
48
|
+
for (const dir of cleaned) {
|
|
43
49
|
const name = path.basename(dir);
|
|
44
50
|
const scripts = await scriptsFromDirectory(dir);
|
|
45
51
|
result[name] = scripts;
|
|
@@ -77,13 +83,13 @@ function generateScriptObject(name, path, contents) {
|
|
|
77
83
|
name: name,
|
|
78
84
|
requires: scriptAndMetadataObject.requires,
|
|
79
85
|
function: scriptAndMetadataObject.function,
|
|
80
|
-
content:
|
|
86
|
+
content: undefined,
|
|
81
87
|
isAsync:
|
|
82
88
|
Object.getPrototypeOf(scriptAndMetadataObject.function) ===
|
|
83
89
|
Object.getPrototypeOf(async function () {})
|
|
84
90
|
};
|
|
85
91
|
}
|
|
86
|
-
} catch
|
|
92
|
+
} catch {
|
|
87
93
|
// Use this as a signal to fall back to an old-style script, but don't
|
|
88
94
|
// perform any action
|
|
89
95
|
}
|
|
@@ -93,7 +99,7 @@ function generateScriptObject(name, path, contents) {
|
|
|
93
99
|
return {
|
|
94
100
|
name: name,
|
|
95
101
|
content: contents,
|
|
96
|
-
function:
|
|
102
|
+
function: undefined,
|
|
97
103
|
requires: {}
|
|
98
104
|
};
|
|
99
105
|
}
|
|
@@ -117,12 +123,13 @@ function generateScriptObject(name, path, contents) {
|
|
|
117
123
|
*/
|
|
118
124
|
async function findAndParseScripts(root, category) {
|
|
119
125
|
async function scriptsFromDirectory(dirpath) {
|
|
120
|
-
const dir =
|
|
126
|
+
const dir = await readdir(dirpath);
|
|
127
|
+
const cleaned = dir
|
|
121
128
|
.map(name => toFullPath(name, dirpath))
|
|
122
|
-
.filter(await
|
|
123
|
-
.filter(
|
|
129
|
+
.filter(await onlyFiles)
|
|
130
|
+
.filter(onlyWithExtension('.js'));
|
|
124
131
|
const result = {};
|
|
125
|
-
for (const filepath of
|
|
132
|
+
for (const filepath of cleaned) {
|
|
126
133
|
const name = path.basename(filepath, '.js');
|
|
127
134
|
const script = await readFile(filepath, 'utf8');
|
|
128
135
|
|
|
@@ -142,44 +149,46 @@ async function findAndParseScripts(root, category) {
|
|
|
142
149
|
}
|
|
143
150
|
|
|
144
151
|
return stat(root).then(stats => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return parseDirectory(root);
|
|
158
|
-
}
|
|
152
|
+
return stats.isFile()
|
|
153
|
+
? readFile(root, 'utf8').then(content => {
|
|
154
|
+
const name = path.basename(root, '.js');
|
|
155
|
+
let scripts = {};
|
|
156
|
+
|
|
157
|
+
scripts[name] = generateScriptObject(name, root, content);
|
|
158
|
+
let categories = {};
|
|
159
|
+
categories[category] = scripts;
|
|
160
|
+
|
|
161
|
+
return categories;
|
|
162
|
+
})
|
|
163
|
+
: parseDirectory(root);
|
|
159
164
|
});
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
167
|
+
const defaultScriptCategories = ['browser', 'pageinfo', 'timings'];
|
|
168
|
+
|
|
169
|
+
// FIXME need to add async here, is that possible for properties?
|
|
170
|
+
async function allScriptCategories() {
|
|
171
|
+
return readdir(rootFolder).then(files => {
|
|
172
|
+
files = files.map(fileName => path.join(rootFolder, fileName));
|
|
173
|
+
const p = [];
|
|
174
|
+
for (const file of files) {
|
|
175
|
+
p.push(onlyDirectories(file));
|
|
176
|
+
}
|
|
177
|
+
return Promise.all(p).then(isDirectories => {
|
|
178
|
+
const onlyDirectories = [];
|
|
179
|
+
for (const [index, isDirectory] of isDirectories.entries()) {
|
|
180
|
+
if (isDirectory) {
|
|
181
|
+
onlyDirectories.push(files[index]);
|
|
178
182
|
}
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
}
|
|
184
|
+
return onlyDirectories.map(dirName => path.basename(dirName));
|
|
181
185
|
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
defaultScriptCategories,
|
|
191
|
+
allScriptCategories,
|
|
192
|
+
getScriptsForCategories,
|
|
193
|
+
findAndParseScripts
|
|
185
194
|
};
|