Release 4.0.0
Major features
Plugins
Features can now be extended using plugins.
import modernErrors from 'modern-errors'
import modernErrorsBugs from 'modern-errors-bugs'
import modernErrorsCli from 'modern-errors-cli'
export const AnyError = modernErrors([modernErrorsBugs, modernErrorsCli])CLI plugin
The modern-errors-cli plugin handles CLI errors.
Process errors
The modern-errors-process plugin handles process errors.
Clean stack traces
The modern-errors-stack plugin automatically cleans up stack traces.
HTTP responses
The modern-errors-http plugin converts errors to plain objects to use in an HTTP response.
Error logging (Winston)
The modern-errors-winston plugin logs errors with Winston.
Subclasses
Error subclasses can now be created using ErrorClass.subclass() to share custom logic and options between classes.
const SharedError = AnyError.subclass('SharedError', {
custom: class extends AnyError {
// ...
},
})
export const InputError = SharedError.subclass('InputError')
export const AuthError = SharedError.subclass('AuthError')Improved options
Options can now be applied to any error.
export const AnyError = modernErrors(plugins, options)Or to any error of a specific class.
export const InputError = AnyError.subclass('InputError', options)Or to multiple classes.
export const SharedError = AnyError.subclass('SharedError', options)
export const InputError = SharedError.subclass('InputError')
export const AuthError = SharedError.subclass('AuthError')Or to a specific error.
throw new InputError('...', options)Or to a specific plugin method call, passing only that plugin's options.
AnyError[methodName](...args, options[pluginName])error[methodName](...args, options[pluginName])Aggregate errors
The errors option can now be used to aggregate multiple errors into one, similarly to new AggregateError(errors).
Breaking changes
Creating error classes
The main function now returns the base error class AnyError.
AnyError.subclass(name) must be used to create each error class. The first one must now be named UnknownError.
Before:
export const {
// Custom error classes
InputError,
AuthError,
DatabaseError,
// Error handler
errorHandler,
} = modernErrors(['InputError', 'AuthError', 'DatabaseError'])After:
// Base error class
export const AnyError = modernErrors()
export const UnknownError = AnyError.subclass('UnknownError')
export const InputError = AnyError.subclass('InputError')
export const AuthError = AnyError.subclass('AuthError')
export const DatabaseError = AnyError.subclass('DatabaseError')Error handler
errorHandler() has been renamed to AnyError.normalize().
Before:
const { errorHandler } = modernErrors(errorNames)
const normalizedError = errorHandler(error)After:
const AnyError = modernErrors()
const normalizedError = AnyError.normalize(error)Custom classes
Error classes can now be fully customized using the custom option: constructors, methods, etc. This replaces the previous onCreate option.
Before:
modernErrors({
onCreate(error, options) {
const { filePath } = options
if (typeof filePath !== 'string') {
throw new TypeError('filePath must be a string.')
}
error.filePath = filePath
},
})After:
export const InputError = AnyError.subclass('InputError', {
custom: class extends AnyError {
constructor(message, options = {}) {
super(message, options)
const { filePath } = options
if (typeof filePath !== 'string') {
throw new TypeError('filePath must be a string.')
}
this.filePath = filePath
}
},
})Error properties
Error properties must now be set using props.{propName} instead of {propName}.
Before:
throw new InputError('...', { filePath: '/path' })After:
throw new InputError('...', { props: { filePath: '/path' } })Bug reports
The bugsUrl option has been renamed to bugs. It cannot be a function anymore. It also requires adding the modern-errors-bugs plugin.
A few bug fixes related to using the bugs option twice have also been fixed.
Before:
throw new InputError('...', {
bugsUrl: 'https://github.com/my-name/my-project/issues',
})After:
throw new InputError('...', {
bugs: 'https://github.com/my-name/my-project/issues',
})Serialization/parsing
parse() has been renamed to AnyError.parse(). AnyError.parse() and error.toJSON() also require adding the modern-errors-serialize plugin.
Serialization and parsing now recurse deeply over objects and arrays.
Before:
const { parse } = modernErrors(errorNames)
const errorObject = JSON.parse(errorString)
const error = parse(errorObject)After:
import modernErrorsSerialize from 'modern-errors-serialize'
const AnyError = modernErrors([modernErrorsSerialize])
const errorObject = JSON.parse(errorString)
const error = AnyError.parse(errorObject)Error wrapping
To wrap an error without changing its class, AnyError must now be used instead of Error. When wrapping an error, its cause and bugs are now merged right away, instead of when AnyError.normalize() is called.
Before:
throw new Error('Could not read the file.', { cause })After:
throw new AnyError('Could not read the file.', { cause })Checking error classes
We now recommend using instanceof instead of error.name to check error classes.
Before:
if (error.name === 'InputError') {
// ...
}After:
if (error instanceof InputError) {
// ...
}AnyError can now be used to check for any errors from a specific library.
if (error instanceof AnyError) {
// ...
}TypeScript types
TypeScript support has been greatly improved and is now fully tested. Most types have changed: if you were using them, please check the new documentation here.
Exporting error classes
Error classes should now be exported to be re-used across modules.
License
Switch to MIT license.