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.