reporter.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. 'use strict';
  2. const inherits = require('inherits');
  3. function Reporter(options) {
  4. this._reporterState = {
  5. obj: null,
  6. path: [],
  7. options: options || {},
  8. errors: []
  9. };
  10. }
  11. exports.Reporter = Reporter;
  12. Reporter.prototype.isError = function isError(obj) {
  13. return obj instanceof ReporterError;
  14. };
  15. Reporter.prototype.save = function save() {
  16. const state = this._reporterState;
  17. return { obj: state.obj, pathLen: state.path.length };
  18. };
  19. Reporter.prototype.restore = function restore(data) {
  20. const state = this._reporterState;
  21. state.obj = data.obj;
  22. state.path = state.path.slice(0, data.pathLen);
  23. };
  24. Reporter.prototype.enterKey = function enterKey(key) {
  25. return this._reporterState.path.push(key);
  26. };
  27. Reporter.prototype.exitKey = function exitKey(index) {
  28. const state = this._reporterState;
  29. state.path = state.path.slice(0, index - 1);
  30. };
  31. Reporter.prototype.leaveKey = function leaveKey(index, key, value) {
  32. const state = this._reporterState;
  33. this.exitKey(index);
  34. if (state.obj !== null)
  35. state.obj[key] = value;
  36. };
  37. Reporter.prototype.path = function path() {
  38. return this._reporterState.path.join('/');
  39. };
  40. Reporter.prototype.enterObject = function enterObject() {
  41. const state = this._reporterState;
  42. const prev = state.obj;
  43. state.obj = {};
  44. return prev;
  45. };
  46. Reporter.prototype.leaveObject = function leaveObject(prev) {
  47. const state = this._reporterState;
  48. const now = state.obj;
  49. state.obj = prev;
  50. return now;
  51. };
  52. Reporter.prototype.error = function error(msg) {
  53. let err;
  54. const state = this._reporterState;
  55. const inherited = msg instanceof ReporterError;
  56. if (inherited) {
  57. err = msg;
  58. } else {
  59. err = new ReporterError(state.path.map(function(elem) {
  60. return '[' + JSON.stringify(elem) + ']';
  61. }).join(''), msg.message || msg, msg.stack);
  62. }
  63. if (!state.options.partial)
  64. throw err;
  65. if (!inherited)
  66. state.errors.push(err);
  67. return err;
  68. };
  69. Reporter.prototype.wrapResult = function wrapResult(result) {
  70. const state = this._reporterState;
  71. if (!state.options.partial)
  72. return result;
  73. return {
  74. result: this.isError(result) ? null : result,
  75. errors: state.errors
  76. };
  77. };
  78. function ReporterError(path, msg) {
  79. this.path = path;
  80. this.rethrow(msg);
  81. }
  82. inherits(ReporterError, Error);
  83. ReporterError.prototype.rethrow = function rethrow(msg) {
  84. this.message = msg + ' at: ' + (this.path || '(shallow)');
  85. if (Error.captureStackTrace)
  86. Error.captureStackTrace(this, ReporterError);
  87. if (!this.stack) {
  88. try {
  89. // IE only adds stack when thrown
  90. throw new Error(this.message);
  91. } catch (e) {
  92. this.stack = e.stack;
  93. }
  94. }
  95. return this;
  96. };