Skip to content

Commit 08c6eb6

Browse files
Added better documentation, examples, and tests for Ono.extend()
1 parent e091654 commit 08c6eb6

File tree

2 files changed

+115
-25
lines changed

2 files changed

+115
-25
lines changed

README.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Features
2424

2525
- Enhanced support for [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) and [`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options) — great for logging
2626

27-
- Create Ono instances for your own [custom error classes](#custom-error-classes)
27+
- Supports and enhances your own [custom error classes](#custom-error-classes)
2828

2929
- Tested on Node.js and all modern web browsers on Mac, Windows, and Linux.
3030

@@ -279,7 +279,12 @@ throw ono("$0 is invalid. Must be at least $1 characters.", username, minLength)
279279

280280
Custom Error Classes
281281
-----------------------------
282-
Ono has built-in support for all of [the built-in JavaScript Error types](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#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.
282+
There are two ways to use Ono with your own custom error classes. Which one you choose depends on what parameters your custom error class accepts, and whether you'd prefer to use `ono.myError()` syntax or `new MyError()` syntax.
283+
284+
### Option 1: Standard Errors
285+
Ono has built-in support for all of [the built-in JavaScript Error types](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types). For example, you can use `ono.reference()` to create a `ReferenceError`, or `ono.syntax()` to create a `SyntaxError`.
286+
287+
All of these built-in JavaScript Error types accept a single parameter: the error message string. If your own error classes also work this way, then you can create Ono methods for your custom error classes. Here's an example:
283288

284289
```javascript
285290
const { ono, Ono } = require("@jsdevtools/ono");
@@ -315,11 +320,43 @@ The code above throws an instance of `MyErrorClass` that looks like this:
315320
}
316321
```
317322

323+
### Option 2: Enhanced Error Classes
324+
If your custom error classes require more than just an error message string parameter, then you'll need to use Ono differently. Rather than creating a [custom Ono method](#option-1-standard-errors) and using `ono.myError()` syntax, you'll use Ono _inside_ your error class's constructor. This has a few benefits:
325+
326+
- Your error class can accept whatever parameters you want
327+
- Ono is encapsulated within your error class
328+
- You can use `new MyError()` syntax rather than `ono.myError()` syntax
329+
330+
```javascript
331+
const { ono, Ono } = require("@jsdevtools/ono");
332+
333+
// A custom Error class for 404 Not Found
334+
class NotFoundError extends Error {
335+
constructor(method, url) {
336+
super(`404: ${method} ${url} was not found`);
337+
338+
// Add custom properties, enhance JSON.stringify() support, etc.
339+
Ono.extend(this, { statusCode: 404, method, url });
340+
}
341+
}
342+
343+
// A custom Error class for 500 Server Error
344+
class ServerError extends Error {
345+
constructor(originalError, method, url) {
346+
super(`500: A server error occurred while responding to ${method} ${url}`);
347+
348+
// Append the stack trace and custom properties of the original error,
349+
// and add new custom properties, enhance JSON.stringify() support, etc.
350+
Ono.extend(this, originalError, { statusCode: 500, method, url });
351+
}
352+
}
353+
```
354+
318355

319356

320357
Contributing
321358
--------------------------
322-
Contributions, enhancements, and bug-fixes are welcome! [File an issue](https://github.com/JS-DevTools/ono/issues) on GitHub and [submit a pull request](https://github.com/JS-DevTools/ono/pulls).
359+
Contributions, enhancements, and bug-fixes are welcome! [Open an issue](https://github.com/JS-DevTools/ono/issues) on GitHub and [submit a pull request](https://github.com/JS-DevTools/ono/pulls).
323360

324361
#### Building/Testing
325362
To build/test the project locally on your computer:

test/specs/ono-extend.spec.js

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,94 @@ describe("Ono.extend()", () => {
4040
}
4141
});
4242

43+
it("should enhance an error class with Ono functionality", () => {
44+
class ValidationError extends Error {
45+
constructor (errorNumber, fieldName) {
46+
super(`Error #${errorNumber}: Invalid ${fieldName}`);
47+
this.name = ValidationError.name;
48+
Ono.extend(this, { errorNumber, fieldName });
49+
}
50+
}
51+
52+
function createValidationError () {
53+
return new ValidationError(42, "emailAddress");
54+
}
55+
56+
let error = createValidationError();
57+
58+
expect(error).to.be.an.instanceOf(ValidationError);
59+
expect(error.name).to.equal("ValidationError");
60+
expect(error.message).to.equal("Error #42: Invalid emailAddress");
61+
expect(error.stack).to.satisfy(compareStacks(["createValidationError"]));
62+
expect(error).to.satisfy(compareKeys("name", "message", "stack", "toJSON", "errorNumber", "fieldName"));
63+
64+
expect(error.toJSON()).to.satisfy(comparePOJO({
65+
name: "ValidationError",
66+
message: "Error #42: Invalid emailAddress",
67+
stack: error.stack,
68+
errorNumber: 42,
69+
fieldName: "emailAddress",
70+
}));
71+
72+
if (host.node) {
73+
expect(error[inspect]()).to.satisfy(comparePOJO({
74+
name: "ValidationError",
75+
message: "Error #42: Invalid emailAddress",
76+
stack: error.stack,
77+
errorNumber: 42,
78+
fieldName: "emailAddress",
79+
toJSON: error.toJSON,
80+
toString: error.toString,
81+
}));
82+
}
83+
});
84+
4385
it("should include the stack trace of the original error", () => {
44-
function createOriginalError () {
45-
return new RangeError("Bad range");
86+
class ServerError extends Error {
87+
constructor (error, method, url) {
88+
super("HTTP 500: A server error occurred");
89+
this.name = ServerError.name;
90+
Ono.extend(this, error, { method, url });
91+
}
4692
}
4793

48-
function createNewError () {
49-
return new SyntaxError("Invalid syntax");
94+
function createServerError (originalError) {
95+
return new ServerError(originalError, "POST", "/customers/123456");
96+
}
97+
98+
function createOriginalError () {
99+
return new RangeError("Bad range");
50100
}
51101

52102
let originalError = createOriginalError();
53-
let newError = createNewError();
54-
let onoError = Ono.extend(newError, originalError);
103+
let error = createServerError(originalError);
55104

56-
expect(onoError).to.equal(newError);
57-
expect(onoError.name).to.equal("SyntaxError");
58-
expect(onoError.message).to.equal("Invalid syntax");
59-
expect(onoError.stack).to.satisfy(compareStacks(
60-
["createNewError"],
105+
expect(error).to.be.an.instanceOf(ServerError);
106+
expect(error.name).to.equal("ServerError");
107+
expect(error.message).to.equal("HTTP 500: A server error occurred");
108+
expect(error.stack).to.satisfy(compareStacks(
109+
["createServerError"],
61110
["createOriginalError"],
62111
));
63-
expect(onoError).to.satisfy(compareKeys("name", "message", "stack", "toJSON"));
112+
expect(error).to.satisfy(compareKeys("name", "message", "stack", "toJSON", "method", "url"));
64113

65-
expect(onoError.toJSON()).to.satisfy(comparePOJO({
66-
name: "SyntaxError",
67-
message: "Invalid syntax",
68-
stack: newError.stack
114+
expect(error.toJSON()).to.satisfy(comparePOJO({
115+
name: "ServerError",
116+
message: "HTTP 500: A server error occurred",
117+
stack: error.stack,
118+
method: "POST",
119+
url: "/customers/123456",
69120
}));
70121

71122
if (host.node) {
72-
expect(onoError[inspect]()).to.satisfy(comparePOJO({
73-
name: "SyntaxError",
74-
message: "Invalid syntax",
75-
stack: newError.stack,
76-
toJSON: newError.toJSON,
77-
toString: newError.toString,
123+
expect(error[inspect]()).to.satisfy(comparePOJO({
124+
name: "ServerError",
125+
message: "HTTP 500: A server error occurred",
126+
stack: error.stack,
127+
method: "POST",
128+
url: "/customers/123456",
129+
toJSON: error.toJSON,
130+
toString: error.toString,
78131
}));
79132
}
80133
});

0 commit comments

Comments
 (0)