mocha 9.1.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +1015 -0
  2. package/LICENSE +22 -0
  3. package/README.md +70 -0
  4. package/assets/growl/error.png +0 -0
  5. package/assets/growl/ok.png +0 -0
  6. package/bin/_mocha +10 -0
  7. package/bin/mocha +142 -0
  8. package/browser-entry.js +216 -0
  9. package/index.js +3 -0
  10. package/lib/browser/growl.js +169 -0
  11. package/lib/browser/highlight-tags.js +39 -0
  12. package/lib/browser/parse-query.js +24 -0
  13. package/lib/browser/progress.js +123 -0
  14. package/lib/browser/template.html +20 -0
  15. package/lib/cli/cli.js +89 -0
  16. package/lib/cli/collect-files.js +92 -0
  17. package/lib/cli/commands.js +13 -0
  18. package/lib/cli/config.js +105 -0
  19. package/lib/cli/index.js +3 -0
  20. package/lib/cli/init.js +36 -0
  21. package/lib/cli/lookup-files.js +145 -0
  22. package/lib/cli/node-flags.js +85 -0
  23. package/lib/cli/one-and-dones.js +69 -0
  24. package/lib/cli/options.js +261 -0
  25. package/lib/cli/run-helpers.js +243 -0
  26. package/lib/cli/run-option-metadata.js +117 -0
  27. package/lib/cli/run.js +379 -0
  28. package/lib/cli/watch-run.js +380 -0
  29. package/lib/context.js +86 -0
  30. package/lib/errors.js +563 -0
  31. package/lib/hook.js +89 -0
  32. package/lib/interfaces/bdd.js +111 -0
  33. package/lib/interfaces/common.js +193 -0
  34. package/lib/interfaces/exports.js +60 -0
  35. package/lib/interfaces/index.js +6 -0
  36. package/lib/interfaces/qunit.js +98 -0
  37. package/lib/interfaces/tdd.js +106 -0
  38. package/lib/mocha.js +1374 -0
  39. package/lib/mocharc.json +10 -0
  40. package/lib/nodejs/buffered-worker-pool.js +172 -0
  41. package/lib/nodejs/esm-utils.js +109 -0
  42. package/lib/nodejs/file-unloader.js +15 -0
  43. package/lib/nodejs/growl.js +137 -0
  44. package/lib/nodejs/parallel-buffered-runner.js +433 -0
  45. package/lib/nodejs/reporters/parallel-buffered.js +165 -0
  46. package/lib/nodejs/serializer.js +412 -0
  47. package/lib/nodejs/worker.js +151 -0
  48. package/lib/pending.js +16 -0
  49. package/lib/plugin-loader.js +286 -0
  50. package/lib/reporters/base.js +537 -0
  51. package/lib/reporters/doc.js +95 -0
  52. package/lib/reporters/dot.js +81 -0
  53. package/lib/reporters/html.js +390 -0
  54. package/lib/reporters/index.js +19 -0
  55. package/lib/reporters/json-stream.js +92 -0
  56. package/lib/reporters/json.js +162 -0
  57. package/lib/reporters/landing.js +116 -0
  58. package/lib/reporters/list.js +78 -0
  59. package/lib/reporters/markdown.js +112 -0
  60. package/lib/reporters/min.js +52 -0
  61. package/lib/reporters/nyan.js +276 -0
  62. package/lib/reporters/progress.js +104 -0
  63. package/lib/reporters/spec.js +99 -0
  64. package/lib/reporters/tap.js +293 -0
  65. package/lib/reporters/xunit.js +217 -0
  66. package/lib/runnable.js +476 -0
  67. package/lib/runner.js +1269 -0
  68. package/lib/stats-collector.js +83 -0
  69. package/lib/suite.js +695 -0
  70. package/lib/test.js +113 -0
  71. package/lib/utils.js +641 -0
  72. package/mocha-es2018.js +19816 -0
  73. package/mocha.css +325 -0
  74. package/mocha.js +30844 -0
  75. package/mocha.js.map +1 -0
  76. package/package.json +200 -0
package/lib/utils.js ADDED
@@ -0,0 +1,641 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Various utility functions used throughout Mocha's codebase.
5
+ * @module utils
6
+ */
7
+
8
+ /**
9
+ * Module dependencies.
10
+ */
11
+
12
+ const {nanoid} = require('nanoid/non-secure');
13
+ var path = require('path');
14
+ var util = require('util');
15
+ var he = require('he');
16
+
17
+ const MOCHA_ID_PROP_NAME = '__mocha_id__';
18
+
19
+ /**
20
+ * Inherit the prototype methods from one constructor into another.
21
+ *
22
+ * @param {function} ctor - Constructor function which needs to inherit the
23
+ * prototype.
24
+ * @param {function} superCtor - Constructor function to inherit prototype from.
25
+ * @throws {TypeError} if either constructor is null, or if super constructor
26
+ * lacks a prototype.
27
+ */
28
+ exports.inherits = util.inherits;
29
+
30
+ /**
31
+ * Escape special characters in the given string of html.
32
+ *
33
+ * @private
34
+ * @param {string} html
35
+ * @return {string}
36
+ */
37
+ exports.escape = function(html) {
38
+ return he.encode(String(html), {useNamedReferences: false});
39
+ };
40
+
41
+ /**
42
+ * Test if the given obj is type of string.
43
+ *
44
+ * @private
45
+ * @param {Object} obj
46
+ * @return {boolean}
47
+ */
48
+ exports.isString = function(obj) {
49
+ return typeof obj === 'string';
50
+ };
51
+
52
+ /**
53
+ * Compute a slug from the given `str`.
54
+ *
55
+ * @private
56
+ * @param {string} str
57
+ * @return {string}
58
+ */
59
+ exports.slug = function(str) {
60
+ return str
61
+ .toLowerCase()
62
+ .replace(/\s+/g, '-')
63
+ .replace(/[^-\w]/g, '')
64
+ .replace(/-{2,}/g, '-');
65
+ };
66
+
67
+ /**
68
+ * Strip the function definition from `str`, and re-indent for pre whitespace.
69
+ *
70
+ * @param {string} str
71
+ * @return {string}
72
+ */
73
+ exports.clean = function(str) {
74
+ str = str
75
+ .replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
76
+ .replace(/^\uFEFF/, '')
77
+ // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
78
+ .replace(
79
+ /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/,
80
+ '$1$2$3'
81
+ );
82
+
83
+ var spaces = str.match(/^\n?( *)/)[1].length;
84
+ var tabs = str.match(/^\n?(\t*)/)[1].length;
85
+ var re = new RegExp(
86
+ '^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
87
+ 'gm'
88
+ );
89
+
90
+ str = str.replace(re, '');
91
+
92
+ return str.trim();
93
+ };
94
+
95
+ /**
96
+ * If a value could have properties, and has none, this function is called,
97
+ * which returns a string representation of the empty value.
98
+ *
99
+ * Functions w/ no properties return `'[Function]'`
100
+ * Arrays w/ length === 0 return `'[]'`
101
+ * Objects w/ no properties return `'{}'`
102
+ * All else: return result of `value.toString()`
103
+ *
104
+ * @private
105
+ * @param {*} value The value to inspect.
106
+ * @param {string} typeHint The type of the value
107
+ * @returns {string}
108
+ */
109
+ function emptyRepresentation(value, typeHint) {
110
+ switch (typeHint) {
111
+ case 'function':
112
+ return '[Function]';
113
+ case 'object':
114
+ return '{}';
115
+ case 'array':
116
+ return '[]';
117
+ default:
118
+ return value.toString();
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Takes some variable and asks `Object.prototype.toString()` what it thinks it
124
+ * is.
125
+ *
126
+ * @private
127
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
128
+ * @param {*} value The value to test.
129
+ * @returns {string} Computed type
130
+ * @example
131
+ * canonicalType({}) // 'object'
132
+ * canonicalType([]) // 'array'
133
+ * canonicalType(1) // 'number'
134
+ * canonicalType(false) // 'boolean'
135
+ * canonicalType(Infinity) // 'number'
136
+ * canonicalType(null) // 'null'
137
+ * canonicalType(new Date()) // 'date'
138
+ * canonicalType(/foo/) // 'regexp'
139
+ * canonicalType('type') // 'string'
140
+ * canonicalType(global) // 'global'
141
+ * canonicalType(new String('foo') // 'object'
142
+ * canonicalType(async function() {}) // 'asyncfunction'
143
+ * canonicalType(await import(name)) // 'module'
144
+ */
145
+ var canonicalType = (exports.canonicalType = function canonicalType(value) {
146
+ if (value === undefined) {
147
+ return 'undefined';
148
+ } else if (value === null) {
149
+ return 'null';
150
+ } else if (Buffer.isBuffer(value)) {
151
+ return 'buffer';
152
+ }
153
+ return Object.prototype.toString
154
+ .call(value)
155
+ .replace(/^\[.+\s(.+?)]$/, '$1')
156
+ .toLowerCase();
157
+ });
158
+
159
+ /**
160
+ *
161
+ * Returns a general type or data structure of a variable
162
+ * @private
163
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
164
+ * @param {*} value The value to test.
165
+ * @returns {string} One of undefined, boolean, number, string, bigint, symbol, object
166
+ * @example
167
+ * type({}) // 'object'
168
+ * type([]) // 'array'
169
+ * type(1) // 'number'
170
+ * type(false) // 'boolean'
171
+ * type(Infinity) // 'number'
172
+ * type(null) // 'null'
173
+ * type(new Date()) // 'object'
174
+ * type(/foo/) // 'object'
175
+ * type('type') // 'string'
176
+ * type(global) // 'object'
177
+ * type(new String('foo') // 'string'
178
+ */
179
+ exports.type = function type(value) {
180
+ // Null is special
181
+ if (value === null) return 'null';
182
+ const primitives = new Set([
183
+ 'undefined',
184
+ 'boolean',
185
+ 'number',
186
+ 'string',
187
+ 'bigint',
188
+ 'symbol'
189
+ ]);
190
+ const _type = typeof value;
191
+ if (_type === 'function') return _type;
192
+ if (primitives.has(_type)) return _type;
193
+ if (value instanceof String) return 'string';
194
+ if (value instanceof Error) return 'error';
195
+ if (Array.isArray(value)) return 'array';
196
+
197
+ return _type;
198
+ };
199
+
200
+ /**
201
+ * Stringify `value`. Different behavior depending on type of value:
202
+ *
203
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
204
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
205
+ * - If `value` is an *empty* object, function, or array, return result of function
206
+ * {@link emptyRepresentation}.
207
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
208
+ * JSON.stringify().
209
+ *
210
+ * @private
211
+ * @see exports.type
212
+ * @param {*} value
213
+ * @return {string}
214
+ */
215
+ exports.stringify = function(value) {
216
+ var typeHint = canonicalType(value);
217
+
218
+ if (!~['object', 'array', 'function'].indexOf(typeHint)) {
219
+ if (typeHint === 'buffer') {
220
+ var json = Buffer.prototype.toJSON.call(value);
221
+ // Based on the toJSON result
222
+ return jsonStringify(
223
+ json.data && json.type ? json.data : json,
224
+ 2
225
+ ).replace(/,(\n|$)/g, '$1');
226
+ }
227
+
228
+ // IE7/IE8 has a bizarre String constructor; needs to be coerced
229
+ // into an array and back to obj.
230
+ if (typeHint === 'string' && typeof value === 'object') {
231
+ value = value.split('').reduce(function(acc, char, idx) {
232
+ acc[idx] = char;
233
+ return acc;
234
+ }, {});
235
+ typeHint = 'object';
236
+ } else {
237
+ return jsonStringify(value);
238
+ }
239
+ }
240
+
241
+ for (var prop in value) {
242
+ if (Object.prototype.hasOwnProperty.call(value, prop)) {
243
+ return jsonStringify(
244
+ exports.canonicalize(value, null, typeHint),
245
+ 2
246
+ ).replace(/,(\n|$)/g, '$1');
247
+ }
248
+ }
249
+
250
+ return emptyRepresentation(value, typeHint);
251
+ };
252
+
253
+ /**
254
+ * like JSON.stringify but more sense.
255
+ *
256
+ * @private
257
+ * @param {Object} object
258
+ * @param {number=} spaces
259
+ * @param {number=} depth
260
+ * @returns {*}
261
+ */
262
+ function jsonStringify(object, spaces, depth) {
263
+ if (typeof spaces === 'undefined') {
264
+ // primitive types
265
+ return _stringify(object);
266
+ }
267
+
268
+ depth = depth || 1;
269
+ var space = spaces * depth;
270
+ var str = Array.isArray(object) ? '[' : '{';
271
+ var end = Array.isArray(object) ? ']' : '}';
272
+ var length =
273
+ typeof object.length === 'number'
274
+ ? object.length
275
+ : Object.keys(object).length;
276
+ // `.repeat()` polyfill
277
+ function repeat(s, n) {
278
+ return new Array(n).join(s);
279
+ }
280
+
281
+ function _stringify(val) {
282
+ switch (canonicalType(val)) {
283
+ case 'null':
284
+ case 'undefined':
285
+ val = '[' + val + ']';
286
+ break;
287
+ case 'array':
288
+ case 'object':
289
+ val = jsonStringify(val, spaces, depth + 1);
290
+ break;
291
+ case 'boolean':
292
+ case 'regexp':
293
+ case 'symbol':
294
+ case 'number':
295
+ val =
296
+ val === 0 && 1 / val === -Infinity // `-0`
297
+ ? '-0'
298
+ : val.toString();
299
+ break;
300
+ case 'bigint':
301
+ val = val.toString() + 'n';
302
+ break;
303
+ case 'date':
304
+ var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
305
+ val = '[Date: ' + sDate + ']';
306
+ break;
307
+ case 'buffer':
308
+ var json = val.toJSON();
309
+ // Based on the toJSON result
310
+ json = json.data && json.type ? json.data : json;
311
+ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
312
+ break;
313
+ default:
314
+ val =
315
+ val === '[Function]' || val === '[Circular]'
316
+ ? val
317
+ : JSON.stringify(val); // string
318
+ }
319
+ return val;
320
+ }
321
+
322
+ for (var i in object) {
323
+ if (!Object.prototype.hasOwnProperty.call(object, i)) {
324
+ continue; // not my business
325
+ }
326
+ --length;
327
+ str +=
328
+ '\n ' +
329
+ repeat(' ', space) +
330
+ (Array.isArray(object) ? '' : '"' + i + '": ') + // key
331
+ _stringify(object[i]) + // value
332
+ (length ? ',' : ''); // comma
333
+ }
334
+
335
+ return (
336
+ str +
337
+ // [], {}
338
+ (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
339
+ );
340
+ }
341
+
342
+ /**
343
+ * Return a new Thing that has the keys in sorted order. Recursive.
344
+ *
345
+ * If the Thing...
346
+ * - has already been seen, return string `'[Circular]'`
347
+ * - is `undefined`, return string `'[undefined]'`
348
+ * - is `null`, return value `null`
349
+ * - is some other primitive, return the value
350
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
351
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
352
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
353
+ *
354
+ * @private
355
+ * @see {@link exports.stringify}
356
+ * @param {*} value Thing to inspect. May or may not have properties.
357
+ * @param {Array} [stack=[]] Stack of seen values
358
+ * @param {string} [typeHint] Type hint
359
+ * @return {(Object|Array|Function|string|undefined)}
360
+ */
361
+ exports.canonicalize = function canonicalize(value, stack, typeHint) {
362
+ var canonicalizedObj;
363
+ /* eslint-disable no-unused-vars */
364
+ var prop;
365
+ /* eslint-enable no-unused-vars */
366
+ typeHint = typeHint || canonicalType(value);
367
+ function withStack(value, fn) {
368
+ stack.push(value);
369
+ fn();
370
+ stack.pop();
371
+ }
372
+
373
+ stack = stack || [];
374
+
375
+ if (stack.indexOf(value) !== -1) {
376
+ return '[Circular]';
377
+ }
378
+
379
+ switch (typeHint) {
380
+ case 'undefined':
381
+ case 'buffer':
382
+ case 'null':
383
+ canonicalizedObj = value;
384
+ break;
385
+ case 'array':
386
+ withStack(value, function() {
387
+ canonicalizedObj = value.map(function(item) {
388
+ return exports.canonicalize(item, stack);
389
+ });
390
+ });
391
+ break;
392
+ case 'function':
393
+ /* eslint-disable-next-line no-unused-vars, no-unreachable-loop */
394
+ for (prop in value) {
395
+ canonicalizedObj = {};
396
+ break;
397
+ }
398
+ /* eslint-enable guard-for-in */
399
+ if (!canonicalizedObj) {
400
+ canonicalizedObj = emptyRepresentation(value, typeHint);
401
+ break;
402
+ }
403
+ /* falls through */
404
+ case 'object':
405
+ canonicalizedObj = canonicalizedObj || {};
406
+ withStack(value, function() {
407
+ Object.keys(value)
408
+ .sort()
409
+ .forEach(function(key) {
410
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
411
+ });
412
+ });
413
+ break;
414
+ case 'date':
415
+ case 'number':
416
+ case 'regexp':
417
+ case 'boolean':
418
+ case 'symbol':
419
+ canonicalizedObj = value;
420
+ break;
421
+ default:
422
+ canonicalizedObj = value + '';
423
+ }
424
+
425
+ return canonicalizedObj;
426
+ };
427
+
428
+ /**
429
+ * @summary
430
+ * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
431
+ * @description
432
+ * When invoking this function you get a filter function that get the Error.stack as an input,
433
+ * and return a prettify output.
434
+ * (i.e: strip Mocha and internal node functions from stack trace).
435
+ * @returns {Function}
436
+ */
437
+ exports.stackTraceFilter = function() {
438
+ // TODO: Replace with `process.browser`
439
+ var is = typeof document === 'undefined' ? {node: true} : {browser: true};
440
+ var slash = path.sep;
441
+ var cwd;
442
+ if (is.node) {
443
+ cwd = exports.cwd() + slash;
444
+ } else {
445
+ cwd = (typeof location === 'undefined'
446
+ ? window.location
447
+ : location
448
+ ).href.replace(/\/[^/]*$/, '/');
449
+ slash = '/';
450
+ }
451
+
452
+ function isMochaInternal(line) {
453
+ return (
454
+ ~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
455
+ ~line.indexOf(slash + 'mocha.js') ||
456
+ ~line.indexOf(slash + 'mocha.min.js')
457
+ );
458
+ }
459
+
460
+ function isNodeInternal(line) {
461
+ return (
462
+ ~line.indexOf('(timers.js:') ||
463
+ ~line.indexOf('(events.js:') ||
464
+ ~line.indexOf('(node.js:') ||
465
+ ~line.indexOf('(module.js:') ||
466
+ ~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
467
+ false
468
+ );
469
+ }
470
+
471
+ return function(stack) {
472
+ stack = stack.split('\n');
473
+
474
+ stack = stack.reduce(function(list, line) {
475
+ if (isMochaInternal(line)) {
476
+ return list;
477
+ }
478
+
479
+ if (is.node && isNodeInternal(line)) {
480
+ return list;
481
+ }
482
+
483
+ // Clean up cwd(absolute)
484
+ if (/:\d+:\d+\)?$/.test(line)) {
485
+ line = line.replace('(' + cwd, '(');
486
+ }
487
+
488
+ list.push(line);
489
+ return list;
490
+ }, []);
491
+
492
+ return stack.join('\n');
493
+ };
494
+ };
495
+
496
+ /**
497
+ * Crude, but effective.
498
+ * @public
499
+ * @param {*} value
500
+ * @returns {boolean} Whether or not `value` is a Promise
501
+ */
502
+ exports.isPromise = function isPromise(value) {
503
+ return (
504
+ typeof value === 'object' &&
505
+ value !== null &&
506
+ typeof value.then === 'function'
507
+ );
508
+ };
509
+
510
+ /**
511
+ * Clamps a numeric value to an inclusive range.
512
+ *
513
+ * @param {number} value - Value to be clamped.
514
+ * @param {number[]} range - Two element array specifying [min, max] range.
515
+ * @returns {number} clamped value
516
+ */
517
+ exports.clamp = function clamp(value, range) {
518
+ return Math.min(Math.max(value, range[0]), range[1]);
519
+ };
520
+
521
+ /**
522
+ * It's a noop.
523
+ * @public
524
+ */
525
+ exports.noop = function() {};
526
+
527
+ /**
528
+ * Creates a map-like object.
529
+ *
530
+ * @description
531
+ * A "map" is an object with no prototype, for our purposes. In some cases
532
+ * this would be more appropriate than a `Map`, especially if your environment
533
+ * doesn't support it. Recommended for use in Mocha's public APIs.
534
+ *
535
+ * @public
536
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Custom_and_Null_objects|MDN:Map}
537
+ * @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}
538
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Custom_and_Null_objects|MDN:Object.assign}
539
+ * @param {...*} [obj] - Arguments to `Object.assign()`.
540
+ * @returns {Object} An object with no prototype, having `...obj` properties
541
+ */
542
+ exports.createMap = function(obj) {
543
+ return Object.assign.apply(
544
+ null,
545
+ [Object.create(null)].concat(Array.prototype.slice.call(arguments))
546
+ );
547
+ };
548
+
549
+ /**
550
+ * Creates a read-only map-like object.
551
+ *
552
+ * @description
553
+ * This differs from {@link module:utils.createMap createMap} only in that
554
+ * the argument must be non-empty, because the result is frozen.
555
+ *
556
+ * @see {@link module:utils.createMap createMap}
557
+ * @param {...*} [obj] - Arguments to `Object.assign()`.
558
+ * @returns {Object} A frozen object with no prototype, having `...obj` properties
559
+ * @throws {TypeError} if argument is not a non-empty object.
560
+ */
561
+ exports.defineConstants = function(obj) {
562
+ if (canonicalType(obj) !== 'object' || !Object.keys(obj).length) {
563
+ throw new TypeError('Invalid argument; expected a non-empty object');
564
+ }
565
+ return Object.freeze(exports.createMap(obj));
566
+ };
567
+
568
+ /**
569
+ * Returns current working directory
570
+ *
571
+ * Wrapper around `process.cwd()` for isolation
572
+ * @private
573
+ */
574
+ exports.cwd = function cwd() {
575
+ return process.cwd();
576
+ };
577
+
578
+ /**
579
+ * Returns `true` if Mocha is running in a browser.
580
+ * Checks for `process.browser`.
581
+ * @returns {boolean}
582
+ * @private
583
+ */
584
+ exports.isBrowser = function isBrowser() {
585
+ return Boolean(process.browser);
586
+ };
587
+
588
+ /*
589
+ * Casts `value` to an array; useful for optionally accepting array parameters
590
+ *
591
+ * It follows these rules, depending on `value`. If `value` is...
592
+ * 1. `undefined`: return an empty Array
593
+ * 2. `null`: return an array with a single `null` element
594
+ * 3. Any other object: return the value of `Array.from()` _if_ the object is iterable
595
+ * 4. otherwise: return an array with a single element, `value`
596
+ * @param {*} value - Something to cast to an Array
597
+ * @returns {Array<*>}
598
+ */
599
+ exports.castArray = function castArray(value) {
600
+ if (value === undefined) {
601
+ return [];
602
+ }
603
+ if (value === null) {
604
+ return [null];
605
+ }
606
+ if (
607
+ typeof value === 'object' &&
608
+ (typeof value[Symbol.iterator] === 'function' || value.length !== undefined)
609
+ ) {
610
+ return Array.from(value);
611
+ }
612
+ return [value];
613
+ };
614
+
615
+ exports.constants = exports.defineConstants({
616
+ MOCHA_ID_PROP_NAME
617
+ });
618
+
619
+ /**
620
+ * Creates a new unique identifier
621
+ * @returns {string} Unique identifier
622
+ */
623
+ exports.uniqueID = () => nanoid();
624
+
625
+ exports.assignNewMochaID = obj => {
626
+ const id = exports.uniqueID();
627
+ Object.defineProperty(obj, MOCHA_ID_PROP_NAME, {
628
+ get() {
629
+ return id;
630
+ }
631
+ });
632
+ return obj;
633
+ };
634
+
635
+ /**
636
+ * Retrieves a Mocha ID from an object, if present.
637
+ * @param {*} [obj] - Object
638
+ * @returns {string|void}
639
+ */
640
+ exports.getMochaID = obj =>
641
+ obj && typeof obj === 'object' ? obj[MOCHA_ID_PROP_NAME] : undefined;