testem 3.19.1 → 3.20.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/README.md +175 -134
- package/lib/api.js +1 -1
- package/lib/app.js +186 -116
- package/lib/cli-local-delegation.js +93 -0
- package/lib/config.js +260 -119
- package/lib/file_watcher.js +111 -37
- package/lib/file_watcher_impl.js +295 -0
- package/lib/launcher.js +7 -12
- package/lib/reporters/dev/runner_tabs.js +52 -47
- package/lib/reporters/dev/split_log_panel.js +1 -1
- package/lib/reporters/dev/toast_notify.js +5 -0
- package/lib/runners/browser_test_runner.js +3 -1
- package/lib/runners/hook_runner.js +0 -1
- package/lib/server/index.js +39 -10
- package/lib/tap_consumer.js +73 -11
- package/lib/utils/esbuild-browser-polyfills.js +1 -1
- package/lib/utils/esbuild-buffer-inject.js +1 -1
- package/lib/utils/expand_glob_pattern.js +19 -0
- package/lib/utils/file_watch_glob_policy.js +119 -0
- package/lib/utils/is_emfile_error.js +16 -0
- package/lib/utils/known-browsers.js +155 -118
- package/lib/utils/path_pattern_match.js +39 -0
- package/lib/utils/process.js +42 -0
- package/lib/utils/promises.js +20 -1
- package/lib/utils/reporter.js +2 -2
- package/lib/utils/tmp-cleanup.js +26 -0
- package/package.json +40 -31
- package/testem.js +174 -78
package/lib/config.js
CHANGED
|
@@ -8,14 +8,13 @@ or `testem.json` config file.
|
|
|
8
8
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
const os = require('os');
|
|
13
12
|
const fs = require('fs');
|
|
14
13
|
const yaml = require('js-yaml');
|
|
15
14
|
const log = require('./log');
|
|
16
15
|
const path = require('path');
|
|
17
|
-
const glob = require('glob').glob;
|
|
18
16
|
const url = require('url');
|
|
17
|
+
const { pathToFileURL } = url;
|
|
19
18
|
const querystring = require('querystring');
|
|
20
19
|
const { filter, reduce } = require('./utils/promises');
|
|
21
20
|
|
|
@@ -29,7 +28,7 @@ const _ = require('lodash');
|
|
|
29
28
|
|
|
30
29
|
const knownBrowsers = require('./utils/known-browsers');
|
|
31
30
|
const { convertToPosix } = require('./utils/posix');
|
|
32
|
-
const
|
|
31
|
+
const expandGlobPattern = require('./utils/expand_glob_pattern');
|
|
33
32
|
|
|
34
33
|
class Config {
|
|
35
34
|
constructor(appMode, progOptions, config) {
|
|
@@ -39,7 +38,7 @@ class Config {
|
|
|
39
38
|
this.fileOptions = {};
|
|
40
39
|
this.config = config || {};
|
|
41
40
|
this.getters = {
|
|
42
|
-
test_page: 'getTestPage'
|
|
41
|
+
test_page: 'getTestPage',
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
if (appMode === 'dev') {
|
|
@@ -71,12 +70,33 @@ class Config {
|
|
|
71
70
|
|
|
72
71
|
// Try all testem.json, testem.yml and testem.js
|
|
73
72
|
// testem.json gets precedence
|
|
74
|
-
let files = [
|
|
75
|
-
|
|
73
|
+
let files = [
|
|
74
|
+
'testem.json',
|
|
75
|
+
'.testem.json',
|
|
76
|
+
'.testem.yml',
|
|
77
|
+
'testem.yml',
|
|
78
|
+
'testem.js',
|
|
79
|
+
'.testem.js',
|
|
80
|
+
'testem.mjs',
|
|
81
|
+
'.testem.mjs',
|
|
82
|
+
'testem.cjs',
|
|
83
|
+
'.testem.cjs',
|
|
84
|
+
];
|
|
85
|
+
return filter(
|
|
86
|
+
files.map(this.resolveConfigPath.bind(this)),
|
|
87
|
+
fileExists,
|
|
88
|
+
).then((matched) => {
|
|
76
89
|
let configFile = matched[0];
|
|
77
90
|
if (matched.length > 1) {
|
|
78
|
-
let baseNames = matched.map(fileName => path.basename(fileName));
|
|
79
|
-
console.warn(
|
|
91
|
+
let baseNames = matched.map((fileName) => path.basename(fileName));
|
|
92
|
+
console.warn(
|
|
93
|
+
'Found ' +
|
|
94
|
+
matched.length +
|
|
95
|
+
' config files (' +
|
|
96
|
+
baseNames +
|
|
97
|
+
'), using ' +
|
|
98
|
+
baseNames[0],
|
|
99
|
+
);
|
|
80
100
|
}
|
|
81
101
|
if (configFile) {
|
|
82
102
|
this.readConfigFile(configFile, callback);
|
|
@@ -99,7 +119,7 @@ class Config {
|
|
|
99
119
|
|
|
100
120
|
client() {
|
|
101
121
|
return {
|
|
102
|
-
decycle_depth: this.get('client_decycle_depth')
|
|
122
|
+
decycle_depth: this.get('client_decycle_depth'),
|
|
103
123
|
};
|
|
104
124
|
}
|
|
105
125
|
|
|
@@ -122,11 +142,12 @@ class Config {
|
|
|
122
142
|
}
|
|
123
143
|
|
|
124
144
|
readConfigFile(configFile, callback) {
|
|
125
|
-
if (!configFile) {
|
|
145
|
+
if (!configFile) {
|
|
146
|
+
// allow empty configFile for programmatic setups
|
|
126
147
|
if (callback) {
|
|
127
148
|
callback.call(this);
|
|
128
149
|
}
|
|
129
|
-
} else if (configFile.match(/\.c?js$/)) {
|
|
150
|
+
} else if (configFile.match(/\.(c?js|mjs)$/)) {
|
|
130
151
|
this.readJS(configFile, callback);
|
|
131
152
|
} else if (configFile.match(/\.json$/)) {
|
|
132
153
|
this.readJSON(configFile, callback);
|
|
@@ -140,28 +161,70 @@ class Config {
|
|
|
140
161
|
}
|
|
141
162
|
}
|
|
142
163
|
|
|
164
|
+
unwrapJsExport(exported) {
|
|
165
|
+
if (
|
|
166
|
+
exported &&
|
|
167
|
+
typeof exported === 'object' &&
|
|
168
|
+
exported.__esModule === true &&
|
|
169
|
+
Object.prototype.hasOwnProperty.call(exported, 'default')
|
|
170
|
+
) {
|
|
171
|
+
return exported.default;
|
|
172
|
+
}
|
|
173
|
+
return exported;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
loadJsExportedConfig(absPath) {
|
|
177
|
+
const ext = path.extname(absPath);
|
|
178
|
+
if (ext === '.cjs') {
|
|
179
|
+
return Promise.resolve(this.unwrapJsExport(require(absPath)));
|
|
180
|
+
}
|
|
181
|
+
if (ext === '.mjs') {
|
|
182
|
+
return import(pathToFileURL(absPath).href).then((mod) =>
|
|
183
|
+
mod.default !== undefined ? mod.default : mod,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
return Promise.resolve(this.unwrapJsExport(require(absPath)));
|
|
188
|
+
} catch (e) {
|
|
189
|
+
if (e.code === 'ERR_REQUIRE_ESM') {
|
|
190
|
+
return import(pathToFileURL(absPath).href).then((mod) =>
|
|
191
|
+
mod.default !== undefined ? mod.default : mod,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
throw e;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
143
198
|
readJS(configFile, callback) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
199
|
+
const absPath = this.resolveConfigPath(configFile);
|
|
200
|
+
this.loadJsExportedConfig(absPath)
|
|
201
|
+
.then((exportedConfig) => {
|
|
202
|
+
if (typeof exportedConfig === 'function') {
|
|
203
|
+
return Promise.resolve(exportedConfig()).then((obj) => {
|
|
204
|
+
this.fileOptions = obj;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
this.fileOptions = exportedConfig;
|
|
208
|
+
})
|
|
209
|
+
.catch((err) => {
|
|
210
|
+
log.error(err);
|
|
211
|
+
})
|
|
212
|
+
.then(() => {
|
|
148
213
|
if (callback) {
|
|
149
214
|
callback.call(this);
|
|
150
215
|
}
|
|
151
216
|
});
|
|
152
|
-
} else {
|
|
153
|
-
this.fileOptions = exportedConfig;
|
|
154
|
-
if (callback) {
|
|
155
|
-
callback.call(this);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
217
|
}
|
|
159
218
|
|
|
160
219
|
readYAML(configFile, callback) {
|
|
161
|
-
return fs.promises
|
|
162
|
-
.
|
|
163
|
-
|
|
164
|
-
|
|
220
|
+
return fs.promises
|
|
221
|
+
.readFile(configFile)
|
|
222
|
+
.then(
|
|
223
|
+
(data) => {
|
|
224
|
+
this.fileOptions = yaml.load(String(data));
|
|
225
|
+
},
|
|
226
|
+
() => {},
|
|
227
|
+
)
|
|
165
228
|
.then(() => {
|
|
166
229
|
if (callback) {
|
|
167
230
|
callback.call(this);
|
|
@@ -170,11 +233,15 @@ class Config {
|
|
|
170
233
|
}
|
|
171
234
|
|
|
172
235
|
readJSON(configFile, callback) {
|
|
173
|
-
return fs.promises
|
|
174
|
-
.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
236
|
+
return fs.promises
|
|
237
|
+
.readFile(configFile)
|
|
238
|
+
.then(
|
|
239
|
+
(data) => {
|
|
240
|
+
this.fileOptions = JSON.parse(data.toString());
|
|
241
|
+
this.progOptions.file = configFile;
|
|
242
|
+
},
|
|
243
|
+
() => {},
|
|
244
|
+
)
|
|
178
245
|
.then(() => {
|
|
179
246
|
if (callback) {
|
|
180
247
|
callback.call(this);
|
|
@@ -196,11 +263,12 @@ class Config {
|
|
|
196
263
|
|
|
197
264
|
let urlObj = url.parse(urlString);
|
|
198
265
|
let outputQueryParams = querystring.parse(urlObj.query) || {};
|
|
199
|
-
Object.keys(queryParamsObj).forEach(param => {
|
|
266
|
+
Object.keys(queryParamsObj).forEach((param) => {
|
|
200
267
|
outputQueryParams[param] = queryParamsObj[param];
|
|
201
268
|
});
|
|
202
269
|
urlObj.query = outputQueryParams;
|
|
203
|
-
urlObj.search = querystring
|
|
270
|
+
urlObj.search = querystring
|
|
271
|
+
.stringify(outputQueryParams)
|
|
204
272
|
.replace(/=&/g, '&')
|
|
205
273
|
.replace(/=$/, '');
|
|
206
274
|
urlObj.path = urlObj.pathname + urlObj.search;
|
|
@@ -215,20 +283,32 @@ class Config {
|
|
|
215
283
|
testPage = [testPage];
|
|
216
284
|
}
|
|
217
285
|
|
|
218
|
-
return testPage.map(page =>
|
|
286
|
+
return testPage.map((page) =>
|
|
287
|
+
this.mergeUrlAndQueryParams(page, queryParams),
|
|
288
|
+
);
|
|
219
289
|
}
|
|
220
290
|
|
|
221
291
|
getConfigProperty(key) {
|
|
222
292
|
if (this.config && key in this.config) {
|
|
223
293
|
return this.config[key];
|
|
224
294
|
}
|
|
225
|
-
if (
|
|
295
|
+
if (
|
|
296
|
+
key in this.progOptions &&
|
|
297
|
+
typeof this.progOptions[key] !== 'undefined'
|
|
298
|
+
) {
|
|
226
299
|
return this.progOptions[key];
|
|
227
300
|
}
|
|
228
|
-
if (
|
|
301
|
+
if (
|
|
302
|
+
key in this.fileOptions &&
|
|
303
|
+
typeof this.fileOptions[key] !== 'undefined'
|
|
304
|
+
) {
|
|
229
305
|
return this.fileOptions[key];
|
|
230
306
|
}
|
|
231
|
-
if (
|
|
307
|
+
if (
|
|
308
|
+
this.defaultOptions &&
|
|
309
|
+
key in this.defaultOptions &&
|
|
310
|
+
typeof this.defaultOptions[key] !== 'undefined'
|
|
311
|
+
) {
|
|
232
312
|
return this.defaultOptions[key];
|
|
233
313
|
}
|
|
234
314
|
if (key in this.defaults) {
|
|
@@ -264,27 +344,35 @@ class Config {
|
|
|
264
344
|
|
|
265
345
|
getAvailableLaunchers(cb) {
|
|
266
346
|
let browsers = knownBrowsers(process.platform, this);
|
|
267
|
-
browser_launcher.getAvailableBrowsers(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
347
|
+
browser_launcher.getAvailableBrowsers(
|
|
348
|
+
this,
|
|
349
|
+
browsers,
|
|
350
|
+
(err, availableBrowsers) => {
|
|
351
|
+
if (err) {
|
|
352
|
+
return cb(err);
|
|
353
|
+
}
|
|
271
354
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
355
|
+
let availableLaunchers = {};
|
|
356
|
+
availableBrowsers.forEach((browser) => {
|
|
357
|
+
let newLauncher = new LauncherFactory(browser.name, browser, this);
|
|
358
|
+
availableLaunchers[browser.name.toLowerCase()] = newLauncher;
|
|
359
|
+
});
|
|
277
360
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
361
|
+
// add custom launchers
|
|
362
|
+
let customLaunchers = this.get('launchers');
|
|
363
|
+
if (customLaunchers) {
|
|
364
|
+
for (let name in customLaunchers) {
|
|
365
|
+
let newLauncher = new LauncherFactory(
|
|
366
|
+
name,
|
|
367
|
+
customLaunchers[name],
|
|
368
|
+
this,
|
|
369
|
+
);
|
|
370
|
+
availableLaunchers[name.toLowerCase()] = newLauncher;
|
|
371
|
+
}
|
|
284
372
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
373
|
+
cb(null, availableLaunchers);
|
|
374
|
+
},
|
|
375
|
+
);
|
|
288
376
|
}
|
|
289
377
|
|
|
290
378
|
getLaunchers(cb) {
|
|
@@ -310,7 +398,7 @@ class Config {
|
|
|
310
398
|
let skip = this.get('skip');
|
|
311
399
|
if (skip) {
|
|
312
400
|
skip = skip.toLowerCase().split(',');
|
|
313
|
-
launchers = launchers.filter(name => skip.indexOf(name) === -1);
|
|
401
|
+
launchers = launchers.filter((name) => skip.indexOf(name) === -1);
|
|
314
402
|
}
|
|
315
403
|
return launchers;
|
|
316
404
|
}
|
|
@@ -320,7 +408,7 @@ class Config {
|
|
|
320
408
|
let wanted = this.getWantedLauncherNames(available);
|
|
321
409
|
let err = null;
|
|
322
410
|
|
|
323
|
-
wanted.forEach(name => {
|
|
411
|
+
wanted.forEach((name) => {
|
|
324
412
|
let launcher = available[name.toLowerCase()];
|
|
325
413
|
if (!launcher) {
|
|
326
414
|
if (this.appMode === 'dev' || this.get('ignore_missing_launchers')) {
|
|
@@ -328,10 +416,12 @@ class Config {
|
|
|
328
416
|
} else {
|
|
329
417
|
err = new Error(
|
|
330
418
|
'Launcher ' +
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
419
|
+
name +
|
|
420
|
+
' not found. Not installed? Available: ' +
|
|
421
|
+
Object.keys(available)
|
|
422
|
+
.map((elm) => `"${elm}"`)
|
|
423
|
+
.join(', ') +
|
|
424
|
+
'.',
|
|
335
425
|
);
|
|
336
426
|
}
|
|
337
427
|
} else {
|
|
@@ -343,38 +433,62 @@ class Config {
|
|
|
343
433
|
|
|
344
434
|
printLauncherInfo() {
|
|
345
435
|
this.getAvailableLaunchers((err, launchers) => {
|
|
346
|
-
let launch_in_dev = (this.get('launch_in_dev') || [])
|
|
347
|
-
|
|
436
|
+
let launch_in_dev = (this.get('launch_in_dev') || []).map((s) =>
|
|
437
|
+
s.toLowerCase(),
|
|
438
|
+
);
|
|
348
439
|
let launch_in_ci = this.get('launch_in_ci');
|
|
349
440
|
if (launch_in_ci) {
|
|
350
|
-
launch_in_ci = launch_in_ci.map(s => s.toLowerCase());
|
|
441
|
+
launch_in_ci = launch_in_ci.map((s) => s.toLowerCase());
|
|
351
442
|
}
|
|
352
|
-
launchers = Object.keys(launchers).map(k => launchers[k]);
|
|
443
|
+
launchers = Object.keys(launchers).map((k) => launchers[k]);
|
|
353
444
|
|
|
354
|
-
const launcherColumnWidth = launchers.reduce(
|
|
445
|
+
const launcherColumnWidth = launchers.reduce(
|
|
446
|
+
(acc, current) =>
|
|
447
|
+
acc > current.name.length ? acc : current.name.length,
|
|
448
|
+
0,
|
|
449
|
+
);
|
|
355
450
|
const launcherTitle = 'Launcher'.padEnd(launcherColumnWidth, ' ');
|
|
356
451
|
const launcherTitleDivider = ''.padEnd(launcherColumnWidth, '-');
|
|
357
452
|
|
|
358
|
-
console.log(
|
|
453
|
+
console.log(
|
|
454
|
+
'Have ' +
|
|
455
|
+
launchers.length +
|
|
456
|
+
' launchers available; auto-launch info displayed on the right.',
|
|
457
|
+
);
|
|
359
458
|
console.log(); // newline
|
|
360
459
|
console.log(`${launcherTitle} Type CI Dev`);
|
|
361
460
|
console.log(`${launcherTitleDivider} ------------ -- ---`);
|
|
362
|
-
console.log(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
461
|
+
console.log(
|
|
462
|
+
launchers
|
|
463
|
+
.map((launcher) => {
|
|
464
|
+
let protocol = launcher.settings.protocol;
|
|
465
|
+
let kind =
|
|
466
|
+
protocol === 'browser'
|
|
467
|
+
? 'browser'
|
|
468
|
+
: protocol === 'tap'
|
|
469
|
+
? 'process(TAP)'
|
|
470
|
+
: 'process';
|
|
471
|
+
let dev =
|
|
472
|
+
launch_in_dev.indexOf(launcher.name.toLowerCase()) !== -1
|
|
473
|
+
? Chars.mark
|
|
474
|
+
: ' ';
|
|
475
|
+
let ci =
|
|
476
|
+
!launch_in_ci ||
|
|
477
|
+
launch_in_ci.indexOf(launcher.name.toLowerCase()) !== -1
|
|
478
|
+
? Chars.mark
|
|
479
|
+
: ' ';
|
|
480
|
+
return (
|
|
481
|
+
pad(launcher.name, launcherColumnWidth + 2, ' ', 1) +
|
|
482
|
+
pad(kind, 12, ' ', 1) +
|
|
483
|
+
' ' +
|
|
484
|
+
ci +
|
|
485
|
+
' ' +
|
|
486
|
+
dev +
|
|
487
|
+
' '
|
|
488
|
+
);
|
|
489
|
+
})
|
|
490
|
+
.join('\n'),
|
|
491
|
+
);
|
|
378
492
|
});
|
|
379
493
|
}
|
|
380
494
|
|
|
@@ -389,7 +503,7 @@ class Config {
|
|
|
389
503
|
// Filter glob < 6 negation patterns to still support them
|
|
390
504
|
// See https://github.com/isaacs/node-glob/tree/3f883c43#comments-and-negation
|
|
391
505
|
let positiveWants = [];
|
|
392
|
-
want.forEach(patternEntry => {
|
|
506
|
+
want.forEach((patternEntry) => {
|
|
393
507
|
let pattern = isa(patternEntry, String) ? patternEntry : patternEntry.src;
|
|
394
508
|
if (pattern.indexOf('!') === 0) {
|
|
395
509
|
return dontWant.push(pattern.substring(1));
|
|
@@ -398,33 +512,51 @@ class Config {
|
|
|
398
512
|
positiveWants.push(patternEntry);
|
|
399
513
|
});
|
|
400
514
|
|
|
401
|
-
dontWant = dontWant.map(p => p ? this.resolvePath(p) : p);
|
|
402
|
-
return reduce(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
515
|
+
dontWant = dontWant.map((p) => (p ? this.resolvePath(p) : p));
|
|
516
|
+
return reduce(
|
|
517
|
+
positiveWants,
|
|
518
|
+
(allThatIWant, patternEntry) => {
|
|
519
|
+
let pattern = isa(patternEntry, String)
|
|
520
|
+
? patternEntry
|
|
521
|
+
: patternEntry.src;
|
|
522
|
+
let attrs = patternEntry.attrs || [];
|
|
523
|
+
let patternUrl = url.parse(pattern);
|
|
524
|
+
|
|
525
|
+
if (patternUrl.protocol === 'file:') {
|
|
526
|
+
pattern = patternUrl.hostname + patternUrl.path;
|
|
527
|
+
} else if (patternUrl.protocol) {
|
|
528
|
+
return allThatIWant.concat({ src: pattern, attrs: attrs });
|
|
529
|
+
}
|
|
412
530
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
},
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
531
|
+
return expandGlobPattern(
|
|
532
|
+
convertToPosix(this.resolvePath(pattern)),
|
|
533
|
+
dontWant.map(convertToPosix),
|
|
534
|
+
).then((files) =>
|
|
535
|
+
allThatIWant.concat(
|
|
536
|
+
files.map((f) => {
|
|
537
|
+
f = this.reverseResolvePath(f);
|
|
538
|
+
return { src: f, attrs: attrs };
|
|
539
|
+
}),
|
|
540
|
+
),
|
|
541
|
+
);
|
|
542
|
+
},
|
|
543
|
+
[],
|
|
544
|
+
)
|
|
545
|
+
.then((result) => _.uniqBy(result, 'src'))
|
|
546
|
+
.then(
|
|
547
|
+
(result) => {
|
|
548
|
+
if (callback) {
|
|
549
|
+
callback(null, result);
|
|
550
|
+
}
|
|
551
|
+
return result;
|
|
552
|
+
},
|
|
553
|
+
(err) => {
|
|
554
|
+
if (callback) {
|
|
555
|
+
callback(err);
|
|
556
|
+
}
|
|
557
|
+
throw err;
|
|
558
|
+
},
|
|
559
|
+
);
|
|
428
560
|
}
|
|
429
561
|
|
|
430
562
|
getSrcFiles(callback) {
|
|
@@ -440,10 +572,10 @@ class Config {
|
|
|
440
572
|
return this.getFileSet(want, dontWant, callback);
|
|
441
573
|
}
|
|
442
574
|
|
|
443
|
-
|
|
444
575
|
getServeFiles(callback) {
|
|
445
576
|
let want = this.get('serve_files') || this.get('src_files') || '*.js';
|
|
446
|
-
let dontWant =
|
|
577
|
+
let dontWant =
|
|
578
|
+
this.get('serve_files_ignore') || this.get('src_files_ignore') || '';
|
|
447
579
|
return this.getFileSet(want, dontWant, callback);
|
|
448
580
|
}
|
|
449
581
|
|
|
@@ -471,13 +603,19 @@ class Config {
|
|
|
471
603
|
return;
|
|
472
604
|
}
|
|
473
605
|
if (o.options) {
|
|
474
|
-
o.options.forEach(o => {
|
|
606
|
+
o.options.forEach((o) => {
|
|
475
607
|
options.push(o.name());
|
|
476
608
|
});
|
|
477
609
|
}
|
|
478
610
|
getOptions(o.parent);
|
|
479
611
|
}
|
|
480
|
-
|
|
612
|
+
const progOpts = this.progOptions;
|
|
613
|
+
// In subcommand modes, progOptions is a plain object from optsWithGlobals() with
|
|
614
|
+
// a _commander reference pointing to the Command instance for option enumeration.
|
|
615
|
+
// In dev mode (no subcommand), progOptions is the Commander program object directly.
|
|
616
|
+
getOptions(
|
|
617
|
+
progOpts && progOpts._commander ? progOpts._commander : progOpts,
|
|
618
|
+
);
|
|
481
619
|
return options;
|
|
482
620
|
}
|
|
483
621
|
|
|
@@ -497,16 +635,16 @@ class Config {
|
|
|
497
635
|
ret[key] = this.config[key];
|
|
498
636
|
}
|
|
499
637
|
|
|
500
|
-
const replaceSlashes = f => ({
|
|
638
|
+
const replaceSlashes = (f) => ({
|
|
501
639
|
src: f.src.replace(/\\/g, '/'),
|
|
502
|
-
attrs: f.attrs
|
|
640
|
+
attrs: f.attrs,
|
|
503
641
|
});
|
|
504
642
|
|
|
505
643
|
try {
|
|
506
644
|
const [serveFiles, cssFiles, footerScripts] = await Promise.all([
|
|
507
645
|
this.getServeFiles(),
|
|
508
646
|
this.getCSSFiles(),
|
|
509
|
-
this.getFooterScripts()
|
|
647
|
+
this.getFooterScripts(),
|
|
510
648
|
]);
|
|
511
649
|
|
|
512
650
|
ret.serve_files = serveFiles.map(replaceSlashes);
|
|
@@ -543,10 +681,13 @@ Config.prototype.defaults = {
|
|
|
543
681
|
client_decycle_depth: 5,
|
|
544
682
|
socket_heartbeat_timeout() {
|
|
545
683
|
let browserDisconnectTimeout = this.get('browser_disconnect_timeout');
|
|
546
|
-
let defaultBrowserDisconnectTimeout =
|
|
684
|
+
let defaultBrowserDisconnectTimeout =
|
|
685
|
+
this.defaults.browser_disconnect_timeout;
|
|
547
686
|
|
|
548
|
-
return
|
|
549
|
-
|
|
687
|
+
return browserDisconnectTimeout !== defaultBrowserDisconnectTimeout
|
|
688
|
+
? browserDisconnectTimeout
|
|
689
|
+
: 5;
|
|
690
|
+
},
|
|
550
691
|
};
|
|
551
692
|
|
|
552
693
|
module.exports = Config;
|