1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | 'use strict'
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | var statuses = require('statuses')
|
17 | var inherits = require('inherits')
|
18 | var customErrors = require('./errors.json')
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | module.exports = createError
|
26 | module.exports.HttpError = createHttpErrorConstructor()
|
27 |
|
28 |
|
29 | populateConstructorExports(module.exports, customErrors, module.exports.HttpError)
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | function createError () {
|
39 |
|
40 | var err
|
41 | var msg
|
42 | var status = 500
|
43 | var props = {}
|
44 | for (var i = 0; i < arguments.length; i++) {
|
45 | var arg = arguments[i]
|
46 | if (arg instanceof Error) {
|
47 | err = arg
|
48 | status = err.status || err.statusCode || status
|
49 | continue
|
50 | }
|
51 | switch (typeof arg) {
|
52 | case 'string':
|
53 | msg = arg
|
54 | break
|
55 | case 'number':
|
56 | status = arg
|
57 | break
|
58 | case 'object':
|
59 | props = arg
|
60 | break
|
61 | }
|
62 | }
|
63 |
|
64 | if (typeof status !== 'number' || !statuses[status]) {
|
65 | status = 500
|
66 | }
|
67 |
|
68 |
|
69 | var HttpError = createError[status]
|
70 |
|
71 | if (!err) {
|
72 |
|
73 | err = HttpError
|
74 | ? new HttpError(msg)
|
75 | : new Error(msg || statuses[status])
|
76 | Error.captureStackTrace(err, createError)
|
77 | }
|
78 |
|
79 | if (!HttpError || !(err instanceof HttpError)) {
|
80 |
|
81 | err.expose = status < 500
|
82 | err.status = err.statusCode = status
|
83 | }
|
84 |
|
85 | for (var key in props) {
|
86 | if (key !== 'status' && key !== 'statusCode') {
|
87 | err[key] = props[key]
|
88 | }
|
89 | }
|
90 |
|
91 | return err
|
92 | }
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | function createHttpErrorConstructor () {
|
100 | function HttpError () {
|
101 | throw new TypeError('cannot construct abstract class')
|
102 | }
|
103 |
|
104 | inherits(HttpError, Error)
|
105 |
|
106 | return HttpError
|
107 | }
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | function createClientErrorConstructor (HttpError, name, template, code) {
|
115 | var className = name.match(/Error$/) ? name : name + 'Error'
|
116 |
|
117 | function ClientError () {
|
118 | var args = Array.prototype.slice.call(arguments)
|
119 | var err
|
120 | if (args[0] instanceof Error) {
|
121 | err = args[0]
|
122 | } else {
|
123 | err = new Error(sprintf(template, args))
|
124 | }
|
125 |
|
126 |
|
127 | Error.captureStackTrace(err, ClientError)
|
128 |
|
129 |
|
130 | Object.setPrototypeOf(err, ClientError.prototype)
|
131 |
|
132 |
|
133 | Object.defineProperty(err, 'name', {
|
134 | enumerable: false,
|
135 | configurable: true,
|
136 | value: className,
|
137 | writable: true
|
138 | })
|
139 |
|
140 | return err
|
141 | }
|
142 |
|
143 | inherits(ClientError, HttpError)
|
144 |
|
145 | ClientError.prototype.status = code
|
146 | ClientError.prototype.statusCode = code
|
147 | ClientError.prototype.expose = true
|
148 |
|
149 | return ClientError
|
150 | }
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 | function createServerErrorConstructor (HttpError, name, template, code) {
|
158 | var className = name.match(/Error$/) ? name : name + 'Error'
|
159 |
|
160 | function ServerError () {
|
161 | var args = Array.prototype.slice.call(arguments)
|
162 | var err
|
163 | if (args[0] instanceof Error) {
|
164 | err = args[0]
|
165 | } else {
|
166 | err = new Error(sprintf(template, args))
|
167 | }
|
168 |
|
169 |
|
170 | Error.captureStackTrace(err, ServerError)
|
171 |
|
172 |
|
173 | Object.setPrototypeOf(err, ServerError.prototype)
|
174 |
|
175 |
|
176 | Object.defineProperty(err, 'name', {
|
177 | enumerable: false,
|
178 | configurable: true,
|
179 | value: className,
|
180 | writable: true
|
181 | })
|
182 |
|
183 | return err
|
184 | }
|
185 |
|
186 | inherits(ServerError, HttpError)
|
187 |
|
188 | ServerError.prototype.status = code
|
189 | ServerError.prototype.statusCode = code
|
190 | ServerError.prototype.expose = false
|
191 |
|
192 | return ServerError
|
193 | }
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | function populateConstructorExports (exports, errors, HttpError) {
|
201 | Object.keys(errors).forEach(function (name) {
|
202 | var CodeError
|
203 | var code = errors[name].code
|
204 | var message = errors[name].message
|
205 |
|
206 | switch (String(code).charAt(0)) {
|
207 | case '4':
|
208 | CodeError = createClientErrorConstructor(HttpError, name, message, code)
|
209 | break
|
210 | case '5':
|
211 | CodeError = createServerErrorConstructor(HttpError, name, message, code)
|
212 | break
|
213 | }
|
214 |
|
215 | if (CodeError) {
|
216 |
|
217 | exports[name] = CodeError
|
218 | }
|
219 | })
|
220 | }
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | function sprintf (template, values) {
|
228 | return template.replace(/%s/g, function () {
|
229 | return values.shift() || ''
|
230 | }).replace(/ {2}/g, ' ').trim() + (values.length ? '\n' + values.join('\n') : '')
|
231 | }
|