| 1 | var tmpl = require('tmpl')
|
|---|
| 2 |
|
|---|
| 3 | module.exports = makeError
|
|---|
| 4 |
|
|---|
| 5 | function BaseError() {}
|
|---|
| 6 | BaseError.prototype = new Error()
|
|---|
| 7 | BaseError.prototype.toString = function() {
|
|---|
| 8 | return this.message
|
|---|
| 9 | }
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 | /**
|
|---|
| 13 | * Makes an Error function with the signature:
|
|---|
| 14 | *
|
|---|
| 15 | * function(message, data)
|
|---|
| 16 | *
|
|---|
| 17 | * You'll typically do something like:
|
|---|
| 18 | *
|
|---|
| 19 | * var UnknownFileTypeError = makeError(
|
|---|
| 20 | * 'UnknownFileTypeError',
|
|---|
| 21 | * 'The specified type is not known.'
|
|---|
| 22 | * )
|
|---|
| 23 | * var er = UnknownFileTypeError()
|
|---|
| 24 | *
|
|---|
| 25 | * `er` will have a prototype chain that ensures:
|
|---|
| 26 | *
|
|---|
| 27 | * er instanceof Error
|
|---|
| 28 | * er instanceof UnknownFileTypeError
|
|---|
| 29 | *
|
|---|
| 30 | * You can also do `var er = new UnknownFileTypeError()` if you really like the
|
|---|
| 31 | * `new` keyword.
|
|---|
| 32 | *
|
|---|
| 33 | * @param String The name of the error.
|
|---|
| 34 | * @param String The default message string.
|
|---|
| 35 | * @param Object The default data object, merged with per instance data.
|
|---|
| 36 | */
|
|---|
| 37 | function makeError(name, defaultMessage, defaultData) {
|
|---|
| 38 | defaultMessage = tmpl(defaultMessage || '')
|
|---|
| 39 | defaultData = defaultData || {}
|
|---|
| 40 | if (defaultData.proto && !(defaultData.proto instanceof BaseError))
|
|---|
| 41 | throw new Error('The custom "proto" must be an Error created via makeError')
|
|---|
| 42 |
|
|---|
| 43 | var CustomError = function(message, data) {
|
|---|
| 44 | if (!(this instanceof CustomError)) return new CustomError(message, data)
|
|---|
| 45 |
|
|---|
| 46 | if (typeof message !== 'string' && !data) {
|
|---|
| 47 | data = message
|
|---|
| 48 | message = null
|
|---|
| 49 | }
|
|---|
| 50 |
|
|---|
| 51 | this.name = name
|
|---|
| 52 | this.data = data || defaultData
|
|---|
| 53 |
|
|---|
| 54 | if (typeof message === 'string') {
|
|---|
| 55 | this.message = tmpl(message, this.data)
|
|---|
| 56 | } else {
|
|---|
| 57 | this.message = defaultMessage(this.data)
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | var er = new Error()
|
|---|
| 61 | this.stack = er.stack
|
|---|
| 62 | if (this.stack) {
|
|---|
| 63 | // remove TWO stack level:
|
|---|
| 64 | if (typeof Components !== 'undefined') {
|
|---|
| 65 | // Mozilla:
|
|---|
| 66 | this.stack = this.stack.substring(this.stack.indexOf('\n') + 2)
|
|---|
| 67 | } else if (typeof chrome !== 'undefined' || typeof process !== 'undefined') {
|
|---|
| 68 | // Google Chrome/Node.js:
|
|---|
| 69 | this.stack = this.stack.replace(/\n[^\n]*/, '')
|
|---|
| 70 | this.stack = this.stack.replace(/\n[^\n]*/, '')
|
|---|
| 71 | this.stack = (
|
|---|
| 72 | this.name +
|
|---|
| 73 | (this.message ? (': ' + this.message) : '') +
|
|---|
| 74 | this.stack.substring(5)
|
|---|
| 75 | )
|
|---|
| 76 | }
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | if ('fileName' in er) this.fileName = er.fileName
|
|---|
| 80 | if ('lineNumber' in er) this.lineNumber = er.lineNumber
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | CustomError.prototype = defaultData.proto || new BaseError()
|
|---|
| 84 | delete defaultData.proto
|
|---|
| 85 |
|
|---|
| 86 | return CustomError
|
|---|
| 87 | }
|
|---|