From d57a2421fc24c0e56d9c7190b5fcfb78f095e988 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Mon, 19 Feb 2018 01:49:30 +0100 Subject: [PATCH] errors: implement new error handling This implements a function based system. Instead of passing in the error code as first argument, the error code itself is a error class. It already contains the correct error type, so while adding a new error no one has to think about the error type anymore. In case a single error code has more than one error type, the error class has properties for the non default error types. Those can be used as fallback. This prevents typos, makes the implementation easier and it is less verbose when writing the code for a new error. The implementation itself does not interfere with the old implementation. So the old and the new system can co-exist and it is possible to slowly migrate the old ones to the new system. Backport-PR-URL: https://github.com/nodejs/node/pull/19244 PR-URL: https://github.com/nodejs/node/pull/18857 Reviewed-By: Anna Henningsen Reviewed-By: Gus Caplan Reviewed-By: James M Snell Reviewed-By: Joyee Cheung --- lib/internal/errors.js | 56 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 9cc731e99fb3af..50d1cd3fb53b2c 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -12,6 +12,7 @@ const kCode = Symbol('code'); const messages = new Map(); +const codes = {}; var green = ''; var red = ''; @@ -194,6 +195,54 @@ function createErrDiff(actual, expected, operator) { return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`; } +function makeNodeErrorWithCode(Base, key) { + return class NodeError extends Base { + constructor(...args) { + super(message(key, args)); + } + + get name() { + return `${super.name} [${key}]`; + } + + set name(value) { + defineProperty(this, 'name', { + configurable: true, + enumerable: true, + value, + writable: true + }); + } + + get code() { + return key; + } + + set code(value) { + defineProperty(this, 'code', { + configurable: true, + enumerable: true, + value, + writable: true + }); + } + }; +} + +// Utility function for registering the error codes. Only used here. Exported +// *only* to allow for testing. +function E(sym, val, def, ...otherClasses) { + messages.set(sym, val); + if (def === undefined) return; + def = makeNodeErrorWithCode(def, sym); + if (otherClasses.length !== 0) { + otherClasses.forEach((clazz) => { + def[clazz.name] = makeNodeErrorWithCode(clazz, sym); + }); + } + codes[sym] = def; +} + class AssertionError extends Error { constructor(options) { if (typeof options !== 'object' || options === null) { @@ -296,12 +345,6 @@ function message(key, args) { return String(fmt.apply(null, args)); } -// Utility function for registering the error codes. Only used here. Exported -// *only* to allow for testing. -function E(sym, val) { - messages.set(sym, typeof val === 'function' ? val : String(val)); -} - /** * This used to be util._errnoException(). * @@ -412,6 +455,7 @@ module.exports = exports = { RangeError: makeNodeError(RangeError), URIError: makeNodeError(URIError), AssertionError, + codes, E // This is exported only to facilitate testing. };