mocha-compat 3.6.4 → 10.8.2
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/LICENSE +1 -1
- package/README.md +61 -110
- package/bin/_mocha +10 -0
- package/bin/mocha.js +142 -0
- package/browser-entry.js +61 -22
- package/lib/browser/highlight-tags.js +39 -0
- package/lib/browser/parse-query.js +24 -0
- package/lib/{template.html → browser/template.html} +7 -5
- package/lib/cli/cli.js +89 -0
- package/lib/cli/collect-files.js +137 -0
- package/lib/cli/commands.js +14 -0
- package/lib/cli/config.js +100 -0
- package/lib/cli/index.js +3 -0
- package/lib/cli/init.js +36 -0
- package/lib/cli/lookup-files.js +150 -0
- package/lib/cli/node-flags.js +85 -0
- package/lib/cli/one-and-dones.js +69 -0
- package/lib/cli/options.js +284 -0
- package/lib/cli/run-helpers.js +304 -0
- package/lib/cli/run-option-metadata.js +116 -0
- package/lib/cli/run.js +380 -0
- package/lib/cli/watch-run.js +377 -0
- package/lib/context.js +16 -42
- package/lib/errors.js +563 -0
- package/lib/hook.js +50 -9
- package/lib/interfaces/bdd.js +28 -29
- package/lib/interfaces/common.js +56 -21
- package/lib/interfaces/exports.js +4 -7
- package/lib/interfaces/qunit.js +10 -11
- package/lib/interfaces/tdd.js +15 -15
- package/lib/mocha.js +1073 -292
- package/lib/mocharc.json +10 -0
- package/lib/nodejs/buffered-worker-pool.js +188 -0
- package/lib/nodejs/esm-utils.js +106 -0
- package/lib/nodejs/file-unloader.js +15 -0
- package/lib/nodejs/parallel-buffered-runner.js +433 -0
- package/lib/nodejs/reporters/parallel-buffered.js +165 -0
- package/lib/nodejs/serializer.js +414 -0
- package/lib/nodejs/worker.js +151 -0
- package/lib/pending.js +3 -3
- package/lib/plugin-loader.js +286 -0
- package/lib/reporters/base.js +305 -205
- package/lib/reporters/doc.js +52 -21
- package/lib/reporters/dot.js +31 -18
- package/lib/reporters/html.js +153 -81
- package/lib/reporters/json-stream.js +53 -24
- package/lib/reporters/json.js +88 -18
- package/lib/reporters/landing.js +38 -16
- package/lib/reporters/list.js +34 -19
- package/lib/reporters/markdown.js +28 -15
- package/lib/reporters/min.js +22 -8
- package/lib/reporters/nyan.js +62 -58
- package/lib/reporters/progress.js +32 -19
- package/lib/reporters/spec.js +41 -23
- package/lib/reporters/tap.js +255 -32
- package/lib/reporters/xunit.js +89 -39
- package/lib/runnable.js +233 -148
- package/lib/runner.js +679 -380
- package/lib/stats-collector.js +83 -0
- package/lib/suite.js +376 -112
- package/lib/test.js +82 -21
- package/lib/utils.js +364 -477
- package/mocha.css +183 -54
- package/mocha.js +19840 -15846
- package/mocha.js.map +1 -0
- package/package.json +163 -336
- package/{lib/to-iso-string → vendor/serialize-javascript}/LICENSE +8 -6
- package/vendor/serialize-javascript/README.md +10 -0
- package/vendor/serialize-javascript/index.js +349 -0
- package/bin/_mocha-compat +0 -572
- package/bin/mocha-compat +0 -87
- package/bin/options.js +0 -41
- package/bower.json +0 -38
- package/images/error.png +0 -0
- package/images/ok.png +0 -0
- package/lib/browser/.eslintrc.yaml +0 -4
- package/lib/browser/debug.js +0 -7
- package/lib/browser/events.js +0 -195
- package/lib/browser/progress.js +0 -119
- package/lib/browser/tty.js +0 -13
- package/lib/ms.js +0 -130
- package/lib/to-iso-string/index.js +0 -37
- package/vendor/glob/LICENSE +0 -15
- package/vendor/glob/README.md +0 -399
- package/vendor/glob/common.js +0 -244
- package/vendor/glob/glob.js +0 -788
- package/vendor/glob/package.json +0 -55
- package/vendor/glob/sync.js +0 -486
- package/vendor/inflight/LICENSE +0 -15
- package/vendor/inflight/README.md +0 -37
- package/vendor/inflight/inflight.js +0 -54
- package/vendor/inflight/package.json +0 -29
package/lib/utils.js
CHANGED
|
@@ -1,62 +1,45 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Various utility functions used throughout Mocha's codebase.
|
|
5
|
+
* @module utils
|
|
6
|
+
*/
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Module dependencies.
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
var JSON = require('json3');
|
|
10
|
-
var basename = require('path').basename;
|
|
11
|
-
var debug = require('debug')('mocha:watch');
|
|
12
|
-
var exists = require('fs').existsSync || require('path').existsSync;
|
|
13
|
-
var glob = require('../vendor/glob/glob.js');
|
|
14
11
|
var path = require('path');
|
|
15
|
-
var
|
|
16
|
-
var readdirSync = require('fs').readdirSync;
|
|
17
|
-
var statSync = require('fs').statSync;
|
|
18
|
-
var watchFile = require('fs').watchFile;
|
|
19
|
-
var lstatSync = require('fs').lstatSync;
|
|
20
|
-
var toISOString = require('./to-iso-string');
|
|
12
|
+
var util = require('util');
|
|
21
13
|
var he = require('he');
|
|
22
14
|
|
|
15
|
+
const MOCHA_ID_PROP_NAME = '__mocha_id__';
|
|
16
|
+
|
|
23
17
|
/**
|
|
24
|
-
*
|
|
18
|
+
* Inherit the prototype methods from one constructor into another.
|
|
19
|
+
*
|
|
20
|
+
* @param {function} ctor - Constructor function which needs to inherit the
|
|
21
|
+
* prototype.
|
|
22
|
+
* @param {function} superCtor - Constructor function to inherit prototype from.
|
|
23
|
+
* @throws {TypeError} if either constructor is null, or if super constructor
|
|
24
|
+
* lacks a prototype.
|
|
25
25
|
*/
|
|
26
|
-
|
|
27
|
-
var ignore = ['node_modules', '.git'];
|
|
28
|
-
|
|
29
|
-
exports.inherits = require('util').inherits;
|
|
26
|
+
exports.inherits = util.inherits;
|
|
30
27
|
|
|
31
28
|
/**
|
|
32
29
|
* Escape special characters in the given string of html.
|
|
33
30
|
*
|
|
34
|
-
* @
|
|
31
|
+
* @private
|
|
35
32
|
* @param {string} html
|
|
36
33
|
* @return {string}
|
|
37
34
|
*/
|
|
38
35
|
exports.escape = function (html) {
|
|
39
|
-
return he.encode(String(html), {
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Array#forEach (<=IE8)
|
|
44
|
-
*
|
|
45
|
-
* @api private
|
|
46
|
-
* @param {Array} arr
|
|
47
|
-
* @param {Function} fn
|
|
48
|
-
* @param {Object} scope
|
|
49
|
-
*/
|
|
50
|
-
exports.forEach = function (arr, fn, scope) {
|
|
51
|
-
for (var i = 0, l = arr.length; i < l; i++) {
|
|
52
|
-
fn.call(scope, arr[i], i);
|
|
53
|
-
}
|
|
36
|
+
return he.encode(String(html), {useNamedReferences: false});
|
|
54
37
|
};
|
|
55
38
|
|
|
56
39
|
/**
|
|
57
40
|
* Test if the given obj is type of string.
|
|
58
41
|
*
|
|
59
|
-
* @
|
|
42
|
+
* @private
|
|
60
43
|
* @param {Object} obj
|
|
61
44
|
* @return {boolean}
|
|
62
45
|
*/
|
|
@@ -64,214 +47,19 @@ exports.isString = function (obj) {
|
|
|
64
47
|
return typeof obj === 'string';
|
|
65
48
|
};
|
|
66
49
|
|
|
67
|
-
/**
|
|
68
|
-
* Array#map (<=IE8)
|
|
69
|
-
*
|
|
70
|
-
* @api private
|
|
71
|
-
* @param {Array} arr
|
|
72
|
-
* @param {Function} fn
|
|
73
|
-
* @param {Object} scope
|
|
74
|
-
* @return {Array}
|
|
75
|
-
*/
|
|
76
|
-
exports.map = function (arr, fn, scope) {
|
|
77
|
-
var result = [];
|
|
78
|
-
for (var i = 0, l = arr.length; i < l; i++) {
|
|
79
|
-
result.push(fn.call(scope, arr[i], i, arr));
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Array#indexOf (<=IE8)
|
|
86
|
-
*
|
|
87
|
-
* @api private
|
|
88
|
-
* @param {Array} arr
|
|
89
|
-
* @param {Object} obj to find index of
|
|
90
|
-
* @param {number} start
|
|
91
|
-
* @return {number}
|
|
92
|
-
*/
|
|
93
|
-
var indexOf = exports.indexOf = function (arr, obj, start) {
|
|
94
|
-
for (var i = start || 0, l = arr.length; i < l; i++) {
|
|
95
|
-
if (arr[i] === obj) {
|
|
96
|
-
return i;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return -1;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Array#reduce (<=IE8)
|
|
104
|
-
*
|
|
105
|
-
* @api private
|
|
106
|
-
* @param {Array} arr
|
|
107
|
-
* @param {Function} fn
|
|
108
|
-
* @param {Object} val Initial value.
|
|
109
|
-
* @return {*}
|
|
110
|
-
*/
|
|
111
|
-
var reduce = exports.reduce = function (arr, fn, val) {
|
|
112
|
-
var rval = val;
|
|
113
|
-
|
|
114
|
-
for (var i = 0, l = arr.length; i < l; i++) {
|
|
115
|
-
rval = fn(rval, arr[i], i, arr);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return rval;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Array#filter (<=IE8)
|
|
123
|
-
*
|
|
124
|
-
* @api private
|
|
125
|
-
* @param {Array} arr
|
|
126
|
-
* @param {Function} fn
|
|
127
|
-
* @return {Array}
|
|
128
|
-
*/
|
|
129
|
-
exports.filter = function (arr, fn) {
|
|
130
|
-
var ret = [];
|
|
131
|
-
|
|
132
|
-
for (var i = 0, l = arr.length; i < l; i++) {
|
|
133
|
-
var val = arr[i];
|
|
134
|
-
if (fn(val, i, arr)) {
|
|
135
|
-
ret.push(val);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return ret;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Array#some (<=IE8)
|
|
144
|
-
*
|
|
145
|
-
* @api private
|
|
146
|
-
* @param {Array} arr
|
|
147
|
-
* @param {Function} fn
|
|
148
|
-
* @return {Array}
|
|
149
|
-
*/
|
|
150
|
-
exports.some = function (arr, fn) {
|
|
151
|
-
for (var i = 0, l = arr.length; i < l; i++) {
|
|
152
|
-
if (fn(arr[i])) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return false;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Object.keys (<=IE8)
|
|
161
|
-
*
|
|
162
|
-
* @api private
|
|
163
|
-
* @param {Object} obj
|
|
164
|
-
* @return {Array} keys
|
|
165
|
-
*/
|
|
166
|
-
exports.keys = typeof Object.keys === 'function' ? Object.keys : function (obj) {
|
|
167
|
-
var keys = [];
|
|
168
|
-
var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8
|
|
169
|
-
|
|
170
|
-
for (var key in obj) {
|
|
171
|
-
if (has.call(obj, key)) {
|
|
172
|
-
keys.push(key);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return keys;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Watch the given `files` for changes
|
|
181
|
-
* and invoke `fn(file)` on modification.
|
|
182
|
-
*
|
|
183
|
-
* @api private
|
|
184
|
-
* @param {Array} files
|
|
185
|
-
* @param {Function} fn
|
|
186
|
-
*/
|
|
187
|
-
exports.watch = function (files, fn) {
|
|
188
|
-
var options = { interval: 100 };
|
|
189
|
-
files.forEach(function (file) {
|
|
190
|
-
debug('file %s', file);
|
|
191
|
-
watchFile(file, options, function (curr, prev) {
|
|
192
|
-
if (prev.mtime < curr.mtime) {
|
|
193
|
-
fn(file);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Array.isArray (<=IE8)
|
|
201
|
-
*
|
|
202
|
-
* @api private
|
|
203
|
-
* @param {Object} obj
|
|
204
|
-
* @return {Boolean}
|
|
205
|
-
*/
|
|
206
|
-
var isArray = typeof Array.isArray === 'function' ? Array.isArray : function (obj) {
|
|
207
|
-
return Object.prototype.toString.call(obj) === '[object Array]';
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
exports.isArray = isArray;
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Buffer.prototype.toJSON polyfill.
|
|
214
|
-
*
|
|
215
|
-
* @type {Function}
|
|
216
|
-
*/
|
|
217
|
-
if (typeof Buffer !== 'undefined' && Buffer.prototype) {
|
|
218
|
-
Buffer.prototype.toJSON = Buffer.prototype.toJSON || function () {
|
|
219
|
-
return Array.prototype.slice.call(this, 0);
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Ignored files.
|
|
225
|
-
*
|
|
226
|
-
* @api private
|
|
227
|
-
* @param {string} path
|
|
228
|
-
* @return {boolean}
|
|
229
|
-
*/
|
|
230
|
-
function ignored (path) {
|
|
231
|
-
return !~ignore.indexOf(path);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Lookup files in the given `dir`.
|
|
236
|
-
*
|
|
237
|
-
* @api private
|
|
238
|
-
* @param {string} dir
|
|
239
|
-
* @param {string[]} [ext=['.js']]
|
|
240
|
-
* @param {Array} [ret=[]]
|
|
241
|
-
* @return {Array}
|
|
242
|
-
*/
|
|
243
|
-
exports.files = function (dir, ext, ret) {
|
|
244
|
-
ret = ret || [];
|
|
245
|
-
ext = ext || ['js'];
|
|
246
|
-
|
|
247
|
-
var re = new RegExp('\\.(' + ext.join('|') + ')$');
|
|
248
|
-
|
|
249
|
-
readdirSync(dir)
|
|
250
|
-
.filter(ignored)
|
|
251
|
-
.forEach(function (path) {
|
|
252
|
-
path = join(dir, path);
|
|
253
|
-
if (lstatSync(path).isDirectory()) {
|
|
254
|
-
exports.files(path, ext, ret);
|
|
255
|
-
} else if (path.match(re)) {
|
|
256
|
-
ret.push(path);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
return ret;
|
|
261
|
-
};
|
|
262
|
-
|
|
263
50
|
/**
|
|
264
51
|
* Compute a slug from the given `str`.
|
|
265
52
|
*
|
|
266
|
-
* @
|
|
53
|
+
* @private
|
|
267
54
|
* @param {string} str
|
|
268
55
|
* @return {string}
|
|
269
56
|
*/
|
|
270
57
|
exports.slug = function (str) {
|
|
271
58
|
return str
|
|
272
59
|
.toLowerCase()
|
|
273
|
-
.replace(
|
|
274
|
-
.replace(/[^-\w]/g, '')
|
|
60
|
+
.replace(/\s+/g, '-')
|
|
61
|
+
.replace(/[^-\w]/g, '')
|
|
62
|
+
.replace(/-{2,}/g, '-');
|
|
275
63
|
};
|
|
276
64
|
|
|
277
65
|
/**
|
|
@@ -282,80 +70,24 @@ exports.slug = function (str) {
|
|
|
282
70
|
*/
|
|
283
71
|
exports.clean = function (str) {
|
|
284
72
|
str = str
|
|
285
|
-
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
|
73
|
+
.replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
|
|
74
|
+
.replace(/^\uFEFF/, '')
|
|
286
75
|
// (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
|
|
287
|
-
.replace(
|
|
76
|
+
.replace(
|
|
77
|
+
/^function(?:\s*|\s[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\}|((?:.|\n)*))$/,
|
|
78
|
+
'$1$2$3'
|
|
79
|
+
);
|
|
288
80
|
|
|
289
81
|
var spaces = str.match(/^\n?( *)/)[1].length;
|
|
290
82
|
var tabs = str.match(/^\n?(\t*)/)[1].length;
|
|
291
|
-
var re = new RegExp(
|
|
83
|
+
var re = new RegExp(
|
|
84
|
+
'^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
|
|
85
|
+
'gm'
|
|
86
|
+
);
|
|
292
87
|
|
|
293
88
|
str = str.replace(re, '');
|
|
294
89
|
|
|
295
|
-
return
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Trim the given `str`.
|
|
300
|
-
*
|
|
301
|
-
* @api private
|
|
302
|
-
* @param {string} str
|
|
303
|
-
* @return {string}
|
|
304
|
-
*/
|
|
305
|
-
exports.trim = function (str) {
|
|
306
|
-
return str.replace(/^\s+|\s+$/g, '');
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Parse the given `qs`.
|
|
311
|
-
*
|
|
312
|
-
* @api private
|
|
313
|
-
* @param {string} qs
|
|
314
|
-
* @return {Object}
|
|
315
|
-
*/
|
|
316
|
-
exports.parseQuery = function (qs) {
|
|
317
|
-
return reduce(qs.replace('?', '').split('&'), function (obj, pair) {
|
|
318
|
-
var i = pair.indexOf('=');
|
|
319
|
-
var key = pair.slice(0, i);
|
|
320
|
-
var val = pair.slice(++i);
|
|
321
|
-
|
|
322
|
-
// Due to how the URLSearchParams API treats spaces
|
|
323
|
-
obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
|
|
324
|
-
|
|
325
|
-
return obj;
|
|
326
|
-
}, {});
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Highlight the given string of `js`.
|
|
331
|
-
*
|
|
332
|
-
* @api private
|
|
333
|
-
* @param {string} js
|
|
334
|
-
* @return {string}
|
|
335
|
-
*/
|
|
336
|
-
function highlight (js) {
|
|
337
|
-
return js
|
|
338
|
-
.replace(/</g, '<')
|
|
339
|
-
.replace(/>/g, '>')
|
|
340
|
-
.replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
|
|
341
|
-
.replace(/('.*?')/gm, '<span class="string">$1</span>')
|
|
342
|
-
.replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
|
|
343
|
-
.replace(/(\d+)/gm, '<span class="number">$1</span>')
|
|
344
|
-
.replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
|
|
345
|
-
.replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Highlight the contents of tag `name`.
|
|
350
|
-
*
|
|
351
|
-
* @api private
|
|
352
|
-
* @param {string} name
|
|
353
|
-
*/
|
|
354
|
-
exports.highlightTags = function (name) {
|
|
355
|
-
var code = document.getElementById('mocha').getElementsByTagName(name);
|
|
356
|
-
for (var i = 0, len = code.length; i < len; ++i) {
|
|
357
|
-
code[i].innerHTML = highlight(code[i].innerHTML);
|
|
358
|
-
}
|
|
90
|
+
return str.trim();
|
|
359
91
|
};
|
|
360
92
|
|
|
361
93
|
/**
|
|
@@ -367,12 +99,12 @@ exports.highlightTags = function (name) {
|
|
|
367
99
|
* Objects w/ no properties return `'{}'`
|
|
368
100
|
* All else: return result of `value.toString()`
|
|
369
101
|
*
|
|
370
|
-
* @
|
|
102
|
+
* @private
|
|
371
103
|
* @param {*} value The value to inspect.
|
|
372
104
|
* @param {string} typeHint The type of the value
|
|
373
105
|
* @returns {string}
|
|
374
106
|
*/
|
|
375
|
-
function emptyRepresentation
|
|
107
|
+
function emptyRepresentation(value, typeHint) {
|
|
376
108
|
switch (typeHint) {
|
|
377
109
|
case 'function':
|
|
378
110
|
return '[Function]';
|
|
@@ -389,34 +121,81 @@ function emptyRepresentation (value, typeHint) {
|
|
|
389
121
|
* Takes some variable and asks `Object.prototype.toString()` what it thinks it
|
|
390
122
|
* is.
|
|
391
123
|
*
|
|
392
|
-
* @
|
|
124
|
+
* @private
|
|
393
125
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
|
|
394
126
|
* @param {*} value The value to test.
|
|
395
127
|
* @returns {string} Computed type
|
|
396
128
|
* @example
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
|
|
409
|
-
|
|
129
|
+
* canonicalType({}) // 'object'
|
|
130
|
+
* canonicalType([]) // 'array'
|
|
131
|
+
* canonicalType(1) // 'number'
|
|
132
|
+
* canonicalType(false) // 'boolean'
|
|
133
|
+
* canonicalType(Infinity) // 'number'
|
|
134
|
+
* canonicalType(null) // 'null'
|
|
135
|
+
* canonicalType(new Date()) // 'date'
|
|
136
|
+
* canonicalType(/foo/) // 'regexp'
|
|
137
|
+
* canonicalType('type') // 'string'
|
|
138
|
+
* canonicalType(global) // 'global'
|
|
139
|
+
* canonicalType(new String('foo') // 'object'
|
|
140
|
+
* canonicalType(async function() {}) // 'asyncfunction'
|
|
141
|
+
* canonicalType(Object.create(null)) // 'null-prototype'
|
|
142
|
+
*/
|
|
143
|
+
var canonicalType = (exports.canonicalType = function canonicalType(value) {
|
|
410
144
|
if (value === undefined) {
|
|
411
145
|
return 'undefined';
|
|
412
146
|
} else if (value === null) {
|
|
413
147
|
return 'null';
|
|
414
|
-
} else if (
|
|
148
|
+
} else if (Buffer.isBuffer(value)) {
|
|
415
149
|
return 'buffer';
|
|
150
|
+
} else if (Object.getPrototypeOf(value) === null) {
|
|
151
|
+
return 'null-prototype';
|
|
416
152
|
}
|
|
417
|
-
|
|
153
|
+
|
|
154
|
+
return Object.prototype.toString
|
|
155
|
+
.call(value)
|
|
418
156
|
.replace(/^\[.+\s(.+?)]$/, '$1')
|
|
419
157
|
.toLowerCase();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
*
|
|
162
|
+
* Returns a general type or data structure of a variable
|
|
163
|
+
* @private
|
|
164
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
|
|
165
|
+
* @param {*} value The value to test.
|
|
166
|
+
* @returns {string} One of undefined, boolean, number, string, bigint, symbol, object
|
|
167
|
+
* @example
|
|
168
|
+
* type({}) // 'object'
|
|
169
|
+
* type([]) // 'array'
|
|
170
|
+
* type(1) // 'number'
|
|
171
|
+
* type(false) // 'boolean'
|
|
172
|
+
* type(Infinity) // 'number'
|
|
173
|
+
* type(null) // 'null'
|
|
174
|
+
* type(new Date()) // 'object'
|
|
175
|
+
* type(/foo/) // 'object'
|
|
176
|
+
* type('type') // 'string'
|
|
177
|
+
* type(global) // 'object'
|
|
178
|
+
* type(new String('foo') // 'string'
|
|
179
|
+
*/
|
|
180
|
+
exports.type = function type(value) {
|
|
181
|
+
// Null is special
|
|
182
|
+
if (value === null) return 'null';
|
|
183
|
+
const primitives = new Set([
|
|
184
|
+
'undefined',
|
|
185
|
+
'boolean',
|
|
186
|
+
'number',
|
|
187
|
+
'string',
|
|
188
|
+
'bigint',
|
|
189
|
+
'symbol'
|
|
190
|
+
]);
|
|
191
|
+
const _type = typeof value;
|
|
192
|
+
if (_type === 'function') return _type;
|
|
193
|
+
if (primitives.has(_type)) return _type;
|
|
194
|
+
if (value instanceof String) return 'string';
|
|
195
|
+
if (value instanceof Error) return 'error';
|
|
196
|
+
if (Array.isArray(value)) return 'array';
|
|
197
|
+
|
|
198
|
+
return _type;
|
|
420
199
|
};
|
|
421
200
|
|
|
422
201
|
/**
|
|
@@ -429,26 +208,28 @@ var type = exports.type = function type (value) {
|
|
|
429
208
|
* - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
|
|
430
209
|
* JSON.stringify().
|
|
431
210
|
*
|
|
432
|
-
* @
|
|
211
|
+
* @private
|
|
433
212
|
* @see exports.type
|
|
434
213
|
* @param {*} value
|
|
435
214
|
* @return {string}
|
|
436
215
|
*/
|
|
437
216
|
exports.stringify = function (value) {
|
|
438
|
-
var typeHint =
|
|
217
|
+
var typeHint = canonicalType(value);
|
|
439
218
|
|
|
440
|
-
if (!~
|
|
219
|
+
if (!~['object', 'array', 'function', 'null-prototype'].indexOf(typeHint)) {
|
|
441
220
|
if (typeHint === 'buffer') {
|
|
442
|
-
var json =
|
|
221
|
+
var json = Buffer.prototype.toJSON.call(value);
|
|
443
222
|
// Based on the toJSON result
|
|
444
|
-
return jsonStringify(
|
|
445
|
-
.
|
|
223
|
+
return jsonStringify(
|
|
224
|
+
json.data && json.type ? json.data : json,
|
|
225
|
+
2
|
|
226
|
+
).replace(/,(\n|$)/g, '$1');
|
|
446
227
|
}
|
|
447
228
|
|
|
448
229
|
// IE7/IE8 has a bizarre String constructor; needs to be coerced
|
|
449
230
|
// into an array and back to obj.
|
|
450
231
|
if (typeHint === 'string' && typeof value === 'object') {
|
|
451
|
-
value =
|
|
232
|
+
value = value.split('').reduce(function (acc, char, idx) {
|
|
452
233
|
acc[idx] = char;
|
|
453
234
|
return acc;
|
|
454
235
|
}, {});
|
|
@@ -460,7 +241,10 @@ exports.stringify = function (value) {
|
|
|
460
241
|
|
|
461
242
|
for (var prop in value) {
|
|
462
243
|
if (Object.prototype.hasOwnProperty.call(value, prop)) {
|
|
463
|
-
return jsonStringify(
|
|
244
|
+
return jsonStringify(
|
|
245
|
+
exports.canonicalize(value, null, typeHint),
|
|
246
|
+
2
|
|
247
|
+
).replace(/,(\n|$)/g, '$1');
|
|
464
248
|
}
|
|
465
249
|
}
|
|
466
250
|
|
|
@@ -470,13 +254,13 @@ exports.stringify = function (value) {
|
|
|
470
254
|
/**
|
|
471
255
|
* like JSON.stringify but more sense.
|
|
472
256
|
*
|
|
473
|
-
* @
|
|
257
|
+
* @private
|
|
474
258
|
* @param {Object} object
|
|
475
259
|
* @param {number=} spaces
|
|
476
260
|
* @param {number=} depth
|
|
477
261
|
* @returns {*}
|
|
478
262
|
*/
|
|
479
|
-
function jsonStringify
|
|
263
|
+
function jsonStringify(object, spaces, depth) {
|
|
480
264
|
if (typeof spaces === 'undefined') {
|
|
481
265
|
// primitive types
|
|
482
266
|
return _stringify(object);
|
|
@@ -484,16 +268,19 @@ function jsonStringify (object, spaces, depth) {
|
|
|
484
268
|
|
|
485
269
|
depth = depth || 1;
|
|
486
270
|
var space = spaces * depth;
|
|
487
|
-
var str = isArray(object) ? '[' : '{';
|
|
488
|
-
var end = isArray(object) ? ']' : '}';
|
|
489
|
-
var length =
|
|
271
|
+
var str = Array.isArray(object) ? '[' : '{';
|
|
272
|
+
var end = Array.isArray(object) ? ']' : '}';
|
|
273
|
+
var length =
|
|
274
|
+
typeof object.length === 'number'
|
|
275
|
+
? object.length
|
|
276
|
+
: Object.keys(object).length;
|
|
490
277
|
// `.repeat()` polyfill
|
|
491
|
-
function repeat
|
|
278
|
+
function repeat(s, n) {
|
|
492
279
|
return new Array(n).join(s);
|
|
493
280
|
}
|
|
494
281
|
|
|
495
|
-
function _stringify
|
|
496
|
-
switch (
|
|
282
|
+
function _stringify(val) {
|
|
283
|
+
switch (canonicalType(val)) {
|
|
497
284
|
case 'null':
|
|
498
285
|
case 'undefined':
|
|
499
286
|
val = '[' + val + ']';
|
|
@@ -506,17 +293,16 @@ function jsonStringify (object, spaces, depth) {
|
|
|
506
293
|
case 'regexp':
|
|
507
294
|
case 'symbol':
|
|
508
295
|
case 'number':
|
|
509
|
-
val =
|
|
510
|
-
|
|
511
|
-
|
|
296
|
+
val =
|
|
297
|
+
val === 0 && 1 / val === -Infinity // `-0`
|
|
298
|
+
? '-0'
|
|
299
|
+
: val.toString();
|
|
300
|
+
break;
|
|
301
|
+
case 'bigint':
|
|
302
|
+
val = val.toString() + 'n';
|
|
512
303
|
break;
|
|
513
304
|
case 'date':
|
|
514
|
-
var sDate;
|
|
515
|
-
if (isNaN(val.getTime())) { // Invalid date
|
|
516
|
-
sDate = val.toString();
|
|
517
|
-
} else {
|
|
518
|
-
sDate = val.toISOString ? val.toISOString() : toISOString(val);
|
|
519
|
-
}
|
|
305
|
+
var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
|
|
520
306
|
val = '[Date: ' + sDate + ']';
|
|
521
307
|
break;
|
|
522
308
|
case 'buffer':
|
|
@@ -526,9 +312,10 @@ function jsonStringify (object, spaces, depth) {
|
|
|
526
312
|
val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
|
|
527
313
|
break;
|
|
528
314
|
default:
|
|
529
|
-
val =
|
|
530
|
-
|
|
531
|
-
|
|
315
|
+
val =
|
|
316
|
+
val === '[Function]' || val === '[Circular]'
|
|
317
|
+
? val
|
|
318
|
+
: JSON.stringify(val); // string
|
|
532
319
|
}
|
|
533
320
|
return val;
|
|
534
321
|
}
|
|
@@ -538,28 +325,21 @@ function jsonStringify (object, spaces, depth) {
|
|
|
538
325
|
continue; // not my business
|
|
539
326
|
}
|
|
540
327
|
--length;
|
|
541
|
-
str +=
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
(
|
|
328
|
+
str +=
|
|
329
|
+
'\n ' +
|
|
330
|
+
repeat(' ', space) +
|
|
331
|
+
(Array.isArray(object) ? '' : '"' + i + '": ') + // key
|
|
332
|
+
_stringify(object[i]) + // value
|
|
333
|
+
(length ? ',' : ''); // comma
|
|
545
334
|
}
|
|
546
335
|
|
|
547
|
-
return
|
|
336
|
+
return (
|
|
337
|
+
str +
|
|
548
338
|
// [], {}
|
|
549
|
-
(str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
|
|
339
|
+
(str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
|
|
340
|
+
);
|
|
550
341
|
}
|
|
551
342
|
|
|
552
|
-
/**
|
|
553
|
-
* Test if a value is a buffer.
|
|
554
|
-
*
|
|
555
|
-
* @api private
|
|
556
|
-
* @param {*} value The value to test.
|
|
557
|
-
* @return {boolean} True if `value` is a buffer, otherwise false
|
|
558
|
-
*/
|
|
559
|
-
exports.isBuffer = function (value) {
|
|
560
|
-
return typeof Buffer !== 'undefined' && Buffer.isBuffer(value);
|
|
561
|
-
};
|
|
562
|
-
|
|
563
343
|
/**
|
|
564
344
|
* Return a new Thing that has the keys in sorted order. Recursive.
|
|
565
345
|
*
|
|
@@ -572,20 +352,20 @@ exports.isBuffer = function (value) {
|
|
|
572
352
|
* - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
|
|
573
353
|
* - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
|
|
574
354
|
*
|
|
575
|
-
* @
|
|
355
|
+
* @private
|
|
576
356
|
* @see {@link exports.stringify}
|
|
577
357
|
* @param {*} value Thing to inspect. May or may not have properties.
|
|
578
358
|
* @param {Array} [stack=[]] Stack of seen values
|
|
579
359
|
* @param {string} [typeHint] Type hint
|
|
580
360
|
* @return {(Object|Array|Function|string|undefined)}
|
|
581
361
|
*/
|
|
582
|
-
exports.canonicalize = function canonicalize
|
|
362
|
+
exports.canonicalize = function canonicalize(value, stack, typeHint) {
|
|
583
363
|
var canonicalizedObj;
|
|
584
364
|
/* eslint-disable no-unused-vars */
|
|
585
365
|
var prop;
|
|
586
366
|
/* eslint-enable no-unused-vars */
|
|
587
|
-
typeHint = typeHint ||
|
|
588
|
-
function withStack
|
|
367
|
+
typeHint = typeHint || canonicalType(value);
|
|
368
|
+
function withStack(value, fn) {
|
|
589
369
|
stack.push(value);
|
|
590
370
|
fn();
|
|
591
371
|
stack.pop();
|
|
@@ -593,7 +373,7 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
593
373
|
|
|
594
374
|
stack = stack || [];
|
|
595
375
|
|
|
596
|
-
if (indexOf(
|
|
376
|
+
if (stack.indexOf(value) !== -1) {
|
|
597
377
|
return '[Circular]';
|
|
598
378
|
}
|
|
599
379
|
|
|
@@ -605,13 +385,13 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
605
385
|
break;
|
|
606
386
|
case 'array':
|
|
607
387
|
withStack(value, function () {
|
|
608
|
-
canonicalizedObj =
|
|
388
|
+
canonicalizedObj = value.map(function (item) {
|
|
609
389
|
return exports.canonicalize(item, stack);
|
|
610
390
|
});
|
|
611
391
|
});
|
|
612
392
|
break;
|
|
613
393
|
case 'function':
|
|
614
|
-
/* eslint-disable
|
|
394
|
+
/* eslint-disable-next-line no-unused-vars, no-unreachable-loop */
|
|
615
395
|
for (prop in value) {
|
|
616
396
|
canonicalizedObj = {};
|
|
617
397
|
break;
|
|
@@ -622,12 +402,18 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
622
402
|
break;
|
|
623
403
|
}
|
|
624
404
|
/* falls through */
|
|
405
|
+
case 'null-prototype':
|
|
625
406
|
case 'object':
|
|
626
407
|
canonicalizedObj = canonicalizedObj || {};
|
|
408
|
+
if (typeHint === 'null-prototype' && Symbol.toStringTag in value) {
|
|
409
|
+
canonicalizedObj['[Symbol.toStringTag]'] = value[Symbol.toStringTag];
|
|
410
|
+
}
|
|
627
411
|
withStack(value, function () {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
412
|
+
Object.keys(value)
|
|
413
|
+
.sort()
|
|
414
|
+
.forEach(function (key) {
|
|
415
|
+
canonicalizedObj[key] = exports.canonicalize(value[key], stack);
|
|
416
|
+
});
|
|
631
417
|
});
|
|
632
418
|
break;
|
|
633
419
|
case 'date':
|
|
@@ -644,85 +430,6 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
|
|
|
644
430
|
return canonicalizedObj;
|
|
645
431
|
};
|
|
646
432
|
|
|
647
|
-
/**
|
|
648
|
-
* Lookup file names at the given `path`.
|
|
649
|
-
*
|
|
650
|
-
* @api public
|
|
651
|
-
* @param {string} path Base path to start searching from.
|
|
652
|
-
* @param {string[]} extensions File extensions to look for.
|
|
653
|
-
* @param {boolean} recursive Whether or not to recurse into subdirectories.
|
|
654
|
-
* @return {string[]} An array of paths.
|
|
655
|
-
*/
|
|
656
|
-
exports.lookupFiles = function lookupFiles (path, extensions, recursive) {
|
|
657
|
-
var files = [];
|
|
658
|
-
var re = new RegExp('\\.(' + extensions.join('|') + ')$');
|
|
659
|
-
|
|
660
|
-
if (!exists(path)) {
|
|
661
|
-
if (exists(path + '.js')) {
|
|
662
|
-
path += '.js';
|
|
663
|
-
} else {
|
|
664
|
-
files = glob.sync(path);
|
|
665
|
-
if (!files.length) {
|
|
666
|
-
throw new Error("cannot resolve path (or pattern) '" + path + "'");
|
|
667
|
-
}
|
|
668
|
-
return files;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
try {
|
|
673
|
-
var stat = statSync(path);
|
|
674
|
-
if (stat.isFile()) {
|
|
675
|
-
return path;
|
|
676
|
-
}
|
|
677
|
-
} catch (err) {
|
|
678
|
-
// ignore error
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
readdirSync(path).forEach(function (file) {
|
|
683
|
-
file = join(path, file);
|
|
684
|
-
try {
|
|
685
|
-
var stat = statSync(file);
|
|
686
|
-
if (stat.isDirectory()) {
|
|
687
|
-
if (recursive) {
|
|
688
|
-
files = files.concat(lookupFiles(file, extensions, recursive));
|
|
689
|
-
}
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
} catch (err) {
|
|
693
|
-
// ignore error
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') {
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
files.push(file);
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
return files;
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Generate an undefined error with a message warning the user.
|
|
707
|
-
*
|
|
708
|
-
* @return {Error}
|
|
709
|
-
*/
|
|
710
|
-
|
|
711
|
-
exports.undefinedError = function () {
|
|
712
|
-
return new Error('Caught undefined error, did you throw without specifying what?');
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
/**
|
|
716
|
-
* Generate an undefined error if `err` is not defined.
|
|
717
|
-
*
|
|
718
|
-
* @param {Error} err
|
|
719
|
-
* @return {Error}
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
|
-
exports.getError = function (err) {
|
|
723
|
-
return err || exports.undefinedError();
|
|
724
|
-
};
|
|
725
|
-
|
|
726
433
|
/**
|
|
727
434
|
* @summary
|
|
728
435
|
* This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
|
|
@@ -734,38 +441,41 @@ exports.getError = function (err) {
|
|
|
734
441
|
*/
|
|
735
442
|
exports.stackTraceFilter = function () {
|
|
736
443
|
// TODO: Replace with `process.browser`
|
|
737
|
-
var is = typeof document === 'undefined' ? {
|
|
444
|
+
var is = typeof document === 'undefined' ? {node: true} : {browser: true};
|
|
738
445
|
var slash = path.sep;
|
|
739
446
|
var cwd;
|
|
740
447
|
if (is.node) {
|
|
741
|
-
cwd =
|
|
448
|
+
cwd = exports.cwd() + slash;
|
|
742
449
|
} else {
|
|
743
|
-
cwd = (
|
|
744
|
-
? window.location
|
|
745
|
-
|
|
450
|
+
cwd = (
|
|
451
|
+
typeof location === 'undefined' ? window.location : location
|
|
452
|
+
).href.replace(/\/[^/]*$/, '/');
|
|
746
453
|
slash = '/';
|
|
747
454
|
}
|
|
748
455
|
|
|
749
|
-
function isMochaInternal
|
|
750
|
-
return (
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
456
|
+
function isMochaInternal(line) {
|
|
457
|
+
return (
|
|
458
|
+
~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
|
|
459
|
+
~line.indexOf(slash + 'mocha.js') ||
|
|
460
|
+
~line.indexOf(slash + 'mocha.min.js')
|
|
461
|
+
);
|
|
754
462
|
}
|
|
755
463
|
|
|
756
|
-
function isNodeInternal
|
|
757
|
-
return (
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
464
|
+
function isNodeInternal(line) {
|
|
465
|
+
return (
|
|
466
|
+
~line.indexOf('(timers.js:') ||
|
|
467
|
+
~line.indexOf('(events.js:') ||
|
|
468
|
+
~line.indexOf('(node.js:') ||
|
|
469
|
+
~line.indexOf('(module.js:') ||
|
|
470
|
+
~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
|
|
471
|
+
false
|
|
472
|
+
);
|
|
763
473
|
}
|
|
764
474
|
|
|
765
475
|
return function (stack) {
|
|
766
476
|
stack = stack.split('\n');
|
|
767
477
|
|
|
768
|
-
stack = reduce(
|
|
478
|
+
stack = stack.reduce(function (list, line) {
|
|
769
479
|
if (isMochaInternal(line)) {
|
|
770
480
|
return list;
|
|
771
481
|
}
|
|
@@ -775,8 +485,8 @@ exports.stackTraceFilter = function () {
|
|
|
775
485
|
}
|
|
776
486
|
|
|
777
487
|
// Clean up cwd(absolute)
|
|
778
|
-
if (
|
|
779
|
-
line = line.replace(cwd, '');
|
|
488
|
+
if (/:\d+:\d+\)?$/.test(line)) {
|
|
489
|
+
line = line.replace('(' + cwd, '(');
|
|
780
490
|
}
|
|
781
491
|
|
|
782
492
|
list.push(line);
|
|
@@ -789,16 +499,193 @@ exports.stackTraceFilter = function () {
|
|
|
789
499
|
|
|
790
500
|
/**
|
|
791
501
|
* Crude, but effective.
|
|
792
|
-
* @
|
|
502
|
+
* @public
|
|
793
503
|
* @param {*} value
|
|
794
504
|
* @returns {boolean} Whether or not `value` is a Promise
|
|
795
505
|
*/
|
|
796
|
-
exports.isPromise = function isPromise
|
|
797
|
-
return
|
|
506
|
+
exports.isPromise = function isPromise(value) {
|
|
507
|
+
return (
|
|
508
|
+
typeof value === 'object' &&
|
|
509
|
+
value !== null &&
|
|
510
|
+
typeof value.then === 'function'
|
|
511
|
+
);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Clamps a numeric value to an inclusive range.
|
|
516
|
+
*
|
|
517
|
+
* @param {number} value - Value to be clamped.
|
|
518
|
+
* @param {number[]} range - Two element array specifying [min, max] range.
|
|
519
|
+
* @returns {number} clamped value
|
|
520
|
+
*/
|
|
521
|
+
exports.clamp = function clamp(value, range) {
|
|
522
|
+
return Math.min(Math.max(value, range[0]), range[1]);
|
|
798
523
|
};
|
|
799
524
|
|
|
800
525
|
/**
|
|
801
526
|
* It's a noop.
|
|
802
|
-
* @
|
|
527
|
+
* @public
|
|
803
528
|
*/
|
|
804
529
|
exports.noop = function () {};
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Creates a map-like object.
|
|
533
|
+
*
|
|
534
|
+
* @description
|
|
535
|
+
* A "map" is an object with no prototype, for our purposes. In some cases
|
|
536
|
+
* this would be more appropriate than a `Map`, especially if your environment
|
|
537
|
+
* doesn't support it. Recommended for use in Mocha's public APIs.
|
|
538
|
+
*
|
|
539
|
+
* @public
|
|
540
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Custom_and_Null_objects|MDN:Map}
|
|
541
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects}
|
|
542
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Custom_and_Null_objects|MDN:Object.assign}
|
|
543
|
+
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
|
544
|
+
* @returns {Object} An object with no prototype, having `...obj` properties
|
|
545
|
+
*/
|
|
546
|
+
exports.createMap = function (obj) {
|
|
547
|
+
return Object.assign.apply(
|
|
548
|
+
null,
|
|
549
|
+
[Object.create(null)].concat(Array.prototype.slice.call(arguments))
|
|
550
|
+
);
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Creates a read-only map-like object.
|
|
555
|
+
*
|
|
556
|
+
* @description
|
|
557
|
+
* This differs from {@link module:utils.createMap createMap} only in that
|
|
558
|
+
* the argument must be non-empty, because the result is frozen.
|
|
559
|
+
*
|
|
560
|
+
* @see {@link module:utils.createMap createMap}
|
|
561
|
+
* @param {...*} [obj] - Arguments to `Object.assign()`.
|
|
562
|
+
* @returns {Object} A frozen object with no prototype, having `...obj` properties
|
|
563
|
+
* @throws {TypeError} if argument is not a non-empty object.
|
|
564
|
+
*/
|
|
565
|
+
exports.defineConstants = function (obj) {
|
|
566
|
+
if (canonicalType(obj) !== 'object' || !Object.keys(obj).length) {
|
|
567
|
+
throw new TypeError('Invalid argument; expected a non-empty object');
|
|
568
|
+
}
|
|
569
|
+
return Object.freeze(exports.createMap(obj));
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Returns current working directory
|
|
574
|
+
*
|
|
575
|
+
* Wrapper around `process.cwd()` for isolation
|
|
576
|
+
* @private
|
|
577
|
+
*/
|
|
578
|
+
exports.cwd = function cwd() {
|
|
579
|
+
return process.cwd();
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Returns `true` if Mocha is running in a browser.
|
|
584
|
+
* Checks for `process.browser`.
|
|
585
|
+
* @returns {boolean}
|
|
586
|
+
* @private
|
|
587
|
+
*/
|
|
588
|
+
exports.isBrowser = function isBrowser() {
|
|
589
|
+
return Boolean(process.browser);
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
/*
|
|
593
|
+
* Casts `value` to an array; useful for optionally accepting array parameters
|
|
594
|
+
*
|
|
595
|
+
* It follows these rules, depending on `value`. If `value` is...
|
|
596
|
+
* 1. `undefined`: return an empty Array
|
|
597
|
+
* 2. `null`: return an array with a single `null` element
|
|
598
|
+
* 3. Any other object: return the value of `Array.from()` _if_ the object is iterable
|
|
599
|
+
* 4. otherwise: return an array with a single element, `value`
|
|
600
|
+
* @param {*} value - Something to cast to an Array
|
|
601
|
+
* @returns {Array<*>}
|
|
602
|
+
*/
|
|
603
|
+
exports.castArray = function castArray(value) {
|
|
604
|
+
if (value === undefined) {
|
|
605
|
+
return [];
|
|
606
|
+
}
|
|
607
|
+
if (value === null) {
|
|
608
|
+
return [null];
|
|
609
|
+
}
|
|
610
|
+
if (
|
|
611
|
+
typeof value === 'object' &&
|
|
612
|
+
(typeof value[Symbol.iterator] === 'function' || value.length !== undefined)
|
|
613
|
+
) {
|
|
614
|
+
return Array.from(value);
|
|
615
|
+
}
|
|
616
|
+
return [value];
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
exports.constants = exports.defineConstants({
|
|
620
|
+
MOCHA_ID_PROP_NAME
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
const uniqueIDBase =
|
|
624
|
+
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_';
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Creates a new unique identifier
|
|
628
|
+
* Does not create cryptographically safe ids.
|
|
629
|
+
* Trivial copy of nanoid/non-secure
|
|
630
|
+
* @returns {string} Unique identifier
|
|
631
|
+
*/
|
|
632
|
+
exports.uniqueID = () => {
|
|
633
|
+
let id = '';
|
|
634
|
+
for (let i = 0; i < 21; i++) {
|
|
635
|
+
id += uniqueIDBase[(Math.random() * 64) | 0];
|
|
636
|
+
}
|
|
637
|
+
return id;
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
exports.assignNewMochaID = obj => {
|
|
641
|
+
const id = exports.uniqueID();
|
|
642
|
+
Object.defineProperty(obj, MOCHA_ID_PROP_NAME, {
|
|
643
|
+
get() {
|
|
644
|
+
return id;
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
return obj;
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Retrieves a Mocha ID from an object, if present.
|
|
652
|
+
* @param {*} [obj] - Object
|
|
653
|
+
* @returns {string|void}
|
|
654
|
+
*/
|
|
655
|
+
exports.getMochaID = obj =>
|
|
656
|
+
obj && typeof obj === 'object' ? obj[MOCHA_ID_PROP_NAME] : undefined;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Replaces any detected circular dependency with the string '[Circular]'
|
|
660
|
+
* Mutates original object
|
|
661
|
+
* @param inputObj {*}
|
|
662
|
+
* @returns {*}
|
|
663
|
+
*/
|
|
664
|
+
exports.breakCircularDeps = inputObj => {
|
|
665
|
+
const seen = new Set();
|
|
666
|
+
|
|
667
|
+
function _breakCircularDeps(obj) {
|
|
668
|
+
if (obj && typeof obj !== 'object') {
|
|
669
|
+
return obj;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (seen.has(obj)) {
|
|
673
|
+
return '[Circular]';
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
seen.add(obj);
|
|
677
|
+
for (const k in obj) {
|
|
678
|
+
const descriptor = Object.getOwnPropertyDescriptor(obj, k);
|
|
679
|
+
|
|
680
|
+
if (descriptor && descriptor.writable) {
|
|
681
|
+
obj[k] = _breakCircularDeps(obj[k], k);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// deleting means only a seen object that is its own child will be detected
|
|
686
|
+
seen.delete(obj);
|
|
687
|
+
return obj;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
return _breakCircularDeps(inputObj);
|
|
691
|
+
};
|