ono (Oh No!)
Throw better errors.
Features
-
Wrap and re-throw an error without losing the original error's type, message, stack trace, and properties
-
Add custom properties to errors — great for error numbers, status codes, etc.
-
Use format strings for error messages — great for localization
-
Enhanced support for JSON.stringify()
and util.inspect()
— great for logging
-
Create Ono instances for your own custom error classes
-
Tested on Node.js and all modern web browsers on Mac, Windows, and Linux.
Example
const ono = require("@jsdevtools/ono");
throw ono({ code: "NOT_FOUND", status: 404 }, `Resource not found: ${url}`);
throw ono(originalError, "An error occurred while saving your changes");
throw ono(originalError, { code: 404, status: "NOT_FOUND" });
throw ono(originalError, { code: 404, status: "NOT_FOUND" }, `Resource not found: ${url}`);
throw ono.range(...);
throw ono.syntax(...);
throw ono.reference(...);
const { Ono } = require("@jsdevtools/ono");
class MyErrorClass extends Error {}
ono.myError = new Ono(MyErrorClass);
throw ono.myError(...);
Installation
Install using npm:
npm install @jsdevtools/ono
Usage
When using Ono in Node.js apps, you'll probably want to use CommonJS syntax:
const ono = require("@jsdevtools/ono");
When using a transpiler such as Babel or TypeScript, or a bundler such as Webpack or Rollup, you can use ECMAScript modules syntax instead:
import ono from "@jsdevtools/ono";
Browser support
Ono supports recent versions of every major web browser. Older browsers may require Babel and/or polyfills.
To use Ono in a browser, you'll need to use a bundling tool such as Webpack, Rollup, Parcel, or Browserify. Some bundlers may require a bit of configuration, such as setting browser: true
in rollup-plugin-resolve.
API
ono([originalError], [props], [message, ...])
Creates an Error
object with the given properties.
-
originalError
- (optional) The original error that occurred, if any. This error's message, stack trace, and properties will be copied to the new error. If this error's type is one of the known error types, then the new error will be of the same type.
-
props
- (optional) An object whose properties will be copied to the new error. Properties can be anything, including objects and functions.
-
message
- (optional) The error message string. If it contains placeholders, then pass each placeholder's value as an additional parameter. See the format
option for more info.
Specific error types
The default ono()
function may return an instance of the base Error
class, or it may return a more specific sub-class, based on the type of the originalError
argument. If you want to explicitly create a specific type of error, then you can use any of the following methods:
The method signatures and arguments are exactly the same as the default ono()
function.
Ono(Error, [options])
The Ono
constructor is used to create your own custom ono
methods for custom error types, or to change the default behavior of the built-in methods.
Warning: Be sure not to confuse ono
(lowercase) and Ono
(capitalized). The latter one is a class.
-
Error
- The Error sub-class that this Ono method will create instances of
-
options
- (optional) An options object, which customizes the behavior of the Ono method
Options
The Ono
constructor takes an optional options object as a second parameter. The object can have the following properties, all of which are optional:
Option | Type | Default | Description |
---|
concatMessages | boolean | true | When Ono is used to wrap an error, this setting determines whether the inner error's message is appended to the new error message. |
format | function or boolean | util.format() in Node.js
false in web browsers | A function that replaces placeholders like in error messages with values.
If set to false , then error messages will be treated as literals and no placeholder replacement will occur. |
concatMessages
Option
When wrapping an error, Ono's default behavior is to append the error's message to your message, with a newline between them. For example:
const ono = require("@jsdevtools/ono");
function createArray(length) {
try {
return new Array(length);
}
catch (error) {
throw ono(error, "Sorry, I was unable to create the array.");
}
}
createArray(-5);
The above code produces the following error message:
Sorry, I was unable to create the array.
Invalid array length;
If you'd rather not include the original message, then you can set the concatMessages
option to false
. For example:
const { ono, Ono } = require("@jsdevtools/ono");
ono.range = new Ono(RangeError, { concatMessages: false });
function createArray(length) {
try {
return new Array(length);
}
catch (error) {
throw ono(error, "Sorry, I was unable to create the array.");
}
}
createArray(-5);
Now the error only includes your message, not the original error message.
Sorry, I was unable to create the array.
format
option
The format
option let you set a format function, which replaces placeholders in error messages with values.
When running in Node.js, Ono uses the util.format()
function by default, which lets you use placeholders such as %s, %d, and %j. You can provide the values for these placeholders when calling any Ono method:
throw ono("%s is invalid. Must be at least %d characters.", username, minLength);
Of course, the above example could be accomplished using ES6 template literals instead of format strings:
throw ono(`${username} is invalid. Must be at least ${minLength} characters.`);
Format strings are most useful when you don't alrady know the values at the time that you're writing the string. A common scenario is localization. Here's a simplistic example:
const errorMessages {
invalidLength: {
en: "%s is invalid. Must be at least %d characters.",
es: "%s no es válido. Debe tener al menos %d caracteres.",
zh: "%s 无效。 必须至少%d个字符。",
}
}
let lang = getCurrentUsersLanguage();
throw ono(errorMessages.invalidLength[lang], username, minLength);
The format
option in web browsers
Web browsers don't have a built-in equivalent of Node's util.format()
function, so format strings are only supported in Node.js by default. However, you can set the format
option to any compatible polyfill library to enable this functionality in web browsers too.
Here are some compatible polyfill libraries:
Custom format
implementation
If the standard util.format()
functionality isn't sufficient for your needs, then you can set the format
option to your own custom implementation. Here's a simplistic example:
const { ono, Ono } = require("@jsdevtools/ono");
let options = {
format(message, ...args) {
for (let [index, arg] of args.entries()) {
message = message.replace("$" + index, arg);
}
return message;
}
};
ono.error = new Ono(Error, options);
ono.eval = new Ono(EvalError, options);
ono.range = new Ono(RangeError, options);
ono.reference = new Ono(ReferenceError, options);
ono.syntax = new Ono(SyntaxError, options);
ono.type = new Ono(TypeError, options);
ono.uri = new Ono(URIError, options);
throw ono("$0 is invalid. Must be at least $1 characters.", username, minLength);
Custom Error Classes
Ono has built-in support for all of the built-in JavaScript Error types. For example, you can use ono.reference()
to create a ReferenceError
, or ono.syntax()
to create a SyntaxError
. In addition to the built-in types, you can also create Ono methods for your own custom error classes.
const { ono, Ono } = require("@jsdevtools/ono");
let counter = 0;
class MyErrorClass extends Error {
constructor(message) {
super(message);
this.id = ++counter;
this.timestamp = new Date();
}
}
ono.myError = new Ono(MyErrorClass);
throw ono.myError({ code: 404, status: "NOT_FOUND" }, `Resource not found: ${url}`);
The code above throws an instance of MyErrorClass
that looks like this:
{
"name": "MyErrorClass",
"message": "Resource not found: xyz.html",
"id": 1,
"timestamp": "2019-01-01T12:30:00.456Z",
"code": 404,
"status": "NOT_FOUND",
"stack": "MyErrorClass: Resource not found: xyz.html\n at someFunction (index.js:24:5)",
}
Contributing
Contributions, enhancements, and bug-fixes are welcome! File an issue on GitHub and submit a pull request.
Building/Testing
To build/test the project locally on your computer:
-
Clone this repo
git clone https://github.com/JS-DevTools/ono.git
-
Install dependencies
npm install
-
Run the build script
npm run build
-
Run the tests
npm test
License
Ono is 100% free and open-source, under the MIT license. Use it however you want.
This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.
Big Thanks To
Thanks to these awesome companies for their support of Open Source developers ❤