mocha 5.1.0 → 6.0.0-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.
Files changed (63) hide show
  1. package/CHANGELOG.md +653 -981
  2. package/README.md +2 -1
  3. package/{images → assets/growl}/error.png +0 -0
  4. package/{images → assets/growl}/ok.png +0 -0
  5. package/bin/_mocha +4 -595
  6. package/bin/mocha +84 -58
  7. package/bin/options.js +6 -39
  8. package/browser-entry.js +21 -17
  9. package/lib/browser/growl.js +164 -2
  10. package/lib/browser/progress.js +11 -11
  11. package/lib/{template.html → browser/template.html} +0 -0
  12. package/lib/browser/tty.js +2 -2
  13. package/lib/cli/cli.js +68 -0
  14. package/lib/cli/commands.js +13 -0
  15. package/lib/cli/config.js +79 -0
  16. package/lib/cli/index.js +9 -0
  17. package/lib/cli/init.js +37 -0
  18. package/lib/cli/node-flags.js +48 -0
  19. package/lib/cli/one-and-dones.js +70 -0
  20. package/lib/cli/options.js +299 -0
  21. package/lib/cli/run-helpers.js +328 -0
  22. package/lib/cli/run-option-metadata.js +72 -0
  23. package/lib/cli/run.js +293 -0
  24. package/lib/context.js +14 -14
  25. package/lib/errors.js +139 -0
  26. package/lib/growl.js +135 -0
  27. package/lib/hook.js +5 -16
  28. package/lib/interfaces/bdd.js +14 -13
  29. package/lib/interfaces/common.js +59 -16
  30. package/lib/interfaces/exports.js +4 -7
  31. package/lib/interfaces/qunit.js +8 -10
  32. package/lib/interfaces/tdd.js +10 -11
  33. package/lib/mocha.js +442 -255
  34. package/lib/mocharc.json +10 -0
  35. package/lib/pending.js +1 -5
  36. package/lib/reporters/base.js +92 -117
  37. package/lib/reporters/doc.js +18 -9
  38. package/lib/reporters/dot.js +13 -13
  39. package/lib/reporters/html.js +76 -47
  40. package/lib/reporters/json-stream.js +38 -23
  41. package/lib/reporters/json.js +26 -23
  42. package/lib/reporters/landing.js +9 -8
  43. package/lib/reporters/list.js +11 -10
  44. package/lib/reporters/markdown.js +13 -12
  45. package/lib/reporters/min.js +4 -3
  46. package/lib/reporters/nyan.js +36 -35
  47. package/lib/reporters/progress.js +8 -7
  48. package/lib/reporters/spec.js +14 -11
  49. package/lib/reporters/tap.js +243 -32
  50. package/lib/reporters/xunit.js +52 -33
  51. package/lib/runnable.js +103 -90
  52. package/lib/runner.js +156 -107
  53. package/lib/stats-collector.js +81 -0
  54. package/lib/suite.js +57 -51
  55. package/lib/test.js +13 -13
  56. package/lib/utils.js +192 -103
  57. package/mocha.js +3836 -2046
  58. package/package.json +122 -38
  59. package/bin/.eslintrc.yml +0 -3
  60. package/lib/browser/.eslintrc.yml +0 -4
  61. package/lib/ms.js +0 -94
  62. package/lib/reporters/base.js.orig +0 -498
  63. package/lib/reporters/json.js.orig +0 -128
package/lib/utils.js CHANGED
@@ -14,6 +14,10 @@ var glob = require('glob');
14
14
  var path = require('path');
15
15
  var join = path.join;
16
16
  var he = require('he');
17
+ var errors = require('./errors');
18
+ var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError;
19
+ var createMissingArgumentError = errors.createMissingArgumentError;
20
+ var createUndefinedError = errors.createUndefinedError;
17
21
 
18
22
  /**
19
23
  * Ignored directories.
@@ -26,22 +30,22 @@ exports.inherits = require('util').inherits;
26
30
  /**
27
31
  * Escape special characters in the given string of html.
28
32
  *
29
- * @api private
33
+ * @private
30
34
  * @param {string} html
31
35
  * @return {string}
32
36
  */
33
- exports.escape = function (html) {
34
- return he.encode(String(html), { useNamedReferences: false });
37
+ exports.escape = function(html) {
38
+ return he.encode(String(html), {useNamedReferences: false});
35
39
  };
36
40
 
37
41
  /**
38
42
  * Test if the given obj is type of string.
39
43
  *
40
- * @api private
44
+ * @private
41
45
  * @param {Object} obj
42
46
  * @return {boolean}
43
47
  */
44
- exports.isString = function (obj) {
48
+ exports.isString = function(obj) {
45
49
  return typeof obj === 'string';
46
50
  };
47
51
 
@@ -49,15 +53,15 @@ exports.isString = function (obj) {
49
53
  * Watch the given `files` for changes
50
54
  * and invoke `fn(file)` on modification.
51
55
  *
52
- * @api private
56
+ * @private
53
57
  * @param {Array} files
54
58
  * @param {Function} fn
55
59
  */
56
- exports.watch = function (files, fn) {
57
- var options = { interval: 100 };
58
- files.forEach(function (file) {
60
+ exports.watch = function(files, fn) {
61
+ var options = {interval: 100};
62
+ files.forEach(function(file) {
59
63
  debug('file %s', file);
60
- fs.watchFile(file, options, function (curr, prev) {
64
+ fs.watchFile(file, options, function(curr, prev) {
61
65
  if (prev.mtime < curr.mtime) {
62
66
  fn(file);
63
67
  }
@@ -68,24 +72,24 @@ exports.watch = function (files, fn) {
68
72
  /**
69
73
  * Ignored files.
70
74
  *
71
- * @api private
75
+ * @private
72
76
  * @param {string} path
73
77
  * @return {boolean}
74
78
  */
75
- function ignored (path) {
79
+ function ignored(path) {
76
80
  return !~ignore.indexOf(path);
77
81
  }
78
82
 
79
83
  /**
80
84
  * Lookup files in the given `dir`.
81
85
  *
82
- * @api private
86
+ * @private
83
87
  * @param {string} dir
84
88
  * @param {string[]} [ext=['.js']]
85
89
  * @param {Array} [ret=[]]
86
90
  * @return {Array}
87
91
  */
88
- exports.files = function (dir, ext, ret) {
92
+ exports.files = function(dir, ext, ret) {
89
93
  ret = ret || [];
90
94
  ext = ext || ['js'];
91
95
 
@@ -93,7 +97,7 @@ exports.files = function (dir, ext, ret) {
93
97
 
94
98
  fs.readdirSync(dir)
95
99
  .filter(ignored)
96
- .forEach(function (path) {
100
+ .forEach(function(path) {
97
101
  path = join(dir, path);
98
102
  if (fs.lstatSync(path).isDirectory()) {
99
103
  exports.files(path, ext, ret);
@@ -108,11 +112,11 @@ exports.files = function (dir, ext, ret) {
108
112
  /**
109
113
  * Compute a slug from the given `str`.
110
114
  *
111
- * @api private
115
+ * @private
112
116
  * @param {string} str
113
117
  * @return {string}
114
118
  */
115
- exports.slug = function (str) {
119
+ exports.slug = function(str) {
116
120
  return str
117
121
  .toLowerCase()
118
122
  .replace(/ +/g, '-')
@@ -125,15 +129,22 @@ exports.slug = function (str) {
125
129
  * @param {string} str
126
130
  * @return {string}
127
131
  */
128
- exports.clean = function (str) {
132
+ exports.clean = function(str) {
129
133
  str = str
130
- .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '')
134
+ .replace(/\r\n?|[\n\u2028\u2029]/g, '\n')
135
+ .replace(/^\uFEFF/, '')
131
136
  // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content
132
- .replace(/^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, '$1$2$3');
137
+ .replace(
138
+ /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/,
139
+ '$1$2$3'
140
+ );
133
141
 
134
142
  var spaces = str.match(/^\n?( *)/)[1].length;
135
143
  var tabs = str.match(/^\n?(\t*)/)[1].length;
136
- var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', 'gm');
144
+ var re = new RegExp(
145
+ '^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}',
146
+ 'gm'
147
+ );
137
148
 
138
149
  str = str.replace(re, '');
139
150
 
@@ -143,31 +154,34 @@ exports.clean = function (str) {
143
154
  /**
144
155
  * Parse the given `qs`.
145
156
  *
146
- * @api private
157
+ * @private
147
158
  * @param {string} qs
148
159
  * @return {Object}
149
160
  */
150
- exports.parseQuery = function (qs) {
151
- return qs.replace('?', '').split('&').reduce(function (obj, pair) {
152
- var i = pair.indexOf('=');
153
- var key = pair.slice(0, i);
154
- var val = pair.slice(++i);
155
-
156
- // Due to how the URLSearchParams API treats spaces
157
- obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
158
-
159
- return obj;
160
- }, {});
161
+ exports.parseQuery = function(qs) {
162
+ return qs
163
+ .replace('?', '')
164
+ .split('&')
165
+ .reduce(function(obj, pair) {
166
+ var i = pair.indexOf('=');
167
+ var key = pair.slice(0, i);
168
+ var val = pair.slice(++i);
169
+
170
+ // Due to how the URLSearchParams API treats spaces
171
+ obj[key] = decodeURIComponent(val.replace(/\+/g, '%20'));
172
+
173
+ return obj;
174
+ }, {});
161
175
  };
162
176
 
163
177
  /**
164
178
  * Highlight the given string of `js`.
165
179
  *
166
- * @api private
180
+ * @private
167
181
  * @param {string} js
168
182
  * @return {string}
169
183
  */
170
- function highlight (js) {
184
+ function highlight(js) {
171
185
  return js
172
186
  .replace(/</g, '&lt;')
173
187
  .replace(/>/g, '&gt;')
@@ -175,17 +189,23 @@ function highlight (js) {
175
189
  .replace(/('.*?')/gm, '<span class="string">$1</span>')
176
190
  .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
177
191
  .replace(/(\d+)/gm, '<span class="number">$1</span>')
178
- .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
179
- .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>');
192
+ .replace(
193
+ /\bnew[ \t]+(\w+)/gm,
194
+ '<span class="keyword">new</span> <span class="init">$1</span>'
195
+ )
196
+ .replace(
197
+ /\b(function|new|throw|return|var|if|else)\b/gm,
198
+ '<span class="keyword">$1</span>'
199
+ );
180
200
  }
181
201
 
182
202
  /**
183
203
  * Highlight the contents of tag `name`.
184
204
  *
185
- * @api private
205
+ * @private
186
206
  * @param {string} name
187
207
  */
188
- exports.highlightTags = function (name) {
208
+ exports.highlightTags = function(name) {
189
209
  var code = document.getElementById('mocha').getElementsByTagName(name);
190
210
  for (var i = 0, len = code.length; i < len; ++i) {
191
211
  code[i].innerHTML = highlight(code[i].innerHTML);
@@ -201,12 +221,12 @@ exports.highlightTags = function (name) {
201
221
  * Objects w/ no properties return `'{}'`
202
222
  * All else: return result of `value.toString()`
203
223
  *
204
- * @api private
224
+ * @private
205
225
  * @param {*} value The value to inspect.
206
226
  * @param {string} typeHint The type of the value
207
227
  * @returns {string}
208
228
  */
209
- function emptyRepresentation (value, typeHint) {
229
+ function emptyRepresentation(value, typeHint) {
210
230
  switch (typeHint) {
211
231
  case 'function':
212
232
  return '[Function]';
@@ -223,7 +243,7 @@ function emptyRepresentation (value, typeHint) {
223
243
  * Takes some variable and asks `Object.prototype.toString()` what it thinks it
224
244
  * is.
225
245
  *
226
- * @api private
246
+ * @private
227
247
  * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
228
248
  * @param {*} value The value to test.
229
249
  * @returns {string} Computed type
@@ -240,7 +260,7 @@ function emptyRepresentation (value, typeHint) {
240
260
  * type(global) // 'global'
241
261
  * type(new String('foo') // 'object'
242
262
  */
243
- var type = exports.type = function type (value) {
263
+ var type = (exports.type = function type(value) {
244
264
  if (value === undefined) {
245
265
  return 'undefined';
246
266
  } else if (value === null) {
@@ -248,10 +268,11 @@ var type = exports.type = function type (value) {
248
268
  } else if (Buffer.isBuffer(value)) {
249
269
  return 'buffer';
250
270
  }
251
- return Object.prototype.toString.call(value)
271
+ return Object.prototype.toString
272
+ .call(value)
252
273
  .replace(/^\[.+\s(.+?)]$/, '$1')
253
274
  .toLowerCase();
254
- };
275
+ });
255
276
 
256
277
  /**
257
278
  * Stringify `value`. Different behavior depending on type of value:
@@ -263,26 +284,28 @@ var type = exports.type = function type (value) {
263
284
  * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
264
285
  * JSON.stringify().
265
286
  *
266
- * @api private
287
+ * @private
267
288
  * @see exports.type
268
289
  * @param {*} value
269
290
  * @return {string}
270
291
  */
271
- exports.stringify = function (value) {
292
+ exports.stringify = function(value) {
272
293
  var typeHint = type(value);
273
294
 
274
295
  if (!~['object', 'array', 'function'].indexOf(typeHint)) {
275
296
  if (typeHint === 'buffer') {
276
297
  var json = Buffer.prototype.toJSON.call(value);
277
298
  // Based on the toJSON result
278
- return jsonStringify(json.data && json.type ? json.data : json, 2)
279
- .replace(/,(\n|$)/g, '$1');
299
+ return jsonStringify(
300
+ json.data && json.type ? json.data : json,
301
+ 2
302
+ ).replace(/,(\n|$)/g, '$1');
280
303
  }
281
304
 
282
305
  // IE7/IE8 has a bizarre String constructor; needs to be coerced
283
306
  // into an array and back to obj.
284
307
  if (typeHint === 'string' && typeof value === 'object') {
285
- value = value.split('').reduce(function (acc, char, idx) {
308
+ value = value.split('').reduce(function(acc, char, idx) {
286
309
  acc[idx] = char;
287
310
  return acc;
288
311
  }, {});
@@ -294,7 +317,10 @@ exports.stringify = function (value) {
294
317
 
295
318
  for (var prop in value) {
296
319
  if (Object.prototype.hasOwnProperty.call(value, prop)) {
297
- return jsonStringify(exports.canonicalize(value, null, typeHint), 2).replace(/,(\n|$)/g, '$1');
320
+ return jsonStringify(
321
+ exports.canonicalize(value, null, typeHint),
322
+ 2
323
+ ).replace(/,(\n|$)/g, '$1');
298
324
  }
299
325
  }
300
326
 
@@ -304,13 +330,13 @@ exports.stringify = function (value) {
304
330
  /**
305
331
  * like JSON.stringify but more sense.
306
332
  *
307
- * @api private
333
+ * @private
308
334
  * @param {Object} object
309
335
  * @param {number=} spaces
310
336
  * @param {number=} depth
311
337
  * @returns {*}
312
338
  */
313
- function jsonStringify (object, spaces, depth) {
339
+ function jsonStringify(object, spaces, depth) {
314
340
  if (typeof spaces === 'undefined') {
315
341
  // primitive types
316
342
  return _stringify(object);
@@ -320,13 +346,16 @@ function jsonStringify (object, spaces, depth) {
320
346
  var space = spaces * depth;
321
347
  var str = Array.isArray(object) ? '[' : '{';
322
348
  var end = Array.isArray(object) ? ']' : '}';
323
- var length = typeof object.length === 'number' ? object.length : Object.keys(object).length;
349
+ var length =
350
+ typeof object.length === 'number'
351
+ ? object.length
352
+ : Object.keys(object).length;
324
353
  // `.repeat()` polyfill
325
- function repeat (s, n) {
354
+ function repeat(s, n) {
326
355
  return new Array(n).join(s);
327
356
  }
328
357
 
329
- function _stringify (val) {
358
+ function _stringify(val) {
330
359
  switch (type(val)) {
331
360
  case 'null':
332
361
  case 'undefined':
@@ -340,9 +369,10 @@ function jsonStringify (object, spaces, depth) {
340
369
  case 'regexp':
341
370
  case 'symbol':
342
371
  case 'number':
343
- val = val === 0 && (1 / val) === -Infinity // `-0`
344
- ? '-0'
345
- : val.toString();
372
+ val =
373
+ val === 0 && 1 / val === -Infinity // `-0`
374
+ ? '-0'
375
+ : val.toString();
346
376
  break;
347
377
  case 'date':
348
378
  var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString();
@@ -355,9 +385,10 @@ function jsonStringify (object, spaces, depth) {
355
385
  val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
356
386
  break;
357
387
  default:
358
- val = (val === '[Function]' || val === '[Circular]')
359
- ? val
360
- : JSON.stringify(val); // string
388
+ val =
389
+ val === '[Function]' || val === '[Circular]'
390
+ ? val
391
+ : JSON.stringify(val); // string
361
392
  }
362
393
  return val;
363
394
  }
@@ -367,15 +398,19 @@ function jsonStringify (object, spaces, depth) {
367
398
  continue; // not my business
368
399
  }
369
400
  --length;
370
- str += '\n ' + repeat(' ', space) +
401
+ str +=
402
+ '\n ' +
403
+ repeat(' ', space) +
371
404
  (Array.isArray(object) ? '' : '"' + i + '": ') + // key
372
405
  _stringify(object[i]) + // value
373
406
  (length ? ',' : ''); // comma
374
407
  }
375
408
 
376
- return str +
409
+ return (
410
+ str +
377
411
  // [], {}
378
- (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end);
412
+ (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end)
413
+ );
379
414
  }
380
415
 
381
416
  /**
@@ -390,20 +425,20 @@ function jsonStringify (object, spaces, depth) {
390
425
  * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
391
426
  * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
392
427
  *
393
- * @api private
428
+ * @private
394
429
  * @see {@link exports.stringify}
395
430
  * @param {*} value Thing to inspect. May or may not have properties.
396
431
  * @param {Array} [stack=[]] Stack of seen values
397
432
  * @param {string} [typeHint] Type hint
398
433
  * @return {(Object|Array|Function|string|undefined)}
399
434
  */
400
- exports.canonicalize = function canonicalize (value, stack, typeHint) {
435
+ exports.canonicalize = function canonicalize(value, stack, typeHint) {
401
436
  var canonicalizedObj;
402
437
  /* eslint-disable no-unused-vars */
403
438
  var prop;
404
439
  /* eslint-enable no-unused-vars */
405
440
  typeHint = typeHint || type(value);
406
- function withStack (value, fn) {
441
+ function withStack(value, fn) {
407
442
  stack.push(value);
408
443
  fn();
409
444
  stack.pop();
@@ -422,8 +457,8 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
422
457
  canonicalizedObj = value;
423
458
  break;
424
459
  case 'array':
425
- withStack(value, function () {
426
- canonicalizedObj = value.map(function (item) {
460
+ withStack(value, function() {
461
+ canonicalizedObj = value.map(function(item) {
427
462
  return exports.canonicalize(item, stack);
428
463
  });
429
464
  });
@@ -442,10 +477,12 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
442
477
  /* falls through */
443
478
  case 'object':
444
479
  canonicalizedObj = canonicalizedObj || {};
445
- withStack(value, function () {
446
- Object.keys(value).sort().forEach(function (key) {
447
- canonicalizedObj[key] = exports.canonicalize(value[key], stack);
448
- });
480
+ withStack(value, function() {
481
+ Object.keys(value)
482
+ .sort()
483
+ .forEach(function(key) {
484
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
485
+ });
449
486
  });
450
487
  break;
451
488
  case 'date':
@@ -467,13 +504,13 @@ exports.canonicalize = function canonicalize (value, stack, typeHint) {
467
504
  *
468
505
  * @memberof Mocha.utils
469
506
  * @public
470
- * @api public
471
507
  * @param {string} filepath Base path to start searching from.
472
508
  * @param {string[]} extensions File extensions to look for.
473
509
  * @param {boolean} recursive Whether or not to recurse into subdirectories.
510
+ * @todo Fix extension handling
474
511
  * @return {string[]} An array of paths.
475
512
  */
476
- exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
513
+ exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) {
477
514
  var files = [];
478
515
 
479
516
  if (!fs.existsSync(filepath)) {
@@ -482,7 +519,10 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
482
519
  } else {
483
520
  files = glob.sync(filepath);
484
521
  if (!files.length) {
485
- throw new Error("cannot resolve path (or pattern) '" + filepath + "'");
522
+ throw createNoFilesMatchPatternError(
523
+ 'cannot find any files matching pattern "' + filepath + '"',
524
+ filepath
525
+ );
486
526
  }
487
527
  return files;
488
528
  }
@@ -498,7 +538,7 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
498
538
  return;
499
539
  }
500
540
 
501
- fs.readdirSync(filepath).forEach(function (file) {
541
+ fs.readdirSync(filepath).forEach(function(file) {
502
542
  file = path.join(filepath, file);
503
543
  try {
504
544
  var stat = fs.statSync(file);
@@ -512,6 +552,13 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
512
552
  // ignore error
513
553
  return;
514
554
  }
555
+ if (!extensions) {
556
+ throw createMissingArgumentError(
557
+ 'Argument "extensions" required when argument "filepath" is a directory',
558
+ 'extensions',
559
+ 'array'
560
+ );
561
+ }
515
562
  var re = new RegExp('\\.(?:' + extensions.join('|') + ')$');
516
563
  if (!stat.isFile() || !re.test(file) || path.basename(file)[0] === '.') {
517
564
  return;
@@ -528,8 +575,10 @@ exports.lookupFiles = function lookupFiles (filepath, extensions, recursive) {
528
575
  * @return {Error}
529
576
  */
530
577
 
531
- exports.undefinedError = function () {
532
- return new Error('Caught undefined error, did you throw without specifying what?');
578
+ exports.undefinedError = function() {
579
+ return createUndefinedError(
580
+ 'Caught undefined error, did you throw without specifying what?'
581
+ );
533
582
  };
534
583
 
535
584
  /**
@@ -539,10 +588,30 @@ exports.undefinedError = function () {
539
588
  * @return {Error}
540
589
  */
541
590
 
542
- exports.getError = function (err) {
591
+ exports.getError = function(err) {
543
592
  return err || exports.undefinedError();
544
593
  };
545
594
 
595
+ /**
596
+ * Show a deprecation warning. Each distinct message is only displayed once.
597
+ *
598
+ * @param {string} msg
599
+ */
600
+ exports.deprecate = function deprecate(msg) {
601
+ msg = String(msg);
602
+ if (msg && !deprecate.cache[msg]) {
603
+ deprecate.cache[msg] = true;
604
+ if (process.emitWarning) {
605
+ process.emitWarning(msg, 'DeprecationWarning');
606
+ } else {
607
+ process.nextTick(function() {
608
+ console.warn(msg);
609
+ });
610
+ }
611
+ }
612
+ };
613
+ exports.deprecate.cache = {};
614
+
546
615
  /**
547
616
  * @summary
548
617
  * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
@@ -552,9 +621,9 @@ exports.getError = function (err) {
552
621
  * (i.e: strip Mocha and internal node functions from stack trace).
553
622
  * @returns {Function}
554
623
  */
555
- exports.stackTraceFilter = function () {
624
+ exports.stackTraceFilter = function() {
556
625
  // TODO: Replace with `process.browser`
557
- var is = typeof document === 'undefined' ? { node: true } : { browser: true };
626
+ var is = typeof document === 'undefined' ? {node: true} : {browser: true};
558
627
  var slash = path.sep;
559
628
  var cwd;
560
629
  if (is.node) {
@@ -562,30 +631,35 @@ exports.stackTraceFilter = function () {
562
631
  } else {
563
632
  cwd = (typeof location === 'undefined'
564
633
  ? window.location
565
- : location).href.replace(/\/[^/]*$/, '/');
634
+ : location
635
+ ).href.replace(/\/[^/]*$/, '/');
566
636
  slash = '/';
567
637
  }
568
638
 
569
- function isMochaInternal (line) {
570
- return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) ||
571
- (~line.indexOf('node_modules' + slash + 'mocha.js')) ||
572
- (~line.indexOf('bower_components' + slash + 'mocha.js')) ||
573
- (~line.indexOf(slash + 'mocha.js'));
639
+ function isMochaInternal(line) {
640
+ return (
641
+ ~line.indexOf('node_modules' + slash + 'mocha' + slash) ||
642
+ ~line.indexOf('node_modules' + slash + 'mocha.js') ||
643
+ ~line.indexOf('bower_components' + slash + 'mocha.js') ||
644
+ ~line.indexOf(slash + 'mocha.js')
645
+ );
574
646
  }
575
647
 
576
- function isNodeInternal (line) {
577
- return (~line.indexOf('(timers.js:')) ||
578
- (~line.indexOf('(events.js:')) ||
579
- (~line.indexOf('(node.js:')) ||
580
- (~line.indexOf('(module.js:')) ||
581
- (~line.indexOf('GeneratorFunctionPrototype.next (native)')) ||
582
- false;
648
+ function isNodeInternal(line) {
649
+ return (
650
+ ~line.indexOf('(timers.js:') ||
651
+ ~line.indexOf('(events.js:') ||
652
+ ~line.indexOf('(node.js:') ||
653
+ ~line.indexOf('(module.js:') ||
654
+ ~line.indexOf('GeneratorFunctionPrototype.next (native)') ||
655
+ false
656
+ );
583
657
  }
584
658
 
585
- return function (stack) {
659
+ return function(stack) {
586
660
  stack = stack.split('\n');
587
661
 
588
- stack = stack.reduce(function (list, line) {
662
+ stack = stack.reduce(function(list, line) {
589
663
  if (isMochaInternal(line)) {
590
664
  return list;
591
665
  }
@@ -609,16 +683,31 @@ exports.stackTraceFilter = function () {
609
683
 
610
684
  /**
611
685
  * Crude, but effective.
612
- * @api
686
+ * @public
613
687
  * @param {*} value
614
688
  * @returns {boolean} Whether or not `value` is a Promise
615
689
  */
616
- exports.isPromise = function isPromise (value) {
617
- return typeof value === 'object' && typeof value.then === 'function';
690
+ exports.isPromise = function isPromise(value) {
691
+ return (
692
+ typeof value === 'object' &&
693
+ value !== null &&
694
+ typeof value.then === 'function'
695
+ );
696
+ };
697
+
698
+ /**
699
+ * Clamps a numeric value to an inclusive range.
700
+ *
701
+ * @param {number} value - Value to be clamped.
702
+ * @param {numer[]} range - Two element array specifying [min, max] range.
703
+ * @returns {number} clamped value
704
+ */
705
+ exports.clamp = function clamp(value, range) {
706
+ return Math.min(Math.max(value, range[0]), range[1]);
618
707
  };
619
708
 
620
709
  /**
621
710
  * It's a noop.
622
- * @api
711
+ * @public
623
712
  */
624
- exports.noop = function () {};
713
+ exports.noop = function() {};