mocha 2.0.1 → 2.1.0

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/mocha.js CHANGED
@@ -223,7 +223,22 @@ var JsDiff = (function() {
223
223
 
224
224
  var LineDiff = new Diff();
225
225
  LineDiff.tokenize = function(value) {
226
- return value.split(/^/m);
226
+ var retLines = [],
227
+ lines = value.split(/^/m);
228
+
229
+ for(var i = 0; i < lines.length; i++) {
230
+ var line = lines[i],
231
+ lastLine = lines[i - 1];
232
+
233
+ // Merge lines that may contain windows new lines
234
+ if (line == '\n' && lastLine && lastLine[lastLine.length - 1] === '\r') {
235
+ retLines[retLines.length - 1] += '\n';
236
+ } else if (line) {
237
+ retLines.push(line);
238
+ }
239
+ }
240
+
241
+ return retLines;
227
242
  };
228
243
 
229
244
  return {
@@ -1480,7 +1495,7 @@ function Mocha(options) {
1480
1495
  this.suite = new exports.Suite('', new exports.Context);
1481
1496
  this.ui(options.ui);
1482
1497
  this.bail(options.bail);
1483
- this.reporter(options.reporter);
1498
+ this.reporter(options.reporter, options.reporterOptions);
1484
1499
  if (null != options.timeout) this.timeout(options.timeout);
1485
1500
  this.useColors(options.useColors)
1486
1501
  if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
@@ -1531,10 +1546,10 @@ Mocha.prototype.addFile = function(file){
1531
1546
  * Set reporter to `reporter`, defaults to "spec".
1532
1547
  *
1533
1548
  * @param {String|Function} reporter name or constructor
1549
+ * @param {Object} reporterOptions optional options
1534
1550
  * @api public
1535
1551
  */
1536
-
1537
- Mocha.prototype.reporter = function(reporter){
1552
+ Mocha.prototype.reporter = function(reporter, reporterOptions){
1538
1553
  if ('function' == typeof reporter) {
1539
1554
  this._reporter = reporter;
1540
1555
  } else {
@@ -1549,6 +1564,7 @@ Mocha.prototype.reporter = function(reporter){
1549
1564
  if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
1550
1565
  this._reporter = _reporter;
1551
1566
  }
1567
+ this.options.reporterOptions = reporterOptions;
1552
1568
  return this;
1553
1569
  };
1554
1570
 
@@ -1697,9 +1713,9 @@ Mocha.prototype.globals = function(globals){
1697
1713
  */
1698
1714
 
1699
1715
  Mocha.prototype.useColors = function(colors){
1700
- this.options.useColors = arguments.length && colors != undefined
1701
- ? colors
1702
- : true;
1716
+ if (colors !== undefined) {
1717
+ this.options.useColors = colors;
1718
+ }
1703
1719
  return this;
1704
1720
  };
1705
1721
 
@@ -1801,9 +1817,20 @@ Mocha.prototype.run = function(fn){
1801
1817
  if (options.grep) runner.grep(options.grep, options.invert);
1802
1818
  if (options.globals) runner.globals(options.globals);
1803
1819
  if (options.growl) this._growl(runner, reporter);
1804
- exports.reporters.Base.useColors = options.useColors;
1820
+ if (options.useColors !== undefined) {
1821
+ exports.reporters.Base.useColors = options.useColors;
1822
+ }
1805
1823
  exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
1806
- return runner.run(fn);
1824
+
1825
+ function done(failures) {
1826
+ if (reporter.done) {
1827
+ reporter.done(failures, fn);
1828
+ } else {
1829
+ fn(failures);
1830
+ }
1831
+ }
1832
+
1833
+ return runner.run(done);
1807
1834
  };
1808
1835
 
1809
1836
  }); // module: mocha.js
@@ -2021,7 +2048,7 @@ if ('win32' == process.platform) {
2021
2048
  */
2022
2049
 
2023
2050
  var color = exports.color = function(type, str) {
2024
- if (!exports.useColors) return str;
2051
+ if (!exports.useColors) return String(str);
2025
2052
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
2026
2053
  };
2027
2054
 
@@ -2078,7 +2105,7 @@ exports.cursor = {
2078
2105
  */
2079
2106
 
2080
2107
  exports.list = function(failures){
2081
- console.error();
2108
+ console.log();
2082
2109
  failures.forEach(function(test, i){
2083
2110
  // format
2084
2111
  var fmt = color('error title', ' %s) %s:\n')
@@ -2102,13 +2129,13 @@ exports.list = function(failures){
2102
2129
 
2103
2130
  // explicitly show diff
2104
2131
  if (err.showDiff && sameType(actual, expected)) {
2105
- escape = false;
2106
- err.actual = actual = utils.stringify(actual);
2107
- err.expected = expected = utils.stringify(expected);
2108
- }
2109
2132
 
2110
- // actual / expected diff
2111
- if (err.showDiff && 'string' == typeof actual && 'string' == typeof expected) {
2133
+ if ('string' !== typeof actual) {
2134
+ escape = false;
2135
+ err.actual = actual = utils.stringify(actual);
2136
+ err.expected = expected = utils.stringify(expected);
2137
+ }
2138
+
2112
2139
  fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
2113
2140
  var match = message.match(/^([^:]+): expected/);
2114
2141
  msg = '\n ' + color('error message', match ? match[1] : msg);
@@ -2124,7 +2151,7 @@ exports.list = function(failures){
2124
2151
  stack = stack.slice(index ? index + 1 : index)
2125
2152
  .replace(/^/gm, ' ');
2126
2153
 
2127
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
2154
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
2128
2155
  });
2129
2156
  };
2130
2157
 
@@ -2229,11 +2256,10 @@ Base.prototype.epilogue = function(){
2229
2256
  if (stats.failures) {
2230
2257
  fmt = color('fail', ' %d failing');
2231
2258
 
2232
- console.error(fmt,
2233
- stats.failures);
2259
+ console.log(fmt, stats.failures);
2234
2260
 
2235
2261
  Base.list(this.failures);
2236
- console.error();
2262
+ console.log();
2237
2263
  }
2238
2264
 
2239
2265
  console.log();
@@ -2711,7 +2737,7 @@ function HTML(runner) {
2711
2737
  } else if (test.pending) {
2712
2738
  var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
2713
2739
  } else {
2714
- var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
2740
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
2715
2741
  var str = test.err.stack || test.err.toString();
2716
2742
 
2717
2743
  // FF / Opera do not add the message
@@ -2759,7 +2785,7 @@ function HTML(runner) {
2759
2785
  */
2760
2786
  var makeUrl = function makeUrl(s) {
2761
2787
  var search = window.location.search;
2762
- return (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
2788
+ return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
2763
2789
  };
2764
2790
 
2765
2791
  /**
@@ -3380,6 +3406,12 @@ require.register("reporters/markdown.js", function(module, exports, require){
3380
3406
  var Base = require('./base')
3381
3407
  , utils = require('../utils');
3382
3408
 
3409
+ /**
3410
+ * Constants
3411
+ */
3412
+
3413
+ var SUITE_PREFIX = '$';
3414
+
3383
3415
  /**
3384
3416
  * Expose `Markdown`.
3385
3417
  */
@@ -3410,8 +3442,9 @@ function Markdown(runner) {
3410
3442
  }
3411
3443
 
3412
3444
  function mapTOC(suite, obj) {
3413
- var ret = obj;
3414
- obj = obj[suite.title] = obj[suite.title] || { suite: suite };
3445
+ var ret = obj,
3446
+ key = SUITE_PREFIX + suite.title;
3447
+ obj = obj[key] = obj[key] || { suite: suite };
3415
3448
  suite.suites.forEach(function(suite){
3416
3449
  mapTOC(suite, obj);
3417
3450
  });
@@ -3424,11 +3457,13 @@ function Markdown(runner) {
3424
3457
  var link;
3425
3458
  for (var key in obj) {
3426
3459
  if ('suite' == key) continue;
3427
- if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3428
- if (key) buf += Array(level).join(' ') + link;
3460
+ if (key !== SUITE_PREFIX) {
3461
+ link = ' - [' + key.substring(1) + ']';
3462
+ link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
3463
+ buf += Array(level).join(' ') + link;
3464
+ }
3429
3465
  buf += stringifyTOC(obj[key], level);
3430
3466
  }
3431
- --level;
3432
3467
  return buf;
3433
3468
  }
3434
3469
 
@@ -3517,8 +3552,7 @@ require.register("reporters/nyan.js", function(module, exports, require){
3517
3552
  * Module dependencies.
3518
3553
  */
3519
3554
 
3520
- var Base = require('./base')
3521
- , color = Base.color;
3555
+ var Base = require('./base');
3522
3556
 
3523
3557
  /**
3524
3558
  * Expose `Dot`.
@@ -3595,17 +3629,16 @@ NyanCat.prototype.draw = function(){
3595
3629
 
3596
3630
  NyanCat.prototype.drawScoreboard = function(){
3597
3631
  var stats = this.stats;
3598
- var colors = Base.colors;
3599
3632
 
3600
- function draw(color, n) {
3633
+ function draw(type, n) {
3601
3634
  write(' ');
3602
- write('\u001b[' + color + 'm' + n + '\u001b[0m');
3635
+ write(Base.color(type, n));
3603
3636
  write('\n');
3604
3637
  }
3605
3638
 
3606
- draw(colors.green, stats.passes);
3607
- draw(colors.fail, stats.failures);
3608
- draw(colors.pending, stats.pending);
3639
+ draw('green', stats.passes);
3640
+ draw('fail', stats.failures);
3641
+ draw('pending', stats.pending);
3609
3642
  write('\n');
3610
3643
 
3611
3644
  this.cursorUp(this.numberOfLines);
@@ -3655,26 +3688,26 @@ NyanCat.prototype.drawRainbow = function(){
3655
3688
  NyanCat.prototype.drawNyanCat = function() {
3656
3689
  var self = this;
3657
3690
  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
3658
- var color = '\u001b[' + startWidth + 'C';
3691
+ var dist = '\u001b[' + startWidth + 'C';
3659
3692
  var padding = '';
3660
3693
 
3661
- write(color);
3694
+ write(dist);
3662
3695
  write('_,------,');
3663
3696
  write('\n');
3664
3697
 
3665
- write(color);
3698
+ write(dist);
3666
3699
  padding = self.tick ? ' ' : ' ';
3667
3700
  write('_|' + padding + '/\\_/\\ ');
3668
3701
  write('\n');
3669
3702
 
3670
- write(color);
3703
+ write(dist);
3671
3704
  padding = self.tick ? '_' : '__';
3672
3705
  var tail = self.tick ? '~' : '^';
3673
3706
  var face;
3674
3707
  write(tail + '|' + padding + this.face() + ' ');
3675
3708
  write('\n');
3676
3709
 
3677
- write(color);
3710
+ write(dist);
3678
3711
  padding = self.tick ? ' ' : ' ';
3679
3712
  write(padding + '"" "" ');
3680
3713
  write('\n');
@@ -3755,6 +3788,8 @@ NyanCat.prototype.generateColors = function(){
3755
3788
  */
3756
3789
 
3757
3790
  NyanCat.prototype.rainbowify = function(str){
3791
+ if (!Base.useColors)
3792
+ return str;
3758
3793
  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
3759
3794
  this.colorIndex += 1;
3760
3795
  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
@@ -4053,6 +4088,7 @@ require.register("reporters/xunit.js", function(module, exports, require){
4053
4088
 
4054
4089
  var Base = require('./base')
4055
4090
  , utils = require('../utils')
4091
+ , fs = require('browser/fs')
4056
4092
  , escape = utils.escape;
4057
4093
 
4058
4094
  /**
@@ -4078,12 +4114,19 @@ exports = module.exports = XUnit;
4078
4114
  * @api public
4079
4115
  */
4080
4116
 
4081
- function XUnit(runner) {
4117
+ function XUnit(runner, options) {
4082
4118
  Base.call(this, runner);
4083
4119
  var stats = this.stats
4084
4120
  , tests = []
4085
4121
  , self = this;
4086
4122
 
4123
+ if (options.reporterOptions && options.reporterOptions.output) {
4124
+ if (! fs.createWriteStream) {
4125
+ throw new Error('file output not supported in browser');
4126
+ }
4127
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
4128
+ }
4129
+
4087
4130
  runner.on('pending', function(test){
4088
4131
  tests.push(test);
4089
4132
  });
@@ -4097,7 +4140,7 @@ function XUnit(runner) {
4097
4140
  });
4098
4141
 
4099
4142
  runner.on('end', function(){
4100
- console.log(tag('testsuite', {
4143
+ self.write(tag('testsuite', {
4101
4144
  name: 'Mocha Tests'
4102
4145
  , tests: stats.tests
4103
4146
  , failures: stats.failures
@@ -4107,11 +4150,24 @@ function XUnit(runner) {
4107
4150
  , time: (stats.duration / 1000) || 0
4108
4151
  }, false));
4109
4152
 
4110
- tests.forEach(test);
4111
- console.log('</testsuite>');
4153
+ tests.forEach(function(t) { self.test(t); });
4154
+ self.write('</testsuite>');
4112
4155
  });
4113
4156
  }
4114
4157
 
4158
+ /**
4159
+ * Override done to close the stream (if it's a file).
4160
+ */
4161
+ XUnit.prototype.done = function(failures, fn) {
4162
+ if (this.fileStream) {
4163
+ this.fileStream.end(function() {
4164
+ fn(failures);
4165
+ });
4166
+ } else {
4167
+ fn(failures);
4168
+ }
4169
+ };
4170
+
4115
4171
  /**
4116
4172
  * Inherit from `Base.prototype`.
4117
4173
  */
@@ -4122,11 +4178,22 @@ XUnit.prototype = new F;
4122
4178
  XUnit.prototype.constructor = XUnit;
4123
4179
 
4124
4180
 
4181
+ /**
4182
+ * Write out the given line
4183
+ */
4184
+ XUnit.prototype.write = function(line) {
4185
+ if (this.fileStream) {
4186
+ this.fileStream.write(line + '\n');
4187
+ } else {
4188
+ console.log(line);
4189
+ }
4190
+ };
4191
+
4125
4192
  /**
4126
4193
  * Output tag for the given `test.`
4127
4194
  */
4128
4195
 
4129
- function test(test) {
4196
+ XUnit.prototype.test = function(test, ostream) {
4130
4197
  var attrs = {
4131
4198
  classname: test.parent.fullTitle()
4132
4199
  , name: test.title
@@ -4135,13 +4202,13 @@ function test(test) {
4135
4202
 
4136
4203
  if ('failed' == test.state) {
4137
4204
  var err = test.err;
4138
- console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
4205
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
4139
4206
  } else if (test.pending) {
4140
- console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
4207
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
4141
4208
  } else {
4142
- console.log(tag('testcase', attrs, true) );
4209
+ this.write(tag('testcase', attrs, true) );
4143
4210
  }
4144
- }
4211
+ };
4145
4212
 
4146
4213
  /**
4147
4214
  * HTML tag helper.
@@ -4178,7 +4245,8 @@ require.register("runnable.js", function(module, exports, require){
4178
4245
 
4179
4246
  var EventEmitter = require('browser/events').EventEmitter
4180
4247
  , debug = require('browser/debug')('mocha:runnable')
4181
- , milliseconds = require('./ms');
4248
+ , milliseconds = require('./ms')
4249
+ , utils = require('./utils');
4182
4250
 
4183
4251
  /**
4184
4252
  * Save timer references to avoid Sinon interfering (see GH-237).
@@ -4404,7 +4472,7 @@ Runnable.prototype.run = function(fn){
4404
4472
  done();
4405
4473
  });
4406
4474
  } catch (err) {
4407
- done(err);
4475
+ done(utils.getError(err));
4408
4476
  }
4409
4477
  return;
4410
4478
  }
@@ -4421,7 +4489,7 @@ Runnable.prototype.run = function(fn){
4421
4489
  callFn(this.fn);
4422
4490
  }
4423
4491
  } catch (err) {
4424
- done(err);
4492
+ done(utils.getError(err));
4425
4493
  }
4426
4494
 
4427
4495
  function callFn(fn) {
@@ -4465,7 +4533,9 @@ var globals = [
4465
4533
  'setInterval',
4466
4534
  'clearInterval',
4467
4535
  'XMLHttpRequest',
4468
- 'Date'
4536
+ 'Date',
4537
+ 'setImmediate',
4538
+ 'clearImmediate'
4469
4539
  ];
4470
4540
 
4471
4541
  /**
@@ -4694,7 +4764,6 @@ Runner.prototype.hook = function(name, fn){
4694
4764
  function next(i) {
4695
4765
  var hook = hooks[i];
4696
4766
  if (!hook) return fn();
4697
- if (self.failures && suite.bail()) return fn();
4698
4767
  self.currentRunnable = hook;
4699
4768
 
4700
4769
  hook.ctx.currentTest = self.test;
@@ -4988,7 +5057,7 @@ Runner.prototype.uncaught = function(err){
4988
5057
  }.call(err) ? err : ( err.message || err ));
4989
5058
  } else {
4990
5059
  debug('uncaught undefined exception');
4991
- err = new Error('Caught undefined error, did you throw without specifying what?');
5060
+ err = utils.undefinedError();
4992
5061
  }
4993
5062
  err.uncaught = true;
4994
5063
 
@@ -5229,7 +5298,7 @@ Suite.prototype.clone = function(){
5229
5298
 
5230
5299
  Suite.prototype.timeout = function(ms){
5231
5300
  if (0 == arguments.length) return this._timeout;
5232
- if (ms === 0) this._enableTimeouts = false;
5301
+ if (ms.toString() === '0') this._enableTimeouts = false;
5233
5302
  if ('string' == typeof ms) ms = milliseconds(ms);
5234
5303
  debug('timeout %d', ms);
5235
5304
  this._timeout = parseInt(ms, 10);
@@ -5270,7 +5339,7 @@ Suite.prototype.slow = function(ms){
5270
5339
  /**
5271
5340
  * Sets whether to bail after first error.
5272
5341
  *
5273
- * @parma {Boolean} bail
5342
+ * @param {Boolean} bail
5274
5343
  * @return {Suite|Number} for chaining
5275
5344
  * @api private
5276
5345
  */
@@ -5811,54 +5880,192 @@ exports.highlightTags = function(name) {
5811
5880
  }
5812
5881
  };
5813
5882
 
5883
+ /**
5884
+ * If a value could have properties, and has none, this function is called, which returns
5885
+ * a string representation of the empty value.
5886
+ *
5887
+ * Functions w/ no properties return `'[Function]'`
5888
+ * Arrays w/ length === 0 return `'[]'`
5889
+ * Objects w/ no properties return `'{}'`
5890
+ * All else: return result of `value.toString()`
5891
+ *
5892
+ * @param {*} value Value to inspect
5893
+ * @param {string} [type] The type of the value, if known.
5894
+ * @returns {string}
5895
+ */
5896
+ var emptyRepresentation = function emptyRepresentation(value, type) {
5897
+ type = type || exports.type(value);
5898
+
5899
+ switch(type) {
5900
+ case 'function':
5901
+ return '[Function]';
5902
+ case 'object':
5903
+ return '{}';
5904
+ case 'array':
5905
+ return '[]';
5906
+ default:
5907
+ return value.toString();
5908
+ }
5909
+ };
5910
+
5911
+ /**
5912
+ * Takes some variable and asks `{}.toString()` what it thinks it is.
5913
+ * @param {*} value Anything
5914
+ * @example
5915
+ * type({}) // 'object'
5916
+ * type([]) // 'array'
5917
+ * type(1) // 'number'
5918
+ * type(false) // 'boolean'
5919
+ * type(Infinity) // 'number'
5920
+ * type(null) // 'null'
5921
+ * type(new Date()) // 'date'
5922
+ * type(/foo/) // 'regexp'
5923
+ * type('type') // 'string'
5924
+ * type(global) // 'global'
5925
+ * @api private
5926
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
5927
+ * @returns {string}
5928
+ */
5929
+ exports.type = function type(value) {
5930
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
5931
+ return 'buffer';
5932
+ }
5933
+ return Object.prototype.toString.call(value)
5934
+ .replace(/^\[.+\s(.+?)\]$/, '$1')
5935
+ .toLowerCase();
5936
+ };
5814
5937
 
5815
5938
  /**
5816
- * Stringify `obj`.
5939
+ * @summary Stringify `value`.
5940
+ * @description Different behavior depending on type of value.
5941
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
5942
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
5943
+ * - If `value` is an *empty* object, function, or array, return result of function
5944
+ * {@link emptyRepresentation}.
5945
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
5946
+ * JSON.stringify().
5817
5947
  *
5818
- * @param {Object} obj
5819
- * @return {String}
5948
+ * @see exports.type
5949
+ * @param {*} value
5950
+ * @return {string}
5820
5951
  * @api private
5821
5952
  */
5822
5953
 
5823
- exports.stringify = function(obj) {
5824
- if (obj instanceof RegExp) return obj.toString();
5825
- return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1');
5954
+ exports.stringify = function(value) {
5955
+ var prop,
5956
+ type = exports.type(value);
5957
+
5958
+ if (type === 'null' || type === 'undefined') {
5959
+ return '[' + type + ']';
5960
+ }
5961
+
5962
+ if (type === 'date') {
5963
+ return '[Date: ' + value.toISOString() + ']';
5964
+ }
5965
+
5966
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
5967
+ return value.toString();
5968
+ }
5969
+
5970
+ for (prop in value) {
5971
+ if (value.hasOwnProperty(prop)) {
5972
+ return JSON.stringify(exports.canonicalize(value), null, 2).replace(/,(\n|$)/g, '$1');
5973
+ }
5974
+ }
5975
+
5976
+ return emptyRepresentation(value, type);
5826
5977
  };
5827
5978
 
5828
5979
  /**
5829
- * Return a new object that has the keys in sorted order.
5830
- * @param {Object} obj
5831
- * @param {Array} [stack]
5832
- * @return {Object}
5980
+ * Return if obj is a Buffer
5981
+ * @param {Object} arg
5982
+ * @return {Boolean}
5833
5983
  * @api private
5834
5984
  */
5985
+ exports.isBuffer = function (arg) {
5986
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(arg);
5987
+ };
5835
5988
 
5836
- exports.canonicalize = function(obj, stack) {
5837
- stack = stack || [];
5989
+ /**
5990
+ * @summary Return a new Thing that has the keys in sorted order. Recursive.
5991
+ * @description If the Thing...
5992
+ * - has already been seen, return string `'[Circular]'`
5993
+ * - is `undefined`, return string `'[undefined]'`
5994
+ * - is `null`, return value `null`
5995
+ * - is some other primitive, return the value
5996
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
5997
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
5998
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
5999
+ *
6000
+ * @param {*} value Thing to inspect. May or may not have properties.
6001
+ * @param {Array} [stack=[]] Stack of seen values
6002
+ * @return {(Object|Array|Function|string|undefined)}
6003
+ * @see {@link exports.stringify}
6004
+ * @api private
6005
+ */
5838
6006
 
5839
- if (exports.indexOf(stack, obj) !== -1) return '[Circular]';
6007
+ exports.canonicalize = function(value, stack) {
6008
+ var canonicalizedObj,
6009
+ type = exports.type(value),
6010
+ prop,
6011
+ withStack = function withStack(value, fn) {
6012
+ stack.push(value);
6013
+ fn();
6014
+ stack.pop();
6015
+ };
5840
6016
 
5841
- var canonicalizedObj;
6017
+ stack = stack || [];
5842
6018
 
5843
- if ({}.toString.call(obj) === '[object Array]') {
5844
- stack.push(obj);
5845
- canonicalizedObj = exports.map(obj, function (item) {
5846
- return exports.canonicalize(item, stack);
5847
- });
5848
- stack.pop();
5849
- } else if (typeof obj === 'object' && obj !== null) {
5850
- stack.push(obj);
5851
- canonicalizedObj = {};
5852
- exports.forEach(exports.keys(obj).sort(), function (key) {
5853
- canonicalizedObj[key] = exports.canonicalize(obj[key], stack);
5854
- });
5855
- stack.pop();
5856
- } else {
5857
- canonicalizedObj = obj;
6019
+ if (exports.indexOf(stack, value) !== -1) {
6020
+ return '[Circular]';
6021
+ }
6022
+
6023
+ switch(type) {
6024
+ case 'undefined':
6025
+ canonicalizedObj = '[undefined]';
6026
+ break;
6027
+ case 'buffer':
6028
+ case 'null':
6029
+ canonicalizedObj = value;
6030
+ break;
6031
+ case 'array':
6032
+ withStack(value, function () {
6033
+ canonicalizedObj = exports.map(value, function (item) {
6034
+ return exports.canonicalize(item, stack);
6035
+ });
6036
+ });
6037
+ break;
6038
+ case 'date':
6039
+ canonicalizedObj = '[Date: ' + value.toISOString() + ']';
6040
+ break;
6041
+ case 'function':
6042
+ for (prop in value) {
6043
+ canonicalizedObj = {};
6044
+ break;
6045
+ }
6046
+ if (!canonicalizedObj) {
6047
+ canonicalizedObj = emptyRepresentation(value, type);
6048
+ break;
6049
+ }
6050
+ /* falls through */
6051
+ case 'object':
6052
+ canonicalizedObj = canonicalizedObj || {};
6053
+ withStack(value, function () {
6054
+ exports.forEach(exports.keys(value).sort(), function (key) {
6055
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
6056
+ });
6057
+ });
6058
+ break;
6059
+ case 'number':
6060
+ case 'boolean':
6061
+ canonicalizedObj = value;
6062
+ break;
6063
+ default:
6064
+ canonicalizedObj = value.toString();
5858
6065
  }
5859
6066
 
5860
6067
  return canonicalizedObj;
5861
- };
6068
+ };
5862
6069
 
5863
6070
  /**
5864
6071
  * Lookup file names at the given `path`.
@@ -5906,6 +6113,28 @@ exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
5906
6113
  return files;
5907
6114
  };
5908
6115
 
6116
+ /**
6117
+ * Generate an undefined error with a message warning the user.
6118
+ *
6119
+ * @return {Error}
6120
+ */
6121
+
6122
+ exports.undefinedError = function(){
6123
+ return new Error('Caught undefined error, did you throw without specifying what?');
6124
+ };
6125
+
6126
+ /**
6127
+ * Generate an undefined error if `err` is not defined.
6128
+ *
6129
+ * @param {Error} err
6130
+ * @return {Error}
6131
+ */
6132
+
6133
+ exports.getError = function(err){
6134
+ return err || exports.undefinedError();
6135
+ };
6136
+
6137
+
5909
6138
  }); // module: utils.js
5910
6139
  // The global object is "self" in Web Workers.
5911
6140
  var global = (function() { return this; })();