### Install Project Dependencies Source: https://github.com/ehmicky/modern-errors/blob/main/CONTRIBUTING.md Run this command to install all necessary project dependencies. ```bash npm install ``` -------------------------------- ### Run Project Tests Source: https://github.com/ehmicky/modern-errors/blob/main/CONTRIBUTING.md Execute this command to ensure the project setup is correct and all tests pass. ```bash npm test ``` -------------------------------- ### Install Modern Errors Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Install the `modern-errors` package using npm. If using plugins, install them separately. ```bash npm install modern-errors ``` -------------------------------- ### Install Modern Errors Plugins Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Install specific plugins for `modern-errors` by prefixing the plugin name with `modern-errors-`. ```bash npm install modern-errors-{pluginName} ``` -------------------------------- ### Plugin Template Structure Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md This is a template for creating a new plugin. It outlines the optional members a plugin can export, including name, properties, instanceMethods, staticMethods, getOptions, and isOptions. Use this as a starting point for your own plugins. ```javascript export default { // Name used to configure the plugin name: 'example', // Set error properties properties: (info) => ({}), // Add instance methods like `ErrorClass.exampleMethod(error, ...args)` or // `error.exampleMethod(...args)` instanceMethods: { exampleMethod: (info, ...args) => { // ... }, }, // Add static methods like `ErrorClass.staticMethod(...args)` staticMethods: { staticMethod: (info, ...args) => { // ... }, }, // Validate and normalize options getOptions: (options, full) => options, // Determine if a value is plugin's options isOptions: (options) => typeof options === 'boolean', } ``` -------------------------------- ### Validate Plugin Options (Boolean) Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Implement `getOptions` to validate and normalize plugin options. This example ensures options are strictly boolean, throwing an error for invalid types. It's used when options might be partial. ```javascript export default { name: 'example', getOptions: (options = true) => { if (typeof options !== 'boolean') { throw new Error('It must be true or false.') } return options }, } ``` -------------------------------- ### Setting Custom Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Shows how to use the 'properties' hook in a plugin to add custom properties to error objects. The example sets an 'example' property to true. Properties prefixed with '_' become non-enumerable. ```javascript export default { name: 'example', // Sets `error.example: true` properties: () => ({ example: true }), } ``` -------------------------------- ### Determine if Argument is Options Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Implement `isOptions` to identify if the last argument passed to a plugin method is intended as options. This example checks if the option is a boolean, allowing `getOptions` to perform further validation. ```javascript // `ErrorClass.exampleMethod(error, 'one', true)` results in: // options: true // args: ['one'] // `ErrorClass.exampleMethod(error, 'one', 'two')` results in: // options: undefined // args: ['one', 'two'] export default { name: 'example', isOptions: (options) => typeof options === 'boolean', getOptions: (options) => options, instanceMethod: { exampleMethod: ({ options }, ...args) => { // ... }, }, } ``` -------------------------------- ### Type Custom Error Options Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Define custom options for an error subclass and ensure they are correctly typed. This example shows how to add a `suffix` option and demonstrates a type error when an incorrect type is provided. ```typescript import type { InstanceOptions } from 'modern-errors' interface InputErrorOptions { suffix?: string } export const InputError = BaseError.subclass('InputError', { custom: class extends BaseError { constructor( message: string, options?: InstanceOptions & InputErrorOptions, ) { message += options?.suffix ?? '' super(message, options) } }, }) // Type error: `suffix` must be a string const error = new InputError('Wrong user name', { suffix: true }) ``` -------------------------------- ### Plugin with Options via getOptions Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Use the `getOptions` method to pass and validate plugin options at multiple stages. This pattern ensures options are automatically typed and consistent across plugins. ```javascript export default { name: 'example', getOptions: (options) => options, instanceMethods: { exampleMethod: (info) => { console.log(info.options.exampleOption) }, }, } ``` -------------------------------- ### Define Plugin Options Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Configure plugin-specific options by defining a `getOptions` function. This function receives user-provided options and returns them, allowing for validation and transformation. ```javascript export default { name: 'example', getOptions: (options) => options, // `new ErrorClass('message', { example: value })` sets `error.example: value` properties: ({ options }) => ({ example: options }), } ``` -------------------------------- ### Avoid Options via Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Configuration options should not be set directly on error properties. Use the `getOptions` pattern for consistent and validated option management. ```javascript export default { name: 'example', instanceMethods: { exampleMethod: (info) => { console.log(info.error.exampleOption) }, }, } ``` -------------------------------- ### Configure Plugin Options Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Define plugin options, such as the bugs URL and initial props, to be applied to errors. ```javascript const options = { // `modern-errors-bugs` options bugs: 'https://github.com/my-name/my-project/issues', // `props` can be configured and modified like plugin options props: { userId: 5 }, } ``` -------------------------------- ### getOptions Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Normalizes and returns plugin options. It's crucial for using plugin options and should throw an error for invalid options, prepending the message with 'Invalid "plugin.name" options:'. ```APIDOC ## getOptions ### Description Normalize and return the plugin's `options`. Required to use plugin `options`. If `options` are invalid, an `Error` should be thrown. The error message is automatically prepended with `Invalid "plugin.name" options:`. Regular `Error`s should be thrown, as opposed to using `modern-errors` itself. The plugin's `options`'s type can be anything. ### Method Signature `(options, full) => options` ### Parameters #### Arguments - **options** (any) - The plugin options to normalize. - **full** (boolean) - Indicates if the options might still be partial. `false` in the first stage of option processing, `true` in others. When `false`, validation of required properties or interdependent properties should be skipped. ### Example 1 (Simple boolean option) ```javascript export default { name: 'example', getOptions: (options = true) => { if (typeof options !== 'boolean') { throw new Error('It must be true or false.') } return options }, } ``` ### Example 2 (Object option with validation) ```javascript export default { name: 'example', getOptions: (options, full) => { if (typeof options !== 'object' || options === null) { throw new Error('It must be a plain object.') } if (full && options.apiKey === undefined) { throw new Error('"apiKey" is required.') } return options }, } ``` ``` -------------------------------- ### Plugin Structure Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md A plugin is a plain object with a default export. The 'name' property is mandatory and used for configuration. Other optional properties include 'properties', 'instanceMethods', 'staticMethods', 'getOptions', and 'isOptions'. ```APIDOC ## Plugin Structure Plugins are plain objects with a [default export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export). All members are optional except for [`name`](#name). ```js export default { // Name used to configure the plugin name: 'example', // Set error properties properties: (info) => ({}), // Add instance methods like `ErrorClass.exampleMethod(error, ...args)` or // `error.exampleMethod(...args)` instanceMethods: { exampleMethod: (info, ...args) => { // ... }, }, // Add static methods like `ErrorClass.staticMethod(...args)` staticMethods: { staticMethod: (info, ...args) => { // ... }, }, // Validate and normalize options getOptions: (options, full) => options, // Determine if a value is plugin's options isOptions: (options) => typeof options === 'boolean', } ``` ``` -------------------------------- ### Validate Plugin Options (Object with API Key) Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Implement `getOptions` to validate object-based plugin options, including a required `apiKey` when `full` is true. This handles options passed at various stages of error class or instance creation. ```javascript export default { name: 'example', getOptions: (options, full) => { if (typeof options !== 'object' || options === null) { throw new Error('It must be a plain object.') } if (full && options.apiKey === undefined) { throw new Error('"apiKey" is required.') } return options }, } ``` -------------------------------- ### Avoid Options via Error Method Arguments Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Do not pass configuration options as arguments to error methods. This approach bypasses the benefits of centralized option handling provided by `modern-errors`. ```javascript export default { name: 'example', instanceMethods: { exampleMethod: (exampleOption) => { console.log(exampleOption) }, }, } ``` -------------------------------- ### Apply Options to Specific Error Instance Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Configure plugin options when instantiating a specific error class. ```javascript throw new InputError('...', options) ``` -------------------------------- ### Avoid Options via Function Returning Plugin Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Do not use a function that returns the plugin to pass options. This pattern is less maintainable and does not integrate as seamlessly with `modern-errors`' option handling. ```javascript export default (exampleOption) => ({ name: 'example', instanceMethods: { exampleMethod: () => { console.log(exampleOption) }, }, }) ``` -------------------------------- ### Avoid Options via Top-Level Objects Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Refrain from using top-level objects for plugin configuration. This pattern lacks the structured validation and typing benefits of the `getOptions` method. ```javascript export const pluginOptions = {} export default { name: 'example', instanceMethods: { exampleMethod: () => { console.log(pluginOptions.exampleOption) }, }, } ``` -------------------------------- ### Apply Options to Plugin Method Call (Instance) Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Pass plugin-specific options as the last argument to a plugin method called on an error instance. ```javascript error[methodName](...args, options[pluginName]) ``` -------------------------------- ### instanceMethods Object Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'instanceMethods' object allows you to define methods that can be called on an error instance or statically on the error class, with the error instance as the first argument. The 'info' object is provided by modern-errors, and subsequent arguments are passed from the method call. ```APIDOC ### instanceMethods.methodName _Type_: `(info, ...args) => any` Add error instance methods like `ErrorClass.methodName(error, ...args)` or `error.methodName(...args)`. Unlike [static methods](#staticmethodsmethodname), this should be used when the method's main argument is an `error` instance. The first argument [`info`](#info) is provided by `modern-errors`. The `error` argument is passed as [`info.error`](#error). The other `...args` are forwarded from the method's call. ```js export default { name: 'example', // `ErrorClass.concatMessage(error, "one")` or `error.concatMessage("one")` // return `${error.message} - one` instanceMethods: { concatMessage: (info, string) => `${info.error.message} - ${string}`, }, } ``` [Invalid errors](../README.md#invalid-errors) passed as `error` argument are automatically [normalized](../README.md#-normalize-errors). This only occurs when using `ErrorClass.methodName(error, ...args)`, not `error.methodName(...args)`. For this reason, we discourage using or documenting `error.methodName(...args)` unless there is a use case for it, since users might accidentally call it without [normalizing](../README.md#-normalize-errors) `error` first. ```js try { return regExp.test(value) } catch (error) { ErrorClass.exampleMethod(error, ...args) // This works ErrorClass.normalize(error).exampleMethod(...args) // This works error.exampleMethod(...args) // This throws } ``` ``` -------------------------------- ### TypeScript: Validate Plugin Options Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Use TypeScript to validate plugin options. Typing the `getOptions` parameter ensures that user-provided options conform to the expected structure. ```typescript // Any `{ example }` plugin option passed by users will be validated as boolean export default { name: 'example' as const, getOptions: (options: boolean): object => { // ... }, } ``` -------------------------------- ### Plugin Name Configuration Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Defines the 'name' property for a plugin, which is used to configure the plugin's options when creating error classes or instances. The name must consist only of lowercase letters. ```javascript // Users configure this plugin using // `ErrorClass.subclass('ErrorName', { example: ... })` // or `new ErrorClass('...', { example: ... }) export default { name: 'example', } ``` -------------------------------- ### TypeScript: Generic Info Type for Options Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Pass the expected options type as a generic argument to `Info` to correctly type `info.options` within plugin functions. ```typescript export default { // ... properties: (info: Info['properties']) => { // `info.options` is `boolean` if (info.options) { // ... } }, } ``` -------------------------------- ### Error Subclassing with Properties Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Create subclasses of existing error classes and define custom properties for both the class and instances. Parent class options are merged with subclass options. ```javascript export const BaseError = ModernError.subclass('BaseError', { props: { isError: true }, }) export const InputError = BaseError.subclass('InputError', { props: { isUserError: true }, }) const error = new InputError('...') console.log(error.isError) // true console.log(error.isUserError) // true console.log(error instanceof BaseError) // true console.log(error instanceof InputError) // true ``` -------------------------------- ### Apply Options to BaseError Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Configure plugin options when creating a base error class using `ModernError.subclass()`. ```javascript export const BaseError = ModernError.subclass('BaseError', options) ``` -------------------------------- ### Apply Options to Specific Error Class Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Configure plugin options when creating a specific error class (and its subclasses) using `ErrorClass.subclass()`. ```javascript export const InputError = BaseError.subclass('InputError', options) ``` -------------------------------- ### Define a Simple Plugin with Properties Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md This snippet shows how to create a basic plugin that modifies the error message by replacing a specific string. It's useful for sanitizing or masking sensitive information in error messages. ```javascript export default { name: 'secret', properties: ({ error }) => ({ message: error.message.replaceAll('secret', '******'), }), } ``` -------------------------------- ### Define and Use Typed Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Define a subclass with static and instance properties, then create an instance. TypeScript infers the types of the extracted properties and custom methods. ```typescript const BaseError = ModernError.subclass('BaseError', { props: { userId: 5 as const }, custom: class extends ModernError { isUserInput() { return true as const } }, }) const error = new BaseError('Wrong user name', { props: { userName: 'Alice' as const }, }) const { userId, userName } = error // Inferred type: `5` and `"Alice"` const result = error.isUserInput() // Inferred type: `true` ``` -------------------------------- ### getOptions Function Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'getOptions' function is used to validate and normalize the options passed to the error class. It receives the raw options and a 'full' flag, and should return the processed options. ```APIDOC ### getOptions _Type_: `(options, full) => options` Validate and normalize options. ``` -------------------------------- ### Access Error Information in Plugin Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Implement `staticMethods` to access and process error information. The `errorInfo` function provides details about an error, allowing custom logging or handling. ```javascript export default { name: 'example', staticMethods: { getLogErrors: ({ errorInfo }) => (errors) => { errors.forEach((error) => { const { options } = errorInfo(error) console.error(options.example?.stack ? error.stack : error.message) }) }, }, } ``` -------------------------------- ### Infer Error Class and Instance Types Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Illustrates how to use TypeScript utility types like `ReturnType` and `InstanceType` to infer the types of error classes and their instances, enabling type-safe function signatures. ```typescript type AnyErrorClass = ReturnType const InputError = BaseError.subclass('InputError') type InputErrorClass = typeof InputError type InputErrorInstance = InstanceType const printErrorClass = (ErrorClass: AnyErrorClass) => { // ... } const printInputErrorClass = (InputErrorClass: InputErrorClass) => { // ... } const logInputError = (inputError: InputErrorInstance) => { // ... } printErrorClass(InputError) printInputErrorClass(InputError) logInputError(new InputError('Wrong user name')) ``` -------------------------------- ### Use Plugins for Serialization Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Integrate plugins like `modern-errors-serialize` to add functionality such as serializing and parsing errors. This allows errors to be easily converted to and from JSON. ```javascript import ModernError from 'modern-errors' import modernErrorsSerialize from 'modern-errors-serialize' export const BaseError = ModernError.subclass('BaseError', { plugins: [modernErrorsSerialize], }) // ... // Serialize error as JSON, then back to identical error instance const error = new InputError('Missing file path.') const errorString = JSON.stringify(error) const identicalError = BaseError.parse(JSON.parse(errorString)) ``` -------------------------------- ### Configure BaseError with Plugins Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Configure `BaseError` to use specific plugins like `modern-errors-bugs` and `modern-errors-serialize` by passing them in the `plugins` array during subclassing. ```javascript import ModernError from 'modern-errors' import modernErrorsBugs from 'modern-errors-bugs' import modernErrorsSerialize from 'modern-errors-serialize' export const BaseError = ModernError.subclass('BaseError', { plugins: [modernErrorsBugs, modernErrorsSerialize], }) ``` -------------------------------- ### Throw a Simple Error Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Throw a custom error instance with a specific message. This is the basic way to signal an error condition. ```javascript throw new InputError('Missing file path.') ``` -------------------------------- ### Define and Normalize Unknown Errors Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Define a custom `UnknownError` class using `BaseError.subclass()` and use `BaseError.normalize(error, UnknownError)` to assign this class to unhandled exceptions. ```javascript export const UnknownError = BaseError.subclass('UnknownError') ``` ```javascript try { return regExp.test(value) } catch (error) { // Now an `UnknownError` instance throw BaseError.normalize(error, UnknownError) } ``` -------------------------------- ### Apply Options to Plugin Method Call (Class) Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Pass plugin-specific options as the last argument to a plugin method called on an error class. ```javascript ErrorClass[methodName](...args, options[pluginName]) ``` -------------------------------- ### Use a Plugin with a Custom Error Class Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Demonstrates how to integrate a custom plugin into a modern-errors subclass. This allows all errors extending from this subclass to inherit the plugin's functionality, such as the modified error message from the 'secret' plugin. ```javascript import ModernError from 'modern-errors' import secretPlugin from './secret.js' const BaseError = ModernError.subclass('BaseError', { plugins: [secretPlugin] }) const error = new BaseError('Message with a secret') console.log(error.message) // 'Message with a ******' ``` -------------------------------- ### Set Properties on Errors Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When throwing an error, you can include additional properties using the `props` option. This is helpful for providing context, such as the file path that caused an `InputError`. ```javascript throw new InputError('Invalid file path', { props: { filePath: '/...' } }) ``` -------------------------------- ### properties Function Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'properties' function accepts an 'info' object and should return an object containing properties to be added to the error instance. This can include 'message', 'stack', or custom properties. Internal or secret properties can be prefixed with '_' to make them non-enumerable. ```APIDOC ### properties _Type_: `(info) => object` Set properties on `error.*` (including `message` or `stack`). The properties to set must be returned as an object. Error properties that are internal or secret can be prefixed with `_`. This makes them [non-enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties), which prevents iterating or logging them. ```js export default { name: 'example', // Sets `error.example: true` properties: () => ({ example: true }), } ``` ``` -------------------------------- ### staticMethods.methodName Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Allows adding static methods to error classes, useful for operations not directly tied to an error instance. The first argument `info` is provided by Modern Errors. ```APIDOC ## staticMethods.methodName ### Description Add error static methods like `ErrorClass.methodName(...args)`. This should be used when the method's main argument is not an `error` instance. The first argument `info` is provided by `modern-errors`. `info.error` is not defined. The other `...args` are forwarded from the method's call. ### Method Signature `(info, ...args) => any` ### Example ```javascript export default { name: 'example', // `ErrorClass.multiply(2, 3)` returns `6` staticMethods: { multiply: (info, first, second) => first * second, }, } ``` ``` -------------------------------- ### name Property Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'name' property is a string that serves as the plugin's identifier. It's used when configuring the plugin's options in error classes. Only lowercase letters are permitted. ```APIDOC ### name _Type_: `string` Plugin's name. It is used to [configure](../README.md#plugin-options) the plugin's options. Only lowercase letters must be used (as opposed to `_` `-` `.` or uppercase letters). ```js // Users configure this plugin using // `ErrorClass.subclass('ErrorName', { example: ... })` // or `new ErrorClass('...', { example: ... })` export default { name: 'example', } ``` ``` -------------------------------- ### Top-Level Error Handling with BaseError.normalize() Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Use `BaseError.normalize(error, UnknownError)` in a top-level error handler to ensure all thrown errors are valid, have plugins applied, and are either known or `UnknownError` instances. ```javascript export const main = () => { try { // ... } catch (error) { throw BaseError.normalize(error, UnknownError) } } ``` -------------------------------- ### Handle Known Errors with try-catch and InputError Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Handle known errors within a `try...catch` block and wrap them with a specific error class like `InputError` using the `cause` option. This isolates the error source. ```javascript try { return regExp.test(value) } catch (error) { // Now an `InputError` instance throw new InputError('Invalid regular expression:', { cause: error }) } ``` -------------------------------- ### isOptions Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Determines if the last argument passed to a plugin method is the plugin's options. This is essential for correctly parsing arguments when options can be passed at various stages. ```APIDOC ## isOptions ### Description Determines whether the last argument of a plugin method are `options` or not. This should be defined if the plugin has any method with arguments. If `options` are invalid but can be determined not to be the last argument of any plugin's method, `isOptions()` should still return `true`. This allows `getOptions()` to validate them and throw proper error messages. ### Method Signature `(options) => boolean` ### Example ```javascript // `ErrorClass.exampleMethod(error, 'one', true)` results in: // options: true // args: ['one'] // `ErrorClass.exampleMethod(error, 'one', 'two')` results in: // options: undefined // args: ['one', 'two'] export default { name: 'example', isOptions: (options) => typeof options === 'boolean', getOptions: (options) => options, instanceMethod: { exampleMethod: ({ options }, ...args) => { // ... }, }, } ``` ``` -------------------------------- ### new ErrorClass Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Instantiates a new error object. This allows for creating specific error instances with custom messages and options. ```APIDOC ## new ErrorClass(message, options?) ### Description Instantiates a new error object. ### Parameters - **message** (string) - The error message. - **options** (InstanceOptions?) - Optional configuration for the error instance. ### Options #### options.props - Type: `object` - Description: [Error instance properties](#error-instance-properties). #### options.cause - Type: `any` - Description: The inner error being [wrapped](#-wrap-errors). #### options.errors - Type: `any[]` - Description: An array of errors being [aggregated](#aggregate-errors). #### options.* - Description: Any [plugin options](#plugin-options) can also be specified here. ### Return Value - Type: `Error` - Description: A new instance of the error class. ``` -------------------------------- ### TypeScript: Type Instance Methods Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Define types for `instanceMethods` in TypeScript to ensure correct validation of method calls on error objects. Generics are currently ignored. ```typescript // Any `ErrorClass.exampleMethod(error, input)` or `error.exampleMethod(input)` // call will be validated export default { // ... instanceMethods: { exampleMethod: (info: Info['instanceMethods'], input: boolean): void => {}, }, } ``` -------------------------------- ### staticMethods Object Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'staticMethods' object allows you to define static methods that can be called directly on the error class. The 'info' object is provided by modern-errors, and subsequent arguments are passed from the method call. ```APIDOC ### staticMethods.methodName _Type_: `(info, ...args) => any` Add static methods like `ErrorClass.staticMethod(...args)`. The first argument [`info`](#info) is provided by `modern-errors`. The `error` argument is passed as [`info.error`](#error). The other `...args` are forwarded from the method's call. ```js export default { name: 'example', // `ErrorClass.staticMethod(error, 'arg1')` staticMethods: { staticMethod: (info, arg1) => { // ... }, }, } ``` ``` -------------------------------- ### info.error Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Provides access to the normalized error instance within plugin methods. This member is not defined for static methods. ```APIDOC ## info.error ### Description Normalized error instance. This is not defined in [static methods](#staticmethodsmethodname). Its members are readonly and should not be directly mutated, with the exception that [instance methods](#instancemethodsmethodname) can mutate `info.error`. ### Type `Error` ### Example ```javascript export default { name: 'example', properties: ({ error }) => ({ isInputError: error.name === 'InputError' }), } ``` ``` -------------------------------- ### Wrap Errors with Cause Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Wrap an existing error by passing it as the `cause` option when creating a new error. This preserves the original error's stack trace and information. ```javascript try { // ... } catch (cause) { throw new InputError('Could not read the file.', { cause }) ``` -------------------------------- ### TypeScript: Type Error Info Properties Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Type the `info` parameter in plugin functions using `Info['properties']` for precise type checking of error details. ```typescript import type { Info } from 'modern-errors' export default { // ... properties: (info: Info['properties']) => { // ... }, } ``` -------------------------------- ### info.ErrorClasses Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Provides an array containing the current error class and all its subclasses, useful for checking class inclusion. ```APIDOC ## info.ErrorClasses ### Description Array containing both the [current error class](#errorclass) and all its [subclasses](../README.md#error-subclasses) (including deep ones). ### Type `ErrorClass[]` ### Example ```javascript export default { name: 'example', staticMethods: { isKnownErrorClass: ({ ErrorClasses }, value) => ErrorClasses.includes(value), }, } ``` ``` -------------------------------- ### Adding Instance Methods to Errors Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Demonstrates how to add an instance method to errors using the 'instanceMethods' hook. This method, 'concatMessage', can be called on error instances or via the ErrorClass, and it appends a string to the error's message. Note the difference in error normalization when called via ErrorClass vs. directly on the error instance. ```javascript export default { name: 'example', // `ErrorClass.concatMessage(error, "one")` or `error.concatMessage("one")` // return `${error.message} - one` instanceMethods: { concatMessage: (info, string) => `${info.error.message} - ${string}`, }, } ``` ```javascript try { return regExp.test(value) } catch (error) { ErrorClass.exampleMethod(error, ...args) // This works ErrorClass.normalize(error).exampleMethod(...args) // This works error.exampleMethod(...args) // This throws } ``` -------------------------------- ### Narrow Error Types with instanceof Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Demonstrates how to use `instanceof` to narrow down the type of a caught error to a specific subclass, allowing access to its unique properties. ```typescript const InputError = BaseError.subclass('InputError', { props: { isUserError: true as const }, }) try { // ... } catch (error) { // Narrows `error` type to `InputError` if (error instanceof InputError) { const { isUserError } = error // Inferred type: `true` } } ``` -------------------------------- ### Define Instance-Level Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Pass custom properties directly to the error constructor using the `props` option. These properties are specific to the error instance. ```javascript const error = new InputError('...', { props: { isUserError: true } }) console.log(error.isUserError) // true ``` -------------------------------- ### isOptions Function Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md The 'isOptions' function determines if a given value represents the plugin's options. It typically returns a boolean. ```APIDOC ### isOptions _Type_: `(options) => boolean` Determine if a value is plugin's options. ``` -------------------------------- ### Define Custom Error Class Logic Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Provide a custom error class extending the parent error class to add methods, constructors, properties, or options. The constructor must accept `(message, options)`. ```javascript export const InputError = BaseError.subclass('InputError', { // The `class` must extend from the parent error class custom: class extends BaseError { // If a `constructor` is defined, its parameters must be (message, options) // Additional `options` can be defined. constructor(message, options) { message += options?.suffix ?? '' super(message, options) } isUserInput() { // ... } }, }) const error = new InputError('Wrong user name', { suffix: ': example' }) console.log(error.message) // 'Wrong user name: example' console.log(error.isUserInput()) ``` -------------------------------- ### TypeScript: Type Plugin Name Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Type the `name` property with `as const` in TypeScript. This allows the name to be used for validating plugin options more precisely. ```typescript export default { name: 'example' as const, // ... } ``` -------------------------------- ### Define Internal Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Prefix property names with an underscore (`_`) to make them internal and non-enumerable. These properties are not logged or included in `Object.keys()`. ```javascript const error = new InputError('...', { props: { userId: 6, _isUserError: true }, }) console.log(error.userId) // 6 console.log(error._isUserError) // true console.log(Object.keys(error)) // ['userId'] console.log(error) // `userId` is logged, but not `_isUserError` ``` -------------------------------- ### Wrap Errors with InputError Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Wrap any error, including invalid or unknown ones, by passing it to the `cause` option of a specific error class like `InputError`. ```javascript try { // ... } catch (cause) { throw new InputError('...', { cause }) } ``` -------------------------------- ### Check Error Instances Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Use the `instanceof` operator to check if an error is an instance of a specific custom error class. This allows for targeted error handling. ```javascript if (error instanceof InputError) { // ... } ``` -------------------------------- ### Wrap Error Options: Merging Properties Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When wrapping an error, the `props` and plugin options from the outer error are merged with those of the inner error. ```javascript try { throw new AuthError('...', innerOptions) } catch (cause) { // `outerOptions` are merged with `innerOptions` throw new BaseError('...', { ...outerOptions, cause }) } ``` -------------------------------- ### Normalize Invalid Errors with BaseError.normalize() Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Use `BaseError.normalize()` to fix errors that are not `Error` instances or have invalid properties. This ensures the error is a valid `BaseError` instance. ```javascript try { throw 'Missing file path.' } catch (invalidError) { // This fails: `invalidError.message` is `undefined` console.log(invalidError.message.trim()) } ``` ```javascript try { throw 'Missing file path.' } catch (invalidError) { const normalizedError = BaseError.normalize(invalidError) // This works: 'Missing file path.' // `normalizedError` is a `BaseError` instance. console.log(normalizedError.message.trim()) } ``` -------------------------------- ### Add Static Method to Error Class Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Define a static method for an error class that does not primarily operate on an error instance. The first argument is `info`, and subsequent arguments are passed directly to the method. ```javascript export default { name: 'example', // `ErrorClass.multiply(2, 3)` returns `6` staticMethods: { multiply: (info, first, second) => first * second, }, } ``` -------------------------------- ### Aggregate Errors with InputError Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Use the `errors` option to aggregate multiple errors into a single `InputError`. This is similar to `AggregateError` but works with any error class. ```javascript const databaseError = new DatabaseError('...') const authError = new AuthError('...') throw new InputError('...', { errors: [databaseError, authError] }) ``` -------------------------------- ### info.ErrorClass Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Provides access to the current error class within plugin methods, allowing for operations like normalizing errors. ```APIDOC ## info.ErrorClass ### Description Current [error class](../README.md#%EF%B8%8F-error-classes). ### Type `ErrorClass` ### Example ```javascript export default { name: 'example', instanceMethods: { addErrors: ({ error, ErrorClass }, errors = []) => { error.errors = errors.map(ErrorClass.normalize) }, }, } ``` ``` -------------------------------- ### Normalize Errors to a Specific Class Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Use `BaseError.normalize(error)` to convert non-Error values (like strings) into instances of `BaseError`. This ensures consistent error handling. ```javascript try { throw 'Missing file path.' } catch (error) { // Normalized from a string to a `BaseError` instance throw BaseError.normalize(error) } ``` -------------------------------- ### Create Custom Error Classes with ModernError Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Define custom error classes by subclassing `ModernError`. This is useful for categorizing different types of errors within your application. ```javascript import ModernError from 'modern-errors' export const BaseError = ModernError.subclass('BaseError') export const UnknownError = BaseError.subclass('UnknownError') export const InputError = BaseError.subclass('InputError') export const AuthError = BaseError.subclass('AuthError') export const DatabaseError = BaseError.subclass('DatabaseError') ``` -------------------------------- ### Wrap Error Message: Empty Outer Message Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When the outer error message is empty, the inner error's message is used directly. If the outer message ends with `:` or `:\n`, the inner message is prepended. ```javascript const cause = new InputError('File does not exist.') // InputError: File does not exist. throw new InputError('', { cause }) ``` -------------------------------- ### TypeScript: Use Plugin Type with `satisfies` Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Use the `Plugin` type with the `satisfies` operator in TypeScript. This prevents type widening and preserves specific types declared by the plugin. ```typescript import type { Plugin } from 'modern-errors' export default { // ... } satisfies Plugin ``` -------------------------------- ### Integrate and Type Plugins Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Integrate a plugin like `modern-errors-http` into a custom error subclass. TypeScript provides type checking for plugin-specific options and inferred types for plugin methods. ```typescript import ModernError from 'modern-errors' // This plugin adds a `BaseError.httpResponse(error)` method import modernErrorsHttp from 'modern-errors-http' const BaseError = ModernError.subclass('BaseError', { plugins: [modernErrorsHttp], }) const error = new BaseError('Wrong user name', { http: { title: false }, // Type error: `title` must be a string }) const httpResponse = BaseError.httpResponse(error) // Inferred type: response object ``` -------------------------------- ### Access Current Error Class Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Within instance methods, the `ErrorClass` property in the `info` object provides access to the current error class. This allows for operations like normalizing other errors using the same class hierarchy. ```javascript export default { name: 'example', instanceMethods: { addErrors: ({ error, ErrorClass }, errors = []) => { error.errors = errors.map(ErrorClass.normalize) }, }, } ``` -------------------------------- ### ModernError.subclass Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Creates and returns a child ErrorClass. This method allows for the creation of hierarchical error structures. ```APIDOC ## ModernError.subclass(name, options?) ### Description Creates and returns a child `ErrorClass`. ### Parameters - **name** (string) - The name of the new error class. - **options** (ClassOptions?) - Optional configuration for the new error class. ### Options #### options.props - Type: `object` - Description: [Error class properties](#error-class-properties). #### options.plugins - Type: `Plugin[]` - Description: An array of plugins to associate with the error class. #### options.custom - Type: `class extends ErrorClass {}` - Description: A custom class to extend the error class with additional methods, constructors, or properties. #### options.* - Description: Any [plugin options](#plugin-options) can also be specified here. ``` -------------------------------- ### Wrap an Inner Error with a New Error Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Wrap an existing error (the `cause`) within a new error instance using the `cause` option. The inner error's properties are merged into the outer error. ```javascript try { // ... } catch (cause) { throw new InputError('Could not read the file.', { cause }) } ``` -------------------------------- ### Access Normalized Error Instance Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Use the `error` property within the `info` object in custom properties to access the normalized error instance. This is particularly useful for inspecting or transforming error details. ```javascript export default { name: 'example', properties: ({ error }) => ({ isInputError: error.name === 'InputError' }), } ``` -------------------------------- ### Check if Error Class is Known Source: https://github.com/ehmicky/modern-errors/blob/main/docs/plugins.md Define a static method that utilizes the `ErrorClasses` array from the `info` object to determine if a given value is the current error class or one of its subclasses. ```javascript export default { name: 'example', staticMethods: { isKnownErrorClass: ({ ErrorClasses }, value) => ErrorClasses.includes(value), }, } ``` -------------------------------- ### Define Class-Level Error Properties Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Define custom properties on an error class using the `props` option within `subclass()`. These properties will be available on instances of that class. ```javascript const InputError = BaseError.subclass('InputError', { props: { isUserError: true }, }) const error = new InputError('...') console.log(error.isUserError) // true ``` -------------------------------- ### Wrap Error Class: Replacing Inner Class Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When wrapping an error, the outer error's class replaces the inner error's class, unless the outer class is a parent of the inner class. ```javascript try { throw new AuthError('...') } catch (cause) { // Now an InputError throw new InputError('...', { cause }) } ``` -------------------------------- ### ErrorClass.normalize Source: https://github.com/ehmicky/modern-errors/blob/main/README.md Normalizes an error, converting it to an instance of the specified ErrorClass if necessary. This is useful for handling potentially invalid or unknown error types. ```APIDOC ## ErrorClass.normalize(error, NewErrorClass?) ### Description Normalizes an error. If the provided `error` is an instance of `ErrorClass` or its subclass, it is returned as is. Otherwise, it is converted to an instance of `NewErrorClass` (which defaults to `ErrorClass`). ### Parameters - **error** (Error | any) - The error to normalize. - **NewErrorClass** (subclass of ErrorClass) - The target error class to convert to if normalization is needed. ### Return Value - Type: `Error` - Description: The normalized error instance. ``` -------------------------------- ### Type Error Properties Without Default Values Source: https://github.com/ehmicky/modern-errors/blob/main/docs/typescript.md Define a subclass with explicitly typed instance properties that do not have default values. This allows TypeScript to infer the correct type for these properties. ```typescript const BaseError = ModernError.subclass('BaseError', { props: {} as { userId: number }, }) type UserId = InstanceType['userId'] // Type: `number` ``` -------------------------------- ### Wrap Error Message: Appending with Colon Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When the outer error message ends with a colon, the inner error's message is appended after the colon, forming a combined message. ```javascript // InputError: Could not read the file: File does not exist. throw new InputError(`Could not read the file:`, { cause }) ``` -------------------------------- ### Wrap Error Message: Appending Outer Message Source: https://github.com/ehmicky/modern-errors/blob/main/README.md If the outer error message is not empty and does not end with a colon or newline, it is appended to the inner error's message. ```javascript // InputError: File does not exist. // Could not read the file. throw new InputError('Could not read the file.', { cause }) ``` -------------------------------- ### Wrap Error Class: Preserving Parent Class Source: https://github.com/ehmicky/modern-errors/blob/main/README.md If the outer error's class is a parent of the inner error's class (e.g., `BaseError`), the inner error's original class is preserved. ```javascript try { throw new AuthError('...') } catch (cause) { // Still an AuthError throw new BaseError('...', { cause }) } ``` -------------------------------- ### Wrap Error Message: Appending with Newline Source: https://github.com/ehmicky/modern-errors/blob/main/README.md When the outer error message ends with a newline, the inner error's message is placed on a new line, preserving distinct messages. ```javascript // InputError: Could not read the file: // File does not exist. throw new InputError(`Could not read the file:\n`, { cause }) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.