mocha 1.21.4 → 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.
Files changed (47) hide show
  1. package/README.md +226 -0
  2. package/bin/_mocha +26 -47
  3. package/bin/mocha +8 -1
  4. package/index.js +1 -2
  5. package/lib/browser/debug.js +0 -1
  6. package/lib/browser/diff.js +16 -1
  7. package/lib/browser/escape-string-regexp.js +11 -0
  8. package/lib/browser/events.js +1 -2
  9. package/lib/browser/glob.js +0 -0
  10. package/lib/browser/progress.js +6 -6
  11. package/lib/browser/tty.js +0 -1
  12. package/lib/context.js +0 -1
  13. package/lib/hook.js +0 -1
  14. package/lib/interfaces/bdd.js +4 -4
  15. package/lib/interfaces/exports.js +1 -2
  16. package/lib/interfaces/index.js +0 -1
  17. package/lib/interfaces/qunit.js +2 -2
  18. package/lib/interfaces/tdd.js +4 -4
  19. package/lib/mocha.js +32 -9
  20. package/lib/ms.js +1 -1
  21. package/lib/reporters/base.js +11 -13
  22. package/lib/reporters/doc.js +0 -1
  23. package/lib/reporters/dot.js +0 -1
  24. package/lib/reporters/html-cov.js +1 -2
  25. package/lib/reporters/html.js +13 -5
  26. package/lib/reporters/index.js +0 -1
  27. package/lib/reporters/json-cov.js +1 -2
  28. package/lib/reporters/json-stream.js +4 -3
  29. package/lib/reporters/json.js +7 -2
  30. package/lib/reporters/landing.js +3 -4
  31. package/lib/reporters/list.js +0 -1
  32. package/lib/reporters/markdown.js +15 -6
  33. package/lib/reporters/min.js +0 -1
  34. package/lib/reporters/nyan.js +14 -14
  35. package/lib/reporters/spec.js +0 -1
  36. package/lib/reporters/tap.js +0 -1
  37. package/lib/reporters/templates/coverage.jade +2 -1
  38. package/lib/reporters/templates/style.html +1 -1
  39. package/lib/reporters/xunit.js +41 -10
  40. package/lib/runnable.js +8 -6
  41. package/lib/runner.js +17 -9
  42. package/lib/suite.js +3 -3
  43. package/lib/test.js +0 -1
  44. package/lib/utils.js +247 -49
  45. package/mocha.js +487 -172
  46. package/package.json +20 -13
  47. package/Readme.md +0 -203
package/lib/mocha.js CHANGED
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  var path = require('path')
12
+ , escapeRe = require('escape-string-regexp')
12
13
  , utils = require('./utils');
13
14
 
14
15
  /**
@@ -79,7 +80,7 @@ function Mocha(options) {
79
80
  this.suite = new exports.Suite('', new exports.Context);
80
81
  this.ui(options.ui);
81
82
  this.bail(options.bail);
82
- this.reporter(options.reporter);
83
+ this.reporter(options.reporter, options.reporterOptions);
83
84
  if (null != options.timeout) this.timeout(options.timeout);
84
85
  this.useColors(options.useColors)
85
86
  if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts);
@@ -130,10 +131,10 @@ Mocha.prototype.addFile = function(file){
130
131
  * Set reporter to `reporter`, defaults to "spec".
131
132
  *
132
133
  * @param {String|Function} reporter name or constructor
134
+ * @param {Object} reporterOptions optional options
133
135
  * @api public
134
136
  */
135
-
136
- Mocha.prototype.reporter = function(reporter){
137
+ Mocha.prototype.reporter = function(reporter, reporterOptions){
137
138
  if ('function' == typeof reporter) {
138
139
  this._reporter = reporter;
139
140
  } else {
@@ -148,6 +149,7 @@ Mocha.prototype.reporter = function(reporter){
148
149
  if (!_reporter) throw new Error('invalid reporter "' + reporter + '"');
149
150
  this._reporter = _reporter;
150
151
  }
152
+ this.options.reporterOptions = reporterOptions;
151
153
  return this;
152
154
  };
153
155
 
@@ -220,7 +222,7 @@ Mocha.prototype._growl = function(runner, reporter) {
220
222
 
221
223
  Mocha.prototype.grep = function(re){
222
224
  this.options.grep = 'string' == typeof re
223
- ? new RegExp(utils.escapeRegexp(re))
225
+ ? new RegExp(escapeRe(re))
224
226
  : re;
225
227
  return this;
226
228
  };
@@ -296,9 +298,9 @@ Mocha.prototype.globals = function(globals){
296
298
  */
297
299
 
298
300
  Mocha.prototype.useColors = function(colors){
299
- this.options.useColors = arguments.length && colors != undefined
300
- ? colors
301
- : true;
301
+ if (colors !== undefined) {
302
+ this.options.useColors = colors;
303
+ }
302
304
  return this;
303
305
  };
304
306
 
@@ -370,6 +372,16 @@ Mocha.prototype.asyncOnly = function(){
370
372
  return this;
371
373
  };
372
374
 
375
+ /**
376
+ * Disable syntax highlighting (in browser).
377
+ * @returns {Mocha}
378
+ * @api public
379
+ */
380
+ Mocha.prototype.noHighlighting = function() {
381
+ this.options.noHighlighting = true;
382
+ return this;
383
+ };
384
+
373
385
  /**
374
386
  * Run tests and invoke `fn()` when complete.
375
387
  *
@@ -390,7 +402,18 @@ Mocha.prototype.run = function(fn){
390
402
  if (options.grep) runner.grep(options.grep, options.invert);
391
403
  if (options.globals) runner.globals(options.globals);
392
404
  if (options.growl) this._growl(runner, reporter);
393
- exports.reporters.Base.useColors = options.useColors;
405
+ if (options.useColors !== undefined) {
406
+ exports.reporters.Base.useColors = options.useColors;
407
+ }
394
408
  exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
395
- return runner.run(fn);
409
+
410
+ function done(failures) {
411
+ if (reporter.done) {
412
+ reporter.done(failures, fn);
413
+ } else {
414
+ fn(failures);
415
+ }
416
+ }
417
+
418
+ return runner.run(done);
396
419
  };
package/lib/ms.js CHANGED
@@ -24,7 +24,7 @@ var y = d * 365.25;
24
24
  module.exports = function(val, options){
25
25
  options = options || {};
26
26
  if ('string' == typeof val) return parse(val);
27
- return options.long ? longFormat(val) : shortFormat(val);
27
+ return options['long'] ? longFormat(val) : shortFormat(val);
28
28
  };
29
29
 
30
30
  /**
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -98,7 +97,7 @@ if ('win32' == process.platform) {
98
97
  */
99
98
 
100
99
  var color = exports.color = function(type, str) {
101
- if (!exports.useColors) return str;
100
+ if (!exports.useColors) return String(str);
102
101
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
103
102
  };
104
103
 
@@ -155,7 +154,7 @@ exports.cursor = {
155
154
  */
156
155
 
157
156
  exports.list = function(failures){
158
- console.error();
157
+ console.log();
159
158
  failures.forEach(function(test, i){
160
159
  // format
161
160
  var fmt = color('error title', ' %s) %s:\n')
@@ -179,13 +178,13 @@ exports.list = function(failures){
179
178
 
180
179
  // explicitly show diff
181
180
  if (err.showDiff && sameType(actual, expected)) {
182
- escape = false;
183
- err.actual = actual = utils.stringify(actual);
184
- err.expected = expected = utils.stringify(expected);
185
- }
186
181
 
187
- // actual / expected diff
188
- if ('string' == typeof actual && 'string' == typeof expected) {
182
+ if ('string' !== typeof actual) {
183
+ escape = false;
184
+ err.actual = actual = utils.stringify(actual);
185
+ err.expected = expected = utils.stringify(expected);
186
+ }
187
+
189
188
  fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
190
189
  var match = message.match(/^([^:]+): expected/);
191
190
  msg = '\n ' + color('error message', match ? match[1] : msg);
@@ -201,7 +200,7 @@ exports.list = function(failures){
201
200
  stack = stack.slice(index ? index + 1 : index)
202
201
  .replace(/^/gm, ' ');
203
202
 
204
- console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
203
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
205
204
  });
206
205
  };
207
206
 
@@ -306,11 +305,10 @@ Base.prototype.epilogue = function(){
306
305
  if (stats.failures) {
307
306
  fmt = color('fail', ' %d failing');
308
307
 
309
- console.error(fmt,
310
- stats.failures);
308
+ console.log(fmt, stats.failures);
311
309
 
312
310
  Base.list(this.failures);
313
- console.error();
311
+ console.log();
314
312
  }
315
313
 
316
314
  console.log();
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -48,4 +47,4 @@ function coverageClass(n) {
48
47
  if (n >= 50) return 'medium';
49
48
  if (n >= 25) return 'low';
50
49
  return 'terrible';
51
- }
50
+ }
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -136,7 +135,7 @@ function HTML(runner) {
136
135
  } else if (test.pending) {
137
136
  var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
138
137
  } else {
139
- var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
138
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', test.title, self.testURL(test));
140
139
  var str = test.err.stack || test.err.toString();
141
140
 
142
141
  // FF / Opera do not add the message
@@ -177,14 +176,23 @@ function HTML(runner) {
177
176
  });
178
177
  }
179
178
 
179
+ /**
180
+ * Makes a URL, preserving querystring ("search") parameters.
181
+ * @param {string} s
182
+ * @returns {string} your new URL
183
+ */
184
+ var makeUrl = function makeUrl(s) {
185
+ var search = window.location.search;
186
+ return window.location.pathname + (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s);
187
+ };
188
+
180
189
  /**
181
190
  * Provide suite URL
182
191
  *
183
192
  * @param {Object} [suite]
184
193
  */
185
-
186
194
  HTML.prototype.suiteURL = function(suite){
187
- return '?grep=' + encodeURIComponent(suite.fullTitle());
195
+ return makeUrl(suite.fullTitle());
188
196
  };
189
197
 
190
198
  /**
@@ -194,7 +202,7 @@ HTML.prototype.suiteURL = function(suite){
194
202
  */
195
203
 
196
204
  HTML.prototype.testURL = function(test){
197
- return '?grep=' + encodeURIComponent(test.fullTitle());
205
+ return makeUrl(test.fullTitle());
198
206
  };
199
207
 
200
208
  /**
@@ -1,4 +1,3 @@
1
-
2
1
  exports.Base = require('./base');
3
2
  exports.Dot = require('./dot');
4
3
  exports.Doc = require('./doc');
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -89,7 +88,7 @@ function map(cov) {
89
88
  }
90
89
 
91
90
  return ret;
92
- };
91
+ }
93
92
 
94
93
  /**
95
94
  * Map jscoverage data for a single source file
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -35,7 +34,9 @@ function List(runner) {
35
34
  });
36
35
 
37
36
  runner.on('fail', function(test, err){
38
- console.log(JSON.stringify(['fail', clean(test)]));
37
+ test = clean(test);
38
+ test.err = err.message;
39
+ console.log(JSON.stringify(['fail', test]));
39
40
  });
40
41
 
41
42
  runner.on('end', function(){
@@ -58,4 +59,4 @@ function clean(test) {
58
59
  , fullTitle: test.fullTitle()
59
60
  , duration: test.duration
60
61
  }
61
- }
62
+ }
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -25,6 +24,7 @@ function JSONReporter(runner) {
25
24
  Base.call(this, runner);
26
25
 
27
26
  var tests = []
27
+ , pending = []
28
28
  , failures = []
29
29
  , passes = [];
30
30
 
@@ -40,10 +40,15 @@ function JSONReporter(runner) {
40
40
  failures.push(test);
41
41
  });
42
42
 
43
+ runner.on('pending', function(test){
44
+ pending.push(test);
45
+ });
46
+
43
47
  runner.on('end', function(){
44
48
  var obj = {
45
49
  stats: self.stats,
46
50
  tests: tests.map(clean),
51
+ pending: pending.map(clean),
47
52
  failures: failures.map(clean),
48
53
  passes: passes.map(clean)
49
54
  };
@@ -68,7 +73,7 @@ function clean(test) {
68
73
  title: test.title,
69
74
  fullTitle: test.fullTitle(),
70
75
  duration: test.duration,
71
- err: errorJSON(test.err)
76
+ err: errorJSON(test.err || {})
72
77
  }
73
78
  }
74
79
 
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -56,7 +55,7 @@ function Landing(runner) {
56
55
  }
57
56
 
58
57
  runner.on('start', function(){
59
- stream.write('\n ');
58
+ stream.write('\n\n\n ');
60
59
  cursor.hide();
61
60
  });
62
61
 
@@ -73,7 +72,7 @@ function Landing(runner) {
73
72
  }
74
73
 
75
74
  // render landing strip
76
- stream.write('\u001b[4F\n\n');
75
+ stream.write('\u001b['+(width+1)+'D\u001b[2A');
77
76
  stream.write(runway());
78
77
  stream.write('\n ');
79
78
  stream.write(color('runway', Array(col).join('⋅')));
@@ -94,4 +93,4 @@ function Landing(runner) {
94
93
  * Inherit from `Base.prototype`.
95
94
  */
96
95
 
97
- Landing.prototype.__proto__ = Base.prototype;
96
+ Landing.prototype.__proto__ = Base.prototype;
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -5,6 +5,12 @@
5
5
  var Base = require('./base')
6
6
  , utils = require('../utils');
7
7
 
8
+ /**
9
+ * Constants
10
+ */
11
+
12
+ var SUITE_PREFIX = '$';
13
+
8
14
  /**
9
15
  * Expose `Markdown`.
10
16
  */
@@ -35,8 +41,9 @@ function Markdown(runner) {
35
41
  }
36
42
 
37
43
  function mapTOC(suite, obj) {
38
- var ret = obj;
39
- obj = obj[suite.title] = obj[suite.title] || { suite: suite };
44
+ var ret = obj,
45
+ key = SUITE_PREFIX + suite.title;
46
+ obj = obj[key] = obj[key] || { suite: suite };
40
47
  suite.suites.forEach(function(suite){
41
48
  mapTOC(suite, obj);
42
49
  });
@@ -49,11 +56,13 @@ function Markdown(runner) {
49
56
  var link;
50
57
  for (var key in obj) {
51
58
  if ('suite' == key) continue;
52
- if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
53
- if (key) buf += Array(level).join(' ') + link;
59
+ if (key !== SUITE_PREFIX) {
60
+ link = ' - [' + key.substring(1) + ']';
61
+ link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
62
+ buf += Array(level).join(' ') + link;
63
+ }
54
64
  buf += stringifyTOC(obj[key], level);
55
65
  }
56
- --level;
57
66
  return buf;
58
67
  }
59
68
 
@@ -88,4 +97,4 @@ function Markdown(runner) {
88
97
  process.stdout.write(generateTOC(runner.suite));
89
98
  process.stdout.write(buf);
90
99
  });
91
- }
100
+ }
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -2,8 +2,7 @@
2
2
  * Module dependencies.
3
3
  */
4
4
 
5
- var Base = require('./base')
6
- , color = Base.color;
5
+ var Base = require('./base');
7
6
 
8
7
  /**
9
8
  * Expose `Dot`.
@@ -80,17 +79,16 @@ NyanCat.prototype.draw = function(){
80
79
 
81
80
  NyanCat.prototype.drawScoreboard = function(){
82
81
  var stats = this.stats;
83
- var colors = Base.colors;
84
82
 
85
- function draw(color, n) {
83
+ function draw(type, n) {
86
84
  write(' ');
87
- write('\u001b[' + color + 'm' + n + '\u001b[0m');
85
+ write(Base.color(type, n));
88
86
  write('\n');
89
87
  }
90
88
 
91
- draw(colors.green, stats.passes);
92
- draw(colors.fail, stats.failures);
93
- draw(colors.pending, stats.pending);
89
+ draw('green', stats.passes);
90
+ draw('fail', stats.failures);
91
+ draw('pending', stats.pending);
94
92
  write('\n');
95
93
 
96
94
  this.cursorUp(this.numberOfLines);
@@ -140,26 +138,26 @@ NyanCat.prototype.drawRainbow = function(){
140
138
  NyanCat.prototype.drawNyanCat = function() {
141
139
  var self = this;
142
140
  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
143
- var color = '\u001b[' + startWidth + 'C';
141
+ var dist = '\u001b[' + startWidth + 'C';
144
142
  var padding = '';
145
143
 
146
- write(color);
144
+ write(dist);
147
145
  write('_,------,');
148
146
  write('\n');
149
147
 
150
- write(color);
148
+ write(dist);
151
149
  padding = self.tick ? ' ' : ' ';
152
150
  write('_|' + padding + '/\\_/\\ ');
153
151
  write('\n');
154
152
 
155
- write(color);
153
+ write(dist);
156
154
  padding = self.tick ? '_' : '__';
157
155
  var tail = self.tick ? '~' : '^';
158
156
  var face;
159
157
  write(tail + '|' + padding + this.face() + ' ');
160
158
  write('\n');
161
159
 
162
- write(color);
160
+ write(dist);
163
161
  padding = self.tick ? ' ' : ' ';
164
162
  write(padding + '"" "" ');
165
163
  write('\n');
@@ -185,7 +183,7 @@ NyanCat.prototype.face = function() {
185
183
  } else {
186
184
  return '( - .-)';
187
185
  }
188
- }
186
+ };
189
187
 
190
188
  /**
191
189
  * Move cursor up `n`.
@@ -240,6 +238,8 @@ NyanCat.prototype.generateColors = function(){
240
238
  */
241
239
 
242
240
  NyanCat.prototype.rainbowify = function(str){
241
+ if (!Base.useColors)
242
+ return str;
243
243
  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
244
244
  this.colorIndex += 1;
245
245
  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -1,4 +1,3 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
@@ -1,7 +1,8 @@
1
- !!! 5
1
+ doctype html
2
2
  html
3
3
  head
4
4
  title Coverage
5
+ meta(charset='utf-8')
5
6
  include script.html
6
7
  include style.html
7
8
  body
@@ -317,4 +317,4 @@ code .init { color: #2F6FAD }
317
317
  code .string { color: #5890AD }
318
318
  code .keyword { color: #8A6343 }
319
319
  code .number { color: #2F6FAD }
320
- </style>
320
+ </style>
@@ -1,10 +1,10 @@
1
-
2
1
  /**
3
2
  * Module dependencies.
4
3
  */
5
4
 
6
5
  var Base = require('./base')
7
6
  , utils = require('../utils')
7
+ , fs = require('fs')
8
8
  , escape = utils.escape;
9
9
 
10
10
  /**
@@ -30,12 +30,19 @@ exports = module.exports = XUnit;
30
30
  * @api public
31
31
  */
32
32
 
33
- function XUnit(runner) {
33
+ function XUnit(runner, options) {
34
34
  Base.call(this, runner);
35
35
  var stats = this.stats
36
36
  , tests = []
37
37
  , self = this;
38
38
 
39
+ if (options.reporterOptions && options.reporterOptions.output) {
40
+ if (! fs.createWriteStream) {
41
+ throw new Error('file output not supported in browser');
42
+ }
43
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
44
+ }
45
+
39
46
  runner.on('pending', function(test){
40
47
  tests.push(test);
41
48
  });
@@ -49,7 +56,7 @@ function XUnit(runner) {
49
56
  });
50
57
 
51
58
  runner.on('end', function(){
52
- console.log(tag('testsuite', {
59
+ self.write(tag('testsuite', {
53
60
  name: 'Mocha Tests'
54
61
  , tests: stats.tests
55
62
  , failures: stats.failures
@@ -59,22 +66,46 @@ function XUnit(runner) {
59
66
  , time: (stats.duration / 1000) || 0
60
67
  }, false));
61
68
 
62
- tests.forEach(test);
63
- console.log('</testsuite>');
69
+ tests.forEach(function(t) { self.test(t); });
70
+ self.write('</testsuite>');
64
71
  });
65
72
  }
66
73
 
74
+ /**
75
+ * Override done to close the stream (if it's a file).
76
+ */
77
+ XUnit.prototype.done = function(failures, fn) {
78
+ if (this.fileStream) {
79
+ this.fileStream.end(function() {
80
+ fn(failures);
81
+ });
82
+ } else {
83
+ fn(failures);
84
+ }
85
+ };
86
+
67
87
  /**
68
88
  * Inherit from `Base.prototype`.
69
89
  */
70
90
 
71
91
  XUnit.prototype.__proto__ = Base.prototype;
72
92
 
93
+ /**
94
+ * Write out the given line
95
+ */
96
+ XUnit.prototype.write = function(line) {
97
+ if (this.fileStream) {
98
+ this.fileStream.write(line + '\n');
99
+ } else {
100
+ console.log(line);
101
+ }
102
+ };
103
+
73
104
  /**
74
105
  * Output tag for the given `test.`
75
106
  */
76
107
 
77
- function test(test) {
108
+ XUnit.prototype.test = function(test, ostream) {
78
109
  var attrs = {
79
110
  classname: test.parent.fullTitle()
80
111
  , name: test.title
@@ -83,13 +114,13 @@ function test(test) {
83
114
 
84
115
  if ('failed' == test.state) {
85
116
  var err = test.err;
86
- console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
117
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
87
118
  } else if (test.pending) {
88
- console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
119
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
89
120
  } else {
90
- console.log(tag('testcase', attrs, true) );
121
+ this.write(tag('testcase', attrs, true) );
91
122
  }
92
- }
123
+ };
93
124
 
94
125
  /**
95
126
  * HTML tag helper.