Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

verror.js 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. 'use strict';
  2. /*
  3. * verror.js: richer JavaScript errors
  4. */
  5. const util = require('util');
  6. const _ = require('lodash');
  7. const assert = require('assert-plus');
  8. const { sprintf } = require('extsprintf');
  9. /*
  10. * Public interface
  11. */
  12. /* So you can 'var VError = require('@netflix/nerror')' */
  13. module.exports = VError;
  14. /* For compatibility */
  15. VError.VError = VError;
  16. /* Other exported classes */
  17. VError.PError = PError;
  18. VError.SError = SError;
  19. VError.WError = WError;
  20. VError.MultiError = MultiError;
  21. /**
  22. * Normalized forms, producing an object with the following properties.
  23. * @private
  24. * @typedef {Object} ParsedOptions parsed Options
  25. * @param {Object} options e- quivalent to "options" in third form. This will
  26. * never
  27. * be a direct reference to what the caller passed in
  28. * (i.e., it may be a shallow copy), so it can be freely
  29. * modified.
  30. * @param {String} shortmessage - result of sprintf(sprintf_args), taking
  31. * `options.strict` into account as described in README.md.
  32. */
  33. /**
  34. * Common function used to parse constructor arguments for VError, WError, and
  35. * SError. Named arguments to this function:
  36. *
  37. * strict force strict interpretation of sprintf arguments, even
  38. * if the options in "argv" don't say so
  39. *
  40. * argv error's constructor arguments, which are to be
  41. * interpreted as described in README.md. For quick
  42. * reference, "argv" has one of the following forms:
  43. *
  44. * [ sprintf_args... ] (argv[0] is a string)
  45. * [ cause, sprintf_args... ] (argv[0] is an Error)
  46. * [ options, sprintf_args... ] (argv[0] is an object)
  47. *
  48. * @private
  49. * @param {Array} args - arguments
  50. * @returns {ParsedOptions} parsed options
  51. */
  52. function parseConstructorArguments(args) {
  53. let options, sprintf_args, shortmessage, k;
  54. assert.object(args, 'args');
  55. assert.bool(args.strict, 'args.strict');
  56. assert.array(args.argv, 'args.argv');
  57. assert.optionalBool(args.skipPrintf, 'args.skipPrintf');
  58. const argv = args.argv;
  59. /*
  60. * First, figure out which form of invocation we've been given.
  61. */
  62. if (argv.length === 0) {
  63. options = {};
  64. sprintf_args = [];
  65. } else if (_.isError(argv[0])) {
  66. options = { cause: argv[0] };
  67. sprintf_args = argv.slice(1);
  68. } else if (typeof argv[0] === 'object') {
  69. options = {};
  70. // eslint-disable-next-line guard-for-in
  71. for (k in argv[0]) {
  72. options[k] = argv[0][k];
  73. }
  74. sprintf_args = argv.slice(1);
  75. } else {
  76. assert.string(
  77. argv[0],
  78. 'first argument to VError, PError, SError, or WError ' +
  79. 'constructor must be a string, object, or Error'
  80. );
  81. options = {};
  82. sprintf_args = argv;
  83. }
  84. // Preserve options
  85. if (args.skipPrintf) {
  86. options.skipPrintf = args.skipPrintf;
  87. }
  88. if (args.strict) {
  89. options.strict = args.strict;
  90. }
  91. /*
  92. * Now construct the error's message.
  93. *
  94. * extsprintf (which we invoke here with our caller's arguments in order
  95. * to construct this Error's message) is strict in its interpretation of
  96. * values to be processed by the "%s" specifier. The value passed to
  97. * extsprintf must actually be a string or something convertible to a
  98. * String using .toString(). Passing other values (notably "null" and
  99. * "undefined") is considered a programmer error. The assumption is
  100. * that if you actually want to print the string "null" or "undefined",
  101. * then that's easy to do that when you're calling extsprintf; on the
  102. * other hand, if you did NOT want that (i.e., there's actually a bug
  103. * where the program assumes some variable is non-null and tries to
  104. * print it, which might happen when constructing a packet or file in
  105. * some specific format), then it's better to stop immediately than
  106. * produce bogus output.
  107. *
  108. * However, sometimes the bug is only in the code calling VError, and a
  109. * programmer might prefer to have the error message contain "null" or
  110. * "undefined" rather than have the bug in the error path crash the
  111. * program (making the first bug harder to identify). For that reason,
  112. * by default VError converts "null" or "undefined" arguments to their
  113. * string representations and passes those to extsprintf. Programmers
  114. * desiring the strict behavior can use the SError class or pass the
  115. * "strict" option to the VError constructor.
  116. */
  117. assert.object(options);
  118. if (!options.skipPrintf && !options.strict && !args.strict) {
  119. sprintf_args = sprintf_args.map(function(a) {
  120. return a === null ? 'null' : a === undefined ? 'undefined' : a;
  121. });
  122. }
  123. if (sprintf_args.length === 0) {
  124. shortmessage = '';
  125. } else if (
  126. options.skipPrintf ||
  127. (sprintf_args.length === 1 && typeof sprintf_args[0] === 'string')
  128. ) {
  129. assert.equal(
  130. sprintf_args.length,
  131. 1,
  132. 'only one argument is allowed with options.skipPrintf'
  133. );
  134. shortmessage = sprintf_args[0];
  135. } else {
  136. shortmessage = sprintf.apply(null, sprintf_args);
  137. }
  138. return {
  139. options: options,
  140. shortmessage: shortmessage
  141. };
  142. }
  143. /**
  144. * @public
  145. * @typedef {Object} VErrorOptions Options
  146. * @param {String} name - Name of the error.
  147. * @param {Error} [cause] - Indicates that the new error was caused by `cause`.
  148. * @param {Boolean} [strict=false] - If true, then `null` and `undefined` values
  149. * in `sprintf_args` are passed through to `sprintf()`
  150. * @param {Function} [constructorOpt] -If specified, then the stack trace for
  151. * this error ends at function `constructorOpt`.
  152. * @param {Object} [info]- Specifies arbitrary informational properties.
  153. * @param {Boolean} [skipPrintf=false] - If true, then `sprintf()` is not called
  154. */
  155. /**
  156. *
  157. * About Constructor:
  158. * All of these forms construct a new VError that behaves just like the built-in
  159. * JavaScript `Error` class, with some additional methods described below.
  160. *
  161. * About Properties:
  162. * For all of these classes except `PError`, the printf-style arguments passed to
  163. * the constructor are processed with `sprintf()` to form a message.
  164. * For `WError`, this becomes the complete `message` property. For `SError` and
  165. * `VError`, this message is prepended to the message of the cause, if any
  166. * (with a suitable separator), and the result becomes the `message` property.
  167. *
  168. * The `stack` property is managed entirely by the underlying JavaScript
  169. * implementation. It's generally implemented using a getter function because
  170. * constructing the human-readable stack trace is somewhat expensive.
  171. *
  172. * @public
  173. * @class VError
  174. * @param {...String|VErrorOptions|Error} [arg] - sprintf args, options or cause
  175. * @param {...String} [args] - sprintf args
  176. * @property {String} name - Programmatically-usable name of the error.
  177. * @property {String} message - Human-readable summary of the failure.
  178. * Programmatically-accessible details are provided through `VError.info(err)`
  179. * class method.
  180. * @property {String} stack - Human-readable stack trace where the Error was
  181. * constructed.
  182. * @example
  183. * // This is the most general form. You can specify any supported options
  184. * // including "cause" and "info") this way.</caption>
  185. * new VError(options, sprintf_args...)
  186. * @example
  187. * // This is a useful shorthand when the only option you need is "cause".
  188. * new VError(cause, sprintf_args...)
  189. * @example
  190. * // This is a useful shorthand when you don't need any options at all.
  191. * new VError(sprintf_args...)
  192. */
  193. function VError(...args) {
  194. let obj, ctor, message, k;
  195. /*
  196. * This is a regrettable pattern, but JavaScript's built-in Error class
  197. * is defined to work this way, so we allow the constructor to be called
  198. * without "new".
  199. */
  200. if (!(this instanceof VError)) {
  201. obj = Object.create(VError.prototype);
  202. VError.apply(obj, arguments);
  203. return obj;
  204. }
  205. /*
  206. * For convenience and backwards compatibility, we support several
  207. * different calling forms. Normalize them here.
  208. */
  209. const parsed = parseConstructorArguments({
  210. argv: args,
  211. strict: false
  212. });
  213. /*
  214. * If we've been given a name, apply it now.
  215. */
  216. if (parsed.options.name) {
  217. assert.string(parsed.options.name, 'error\'s "name" must be a string');
  218. this.name = parsed.options.name;
  219. }
  220. /*
  221. * For debugging, we keep track of the original short message (attached
  222. * this Error particularly) separately from the complete message (which
  223. * includes the messages of our cause chain).
  224. */
  225. this.jse_shortmsg = parsed.shortmessage;
  226. message = parsed.shortmessage;
  227. /*
  228. * If we've been given a cause, record a reference to it and update our
  229. * message appropriately.
  230. */
  231. const cause = parsed.options.cause;
  232. if (cause) {
  233. VError._assertError(cause, '"cause" must be an Error');
  234. this.jse_cause = cause;
  235. if (!parsed.options.skipCauseMessage) {
  236. message += ': ' + cause.message;
  237. }
  238. }
  239. /*
  240. * If we've been given an object with properties, shallow-copy that
  241. * here. We don't want to use a deep copy in case there are non-plain
  242. * objects here, but we don't want to use the original object in case
  243. * the caller modifies it later.
  244. */
  245. this.jse_info = {};
  246. if (parsed.options.info) {
  247. // eslint-disable-next-line guard-for-in
  248. for (k in parsed.options.info) {
  249. this.jse_info[k] = parsed.options.info[k];
  250. }
  251. }
  252. this.message = message;
  253. Error.call(this, message);
  254. if (Error.captureStackTrace) {
  255. ctor = parsed.options.constructorOpt || this.constructor;
  256. Error.captureStackTrace(this, ctor);
  257. }
  258. return this;
  259. }
  260. util.inherits(VError, Error);
  261. VError.prototype.name = 'VError';
  262. /**
  263. * Appends any keys/fields to the existing jse_info. this can stomp over any
  264. * existing fields.
  265. * @public
  266. * @memberof VError.prototype
  267. * @param {Object} obj source obj to assign fields from
  268. * @return {Object} new info object
  269. */
  270. VError.prototype.assignInfo = function ve_assignInfo(obj) {
  271. assert.optionalObject(obj, 'obj');
  272. return Object.assign(this.jse_info, obj);
  273. };
  274. /**
  275. * Instance level convenience method vs using the static methods on VError.
  276. * @public
  277. * @memberof VError.prototype
  278. * @return {Object} info object
  279. */
  280. VError.prototype.info = function ve_info() {
  281. return VError.info(this);
  282. };
  283. /**
  284. * A string representing the VError.
  285. * @public
  286. * @memberof VError.prototype
  287. * @return {String} string representation
  288. */
  289. VError.prototype.toString = function ve_toString() {
  290. let str =
  291. (this.hasOwnProperty('name') && this.name) ||
  292. this.constructor.name ||
  293. this.constructor.prototype.name;
  294. if (this.message) {
  295. str += ': ' + this.message;
  296. }
  297. return str;
  298. };
  299. /**
  300. * This method is provided for compatibility. New callers should use
  301. * VError.cause() instead. That method also uses the saner `null` return value
  302. * when there is no cause.
  303. * @public
  304. * @memberof VError.prototype
  305. * @return {undefined|Error} Error cause if any
  306. */
  307. VError.prototype.cause = function ve_cause() {
  308. const cause = VError.cause(this);
  309. return cause === null ? undefined : cause;
  310. };
  311. /*
  312. * Static methods
  313. *
  314. * These class-level methods are provided so that callers can use them on
  315. * instances of Errors that are not VErrors. New interfaces should be provided
  316. * only using static methods to eliminate the class of programming mistake where
  317. * people fail to check whether the Error object has the corresponding methods.
  318. */
  319. /**
  320. * @private
  321. * @static
  322. * @memberof VError
  323. * @param {Error} err - error to assert
  324. * @param {String} [msg] - optional message
  325. * @returns {undefined} no return value
  326. * @throws AssertationError - when input is not an error
  327. */
  328. VError._assertError = function _assertError(err, msg) {
  329. assert.optionalString(msg, 'msg');
  330. const _msg = (msg || 'err must be an Error') + ` but got ${String(err)}`;
  331. assert.ok(_.isError(err), _msg);
  332. };
  333. /**
  334. * Checks if an error is a VError or VError sub-class.
  335. *
  336. * @public
  337. * @static
  338. * @memberof VError
  339. * @param {Error} err - error
  340. * @return {Boolean} is a VError or VError sub-class
  341. */
  342. VError.isVError = function assignInfo(err) {
  343. // We are checking on internals here instead of using
  344. // `err instanceof VError` to being compatible with the original VError lib.
  345. return err && err.hasOwnProperty('jse_info');
  346. };
  347. /**
  348. * Appends any keys/fields to the `jse_info`. This can stomp over any existing
  349. * fields.
  350. *
  351. * Note: This method is static because in this way we don't need to check on
  352. * VError versions to be sure `assignInfo` method is supported.
  353. *
  354. * @public
  355. * @static
  356. * @memberof VError
  357. * @param {Error} err - error
  358. * @param {Object} obj - source obj to assign fields from
  359. * @return {Object} new info object
  360. */
  361. VError.assignInfo = function assignInfo(err, obj) {
  362. VError._assertError(err);
  363. assert.optionalObject(obj, 'obj');
  364. if (!VError.isVError(err)) {
  365. throw new TypeError('err must be an instance of VError');
  366. }
  367. return Object.assign(err.jse_info, obj);
  368. };
  369. /**
  370. * Returns the next Error in the cause chain for `err`, or `null` if there is no
  371. * next error. See the `cause` argument to the constructor.
  372. * Errors can have arbitrarily long cause chains. You can walk the `cause`
  373. * chain by invoking `VError.cause(err)` on each subsequent return value.
  374. * If `err` is not a `VError`, the cause is `null`.
  375. *
  376. * @public
  377. * @static
  378. * @memberof VError
  379. * @param {VError} err - error
  380. * @return {undefined|Error} Error cause if any
  381. */
  382. VError.cause = function cause(err) {
  383. VError._assertError(err);
  384. return _.isError(err.jse_cause) ? err.jse_cause : null;
  385. };
  386. /**
  387. * Returns an object with all of the extra error information that's been
  388. * associated with this Error and all of its causes. These are the properties
  389. * passed in using the `info` option to the constructor. Properties not
  390. * specified in the constructor for this Error are implicitly inherited from
  391. * this error's cause.
  392. *
  393. * These properties are intended to provide programmatically-accessible metadata
  394. * about the error. For an error that indicates a failure to resolve a DNS
  395. * name, informational properties might include the DNS name to be resolved, or
  396. * even the list of resolvers used to resolve it. The values of these
  397. * properties should generally be plain objects (i.e., consisting only of null,
  398. * undefined, numbers, booleans, strings, and objects and arrays containing only
  399. * other plain objects).
  400. *
  401. * @public
  402. * @static
  403. * @memberof VError
  404. * @param {VError} err - error
  405. * @return {Object} info object
  406. */
  407. VError.info = function info(err) {
  408. let rv, k;
  409. VError._assertError(err);
  410. const cause = VError.cause(err);
  411. if (cause !== null) {
  412. rv = VError.info(cause);
  413. } else {
  414. rv = {};
  415. }
  416. if (typeof err.jse_info === 'object' && err.jse_info !== null) {
  417. // eslint-disable-next-line guard-for-in
  418. for (k in err.jse_info) {
  419. rv[k] = err.jse_info[k];
  420. }
  421. }
  422. return rv;
  423. };
  424. /**
  425. * The `findCauseByName()` function traverses the cause chain for `err`, looking
  426. * for an error whose `name` property matches the passed in `name` value. If no
  427. * match is found, `null` is returned.
  428. *
  429. * If all you want is to know _whether_ there's a cause (and you don't care what
  430. * it is), you can use `VError.hasCauseWithName(err, name)`.
  431. *
  432. * If a vanilla error or a non-VError error is passed in, then there is no cause
  433. * chain to traverse. In this scenario, the function will check the `name`
  434. * property of only `err`.
  435. *
  436. * @public
  437. * @static
  438. * @memberof VError
  439. * @param {VError} err - error
  440. * @param {String} name - name of cause Error
  441. * @return {null|Error} cause if any
  442. */
  443. VError.findCauseByName = function findCauseByName(err, name) {
  444. let cause;
  445. VError._assertError(err);
  446. assert.string(name, 'name');
  447. assert.ok(name.length > 0, 'name cannot be empty');
  448. for (cause = err; cause !== null; cause = VError.cause(cause)) {
  449. assert.ok(_.isError(cause));
  450. if (cause.name === name) {
  451. return cause;
  452. }
  453. }
  454. return null;
  455. };
  456. /**
  457. * Returns true if and only if `VError.findCauseByName(err, name)` would return
  458. * a non-null value. This essentially determines whether `err` has any cause in
  459. * its cause chain that has name `name`.
  460. *
  461. * @public
  462. * @static
  463. * @memberof VError
  464. * @param {VError} err - error
  465. * @param {String} name - name of cause Error
  466. * @return {Boolean} has cause
  467. */
  468. VError.hasCauseWithName = function hasCauseWithName(err, name) {
  469. return VError.findCauseByName(err, name) !== null;
  470. };
  471. /**
  472. * Returns a string containing the full stack trace, with all nested errors
  473. * recursively reported as `'caused by:' + err.stack`.
  474. *
  475. * @public
  476. * @static
  477. * @memberof VError
  478. * @param {VError} err - error
  479. * @return {String} full stack trace
  480. */
  481. VError.fullStack = function fullStack(err) {
  482. VError._assertError(err);
  483. const cause = VError.cause(err);
  484. if (cause) {
  485. return err.stack + '\ncaused by: ' + VError.fullStack(cause);
  486. }
  487. return err.stack;
  488. };
  489. /**
  490. * Given an array of Error objects (possibly empty), return a single error
  491. * representing the whole collection of errors. If the list has:
  492. *
  493. * * 0 elements, returns `null`
  494. * * 1 element, returns the sole error
  495. * * more than 1 element, returns a MultiError referencing the whole list
  496. *
  497. * This is useful for cases where an operation may produce any number of errors,
  498. * and you ultimately want to implement the usual `callback(err)` pattern.
  499. * You can accumulate the errors in an array and then invoke
  500. * `callback(VError.errorFromList(errors))` when the operation is complete.
  501. *
  502. * @public
  503. * @static
  504. * @memberof VError
  505. * @param {Array<Error>} errors - errors
  506. * @return {null|Error|MultiError} single or multi error if any
  507. */
  508. VError.errorFromList = function errorFromList(errors) {
  509. assert.arrayOfObject(errors, 'errors');
  510. if (errors.length === 0) {
  511. return null;
  512. }
  513. errors.forEach(function(e) {
  514. assert.ok(_.isError(e), 'all errors must be an Error');
  515. });
  516. if (errors.length === 1) {
  517. return errors[0];
  518. }
  519. return new MultiError(errors);
  520. };
  521. /**
  522. * Convenience function for iterating an error that may itself be a MultiError.
  523. *
  524. * In all cases, `err` must be an Error. If `err` is a MultiError, then `func`
  525. * is invoked as `func(errorN)` for each of the underlying errors of the
  526. * MultiError.
  527. * If `err` is any other kind of error, `func` is invoked once as `func(err)`.
  528. * In all cases, `func` is invoked synchronously.
  529. *
  530. * This is useful for cases where an operation may produce any number of
  531. * warnings that may be encapsulated with a MultiError -- but may not be.
  532. *
  533. * This function does not iterate an error's cause chain.
  534. *
  535. * @public
  536. * @static
  537. * @memberof VError
  538. * @param {Error} err - error
  539. * @param {Function} func - iterator
  540. * @return {undefined} no return value
  541. */
  542. VError.errorForEach = function errorForEach(err, func) {
  543. VError._assertError(err);
  544. assert.func(func, 'func');
  545. if (err.name === 'MultiError') {
  546. err.errors().forEach(function iterError(e) {
  547. func(e);
  548. });
  549. } else {
  550. func(err);
  551. }
  552. };
  553. /**
  554. * PError is like VError, but the message is not run through printf-style
  555. * templating.
  556. *
  557. * @public
  558. * @class PError
  559. * @extends VError
  560. * @param {...String|VErrorOptions|Error} [arg] - sprintf args, options or cause
  561. * @param {...String} [args] - sprintf args
  562. */
  563. function PError(...args) {
  564. let obj;
  565. if (!(this instanceof PError)) {
  566. obj = Object.create(PError.prototype);
  567. PError.apply(obj, args);
  568. return obj;
  569. }
  570. const parsed = parseConstructorArguments({
  571. argv: args,
  572. strict: false,
  573. skipPrintf: true
  574. });
  575. VError.call(this, parsed.options, parsed.shortmessage);
  576. return this;
  577. }
  578. util.inherits(PError, VError);
  579. PError.prototype.name = 'PError';
  580. /**
  581. * SError is like VError, but stricter about types. You cannot pass "null" or
  582. * "undefined" as string arguments to the formatter.
  583. *
  584. * @public
  585. * @class SError
  586. * @extends VError
  587. * @param {...String|VErrorOptions|Error} [arg] - sprintf args, options or cause
  588. * @param {...String} [args] - sprintf args
  589. */
  590. function SError(...args) {
  591. let obj;
  592. if (!(this instanceof SError)) {
  593. obj = Object.create(SError.prototype);
  594. SError.apply(obj, arguments);
  595. return obj;
  596. }
  597. const parsed = parseConstructorArguments({
  598. argv: args,
  599. strict: true
  600. });
  601. const options = parsed.options;
  602. options.skipPrintf = false;
  603. VError.call(this, options, '%s', parsed.shortmessage);
  604. return this;
  605. }
  606. /*
  607. * We don't bother setting SError.prototype.name because once constructed,
  608. * SErrors are just like VErrors.
  609. */
  610. util.inherits(SError, VError);
  611. /**
  612. * Represents a collection of errors for the purpose of consumers that generally
  613. * only deal with one error. Callers can extract the individual errors
  614. * contained in this object, but may also just treat it as a normal single
  615. * error, in which case a summary message will be printed.
  616. *
  617. * @public
  618. * @class MultiError
  619. * @extends VError
  620. * @param {Array<Error>} errors - errors
  621. * @example
  622. * // `error_list` is an array of at least one `Error` object.
  623. * new MultiError(error_list)
  624. *
  625. * // The cause of the MultiError is the first error provided. None of the
  626. * // other `VError` options are supported. The `message` for a MultiError
  627. * // consists the `message` from the first error, prepended with a message
  628. * // indicating that there were other errors.
  629. *
  630. * //For example:
  631. * err = new MultiError([
  632. * new Error('failed to resolve DNS name "abc.example.com"'),
  633. * new Error('failed to resolve DNS name "def.example.com"'),
  634. * ]);
  635. * console.error(err.message);
  636. *
  637. * // outputs:
  638. * // first of 2 errors: failed to resolve DNS name "abc.example.com"
  639. */
  640. function MultiError(errors) {
  641. assert.array(errors, 'list of errors');
  642. assert.ok(errors.length > 0, 'must be at least one error');
  643. this.ase_errors = errors;
  644. VError.call(
  645. this,
  646. {
  647. cause: errors[0]
  648. },
  649. 'first of %d error%s',
  650. errors.length,
  651. errors.length === 1 ? '' : 's'
  652. );
  653. }
  654. util.inherits(MultiError, VError);
  655. MultiError.prototype.name = 'MultiError';
  656. /**
  657. * Returns an array of the errors used to construct this MultiError.
  658. *
  659. * @public
  660. * @memberof MultiError.prototype
  661. * @returns {Array<Error>} errors
  662. */
  663. MultiError.prototype.errors = function me_errors() {
  664. return this.ase_errors.slice(0);
  665. };
  666. /**
  667. * WError for wrapping errors while hiding the lower-level messages from the
  668. * top-level error. This is useful for API endpoints where you don't want to
  669. * expose internal error messages, but you still want to preserve the error
  670. * chain for logging and debugging
  671. *
  672. * @public
  673. * @class WError
  674. * @extends VError
  675. * @param {...String|VErrorOptions|Error} [arg] - sprintf args, options or cause
  676. * @param {...String} [args] - sprintf args
  677. */
  678. function WError(...args) {
  679. let obj;
  680. if (!(this instanceof WError)) {
  681. obj = Object.create(WError.prototype);
  682. WError.apply(obj, args);
  683. return obj;
  684. }
  685. const parsed = parseConstructorArguments({
  686. argv: args,
  687. strict: false
  688. });
  689. const options = parsed.options;
  690. options.skipCauseMessage = true;
  691. options.skipPrintf = false;
  692. VError.call(this, options, '%s', parsed.shortmessage);
  693. return this;
  694. }
  695. util.inherits(WError, VError);
  696. WError.prototype.name = 'WError';
  697. /**
  698. * A string representing the WError.
  699. * @public
  700. * @memberof WError.prototype
  701. * @return {String} string representation
  702. */
  703. WError.prototype.toString = function we_toString() {
  704. let str =
  705. (this.hasOwnProperty('name') && this.name) ||
  706. this.constructor.name ||
  707. this.constructor.prototype.name;
  708. if (this.message) {
  709. str += ': ' + this.message;
  710. }
  711. if (this.jse_cause && this.jse_cause.message) {
  712. str += '; caused by ' + this.jse_cause.toString();
  713. }
  714. return str;
  715. };
  716. /**
  717. * For purely historical reasons, WError's cause() function allows you to set
  718. * the cause.
  719. * @public
  720. * @memberof WError.prototype
  721. * @param {Error} c - cause
  722. * @return {undefined|Error} Error cause
  723. */
  724. WError.prototype.cause = function we_cause(c) {
  725. if (_.isError(c)) {
  726. this.jse_cause = c;
  727. }
  728. return this.jse_cause;
  729. };