Merge pull request #5 from overleaf/publish

Prepare to publish v2
This commit is contained in:
John Lees-Miller
2019-07-08 13:18:56 +01:00
committed by GitHub
8 changed files with 18 additions and 264 deletions

View File

@@ -1,21 +1,19 @@
# overleaf-error-type
# @overleaf/o-error
Make custom error types that:
Make custom error classes that:
- pass `instanceof` checks,
- have stack traces,
- support custom messages and properties (`info`), and
- can wrap internal errors (causes) like [VError](https://github.com/joyent/node-verror).
## For ES6
ES6 classes make it easy to define custom errors by subclassing `Error`. Subclassing `OError` adds a few extra helpers.
### Usage
## Usage
#### Throw an error directly
### Throw an error directly
```js
const OError = require('overleaf-error-type')
const OError = require('@overleaf/o-error')
function doSomethingBad () {
throw new OError({
@@ -25,13 +23,13 @@ function doSomethingBad () {
}
doSomethingBad()
// =>
// { ErrorTypeError: did something bad
// { OError: did something bad
// at doSomethingBad (repl:2:9) <-- stack trace
// name: 'ErrorTypeError', <-- default name
// name: 'OError', <-- default name
// info: { thing: 'foo' } } <-- attached info
```
#### Custom error class
### Custom error class
```js
class FooError extends OError {
@@ -51,7 +49,7 @@ doFoo()
// info: { foo: 'bar' } } <-- attached info
```
#### Wrapping an inner error (cause)
### Wrapping an inner error (cause)
```js
function doFoo2 () {
@@ -90,91 +88,11 @@ try {
// ...
```
## For ES5
For backward compatibility, the following ES5-only interface is still supported.
The approach is based mainly on https://gist.github.com/justmoon/15511f92e5216fa2624b; it just tries to DRY it up a bit.
### Usage
#### Define a standalone error class
```js
const OError = require('overleaf-error-type')
const CustomError = OError.define('CustomError')
function doSomethingBad () {
throw new CustomError()
}
doSomethingBad()
// =>
// CustomError <-- correct name
// at doSomethingBad (repl:2:9) <-- stack trace
```
#### Define an error subclass
```js
const SubCustomError = OError.extend(CustomError, 'SubCustomError')
try {
throw new SubCustomError()
} catch (err) {
console.log(err.name) // => SubCustomError
console.log(err instanceof SubCustomError) // => true
console.log(err instanceof CustomError) // => true
console.log(err instanceof Error) // => true
}
```
#### Add custom message and/or properties
```js
const UserNotFoundError = OError.define('UserNotFoundError',
function (userId) {
this.message = `User not found: ${userId}`
this.userId = userId
})
throw new UserNotFoundError(123)
// => UserNotFoundError: User not found: 123
```
#### Add custom Error types under an existing class
```js
class User {
static lookup (userId) {
throw new User.UserNotFoundError(userId)
}
}
OError.defineIn(User, 'UserNotFoundError', function (userId) {
this.message = `User not found: ${userId}`
this.userId = userId
})
User.lookup(123)
// =>
// UserNotFoundError: User not found: 123
// at Function.lookup (repl:3:11)
```
## References
General:
- [MDN: Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
- [Error Handling in Node.js](https://www.joyent.com/node-js/production/design/errors)
- [verror](https://github.com/joyent/node-verror)
For ES6:
- [Custom JavaScript Errors in ES6](https://medium.com/@xjamundx/custom-javascript-errors-in-es6-aa891b173f87)
- [Custom errors, extending Error](https://javascript.info/custom-errors)
For ES5:
- https://gist.github.com/justmoon/15511f92e5216fa2624b
- https://gist.github.com/justmoon/15511f92e5216fa2624b (some tests are based largely on this gist)

View File

@@ -1,7 +1,5 @@
'use strict'
var util = require('util')
/**
* Make custom error types that pass `instanceof` checks, have stack traces,
* support custom messages and properties, and support wrapping errors (causes).
@@ -9,10 +7,6 @@ var util = require('util')
* @module
*/
//
// For ES6+ Classes
//
/**
* A base class for custom errors that handles:
*
@@ -96,45 +90,4 @@ OError.getFullInfo = getFullInfo
OError.getFullStack = getFullStack
OError.hasCauseInstanceOf = hasCauseInstanceOf
//
// For ES5
//
function extendErrorType (base, name, builder) {
var errorConstructor = function () {
Error.captureStackTrace && Error.captureStackTrace(this, this.constructor)
if (builder) builder.apply(this, arguments)
this.name = name
}
util.inherits(errorConstructor, base)
errorConstructor.prototype.withCause = function (cause) {
this.cause = cause
if (this.message && cause.message) {
this.message += ': ' + cause.message
}
return this
}
return errorConstructor
}
function defineErrorType (name, builder) {
return extendErrorType(Error, name, builder)
}
function extendErrorTypeIn (container, base, name, builder) {
container[name] = extendErrorType(base, name, builder)
}
function defineErrorTypeIn (container, name, builder) {
extendErrorTypeIn(container, Error, name, builder)
}
OError.extend = extendErrorType
OError.define = defineErrorType
OError.extendIn = extendErrorTypeIn
OError.defineIn = defineErrorTypeIn
module.exports = OError

View File

@@ -1,6 +1,6 @@
{
"name": "overleaf-error-type",
"version": "1.0.0",
"name": "@overleaf/o-error",
"version": "2.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -523,13 +523,13 @@
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {

View File

@@ -1,14 +1,13 @@
{
"name": "overleaf-error-type",
"version": "1.0.0",
"description": "Make custom error types that pass `instanceof` checks, have stack traces and support custom messages and properties.",
"name": "@overleaf/o-error",
"version": "2.0.0",
"description": "Make custom error types that pass `instanceof` checks, have stack traces, support custom messages and properties, and can wrap causes (like VError).",
"main": "index.js",
"scripts": {
"test": "mocha --require test/support"
},
"author": "Overleaf (https://www.overleaf.com)",
"license": "MIT",
"private": true,
"devDependencies": {
"chai": "^3.3.0",
"mocha": "^6.1.4"

View File

@@ -1,115 +0,0 @@
'use strict'
var OError = require('..')
const { expectError } = require('./support')
describe('OError', function () {
it('defines a custom error type', function () {
var CustomError = OError.define('CustomError')
function doSomethingBad () {
throw new CustomError()
}
try {
doSomethingBad()
expect.fail('should have thrown')
} catch (e) {
expectError(e, {
name: 'CustomError',
klass: CustomError,
message: 'CustomError',
firstFrameRx: /doSomethingBad/
})
}
})
it('defines a custom error type with a message', function () {
var CustomError = OError.define('CustomError', function (x) {
this.message = 'x=' + x
this.x = x
})
function doSomethingBad () {
throw new CustomError('foo')
}
try {
doSomethingBad()
expect.fail('should have thrown')
} catch (e) {
expect(e.toString()).to.equal('CustomError: x=foo')
expect(e.message).to.equal('x=foo')
expect(e.x).to.equal('foo')
}
})
it('defines extended error type', function () {
var BaseError = OError.define('BaseError')
var DerivedError = OError.extend(BaseError, 'DerivedError')
function doSomethingBad () {
throw new DerivedError()
}
try {
doSomethingBad()
expect.fail('should have thrown')
} catch (e) {
expect(e.toString()).to.equal('DerivedError')
}
})
it('defines error types in a container object', function () {
var SomeClass = {}
OError.defineIn(SomeClass, 'CustomError')
function doSomethingBad () {
throw new SomeClass.CustomError()
}
try {
doSomethingBad()
expect.fail('should have thrown')
} catch (e) {
expect(e.toString()).to.equal('CustomError')
}
})
it('extends error types in a container object', function () {
var SomeClass = {}
OError.defineIn(SomeClass, 'CustomError', function (payload) {
this.message = 'custom error'
this.payload = payload
})
OError.extendIn(SomeClass, SomeClass.CustomError, 'DerivedCustomError',
function (payload) {
SomeClass.CustomError.call(this, payload)
this.message = 'derived custom error'
})
function doSomethingBad () {
throw new SomeClass.CustomError(123)
}
try {
doSomethingBad()
expect.fail('should have thrown')
} catch (e) {
expect(e.toString()).to.equal('CustomError: custom error')
expect(e.payload).to.equal(123)
}
function doSomethingBadWithDerived () {
throw new SomeClass.DerivedCustomError(456)
}
try {
doSomethingBadWithDerived()
expect.fail('should have thrown')
} catch (e) {
expect(e.toString()).to.equal('DerivedCustomError: derived custom error')
expect(e.payload).to.equal(456)
}
})
})

View File

@@ -99,7 +99,6 @@ describe('OError', () => {
it('handles a custom error without info', () => {
try {
throw new CustomError1({})
expect.fail('should have thrown')
} catch (e) {
expect(OError.getFullInfo(e)).to.deep.equal({})
let infoKey = Object.keys(e).find(k => k === 'info')

View File

@@ -4,7 +4,7 @@ var chai = require('chai')
global.expect = chai.expect
exports.expectError = function errorTypeExpectError (e, expected) {
exports.expectError = function OErrorExpectError (e, expected) {
// should set the name to the error's name
expect(e.name).to.equal(expected.name)