1 |
|
2 |
|
3 | 'use strict'
|
4 |
|
5 | const {
|
6 | ArrayPrototypeFilter,
|
7 | ArrayPrototypeJoin,
|
8 | ArrayPrototypeUnshift,
|
9 | Error,
|
10 | ErrorCaptureStackTrace,
|
11 | ObjectDefineProperty,
|
12 | ObjectDefineProperties,
|
13 | ObjectIsExtensible,
|
14 | ObjectGetOwnPropertyDescriptor,
|
15 | ObjectPrototypeHasOwnProperty,
|
16 | ReflectApply,
|
17 | SafeMap,
|
18 | SafeWeakMap,
|
19 | StringPrototypeMatch,
|
20 | StringPrototypeStartsWith,
|
21 | Symbol,
|
22 | SymbolFor
|
23 | } = require('#internal/per_context/primordials')
|
24 |
|
25 | const kIsNodeError = Symbol('kIsNodeError')
|
26 |
|
27 | const messages = new SafeMap()
|
28 | const codes = {}
|
29 |
|
30 | const overrideStackTrace = new SafeWeakMap()
|
31 | let userStackTraceLimit
|
32 | const nodeInternalPrefix = '__node_internal_'
|
33 |
|
34 |
|
35 | let assert
|
36 |
|
37 | let internalUtilInspect = null
|
38 | function lazyInternalUtilInspect () {
|
39 | if (!internalUtilInspect) {
|
40 | internalUtilInspect = require('#internal/util/inspect')
|
41 | }
|
42 | return internalUtilInspect
|
43 | }
|
44 |
|
45 | let buffer
|
46 | function lazyBuffer () {
|
47 | if (buffer === undefined) { buffer = require('buffer').Buffer }
|
48 | return buffer
|
49 | }
|
50 |
|
51 | function isErrorStackTraceLimitWritable () {
|
52 | const desc = ObjectGetOwnPropertyDescriptor(Error, 'stackTraceLimit')
|
53 | if (desc === undefined) {
|
54 | return ObjectIsExtensible(Error)
|
55 | }
|
56 |
|
57 | return ObjectPrototypeHasOwnProperty(desc, 'writable')
|
58 | ? desc.writable
|
59 | : desc.set !== undefined
|
60 | }
|
61 |
|
62 | function inspectWithNoCustomRetry (obj, options) {
|
63 | const utilInspect = lazyInternalUtilInspect()
|
64 |
|
65 | try {
|
66 | return utilInspect.inspect(obj, options)
|
67 | } catch {
|
68 | return utilInspect.inspect(obj, { ...options, customInspect: false })
|
69 | }
|
70 | }
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | class SystemError extends Error {
|
81 | constructor (key, context) {
|
82 | const limit = Error.stackTraceLimit
|
83 | if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0
|
84 | super()
|
85 |
|
86 | if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit
|
87 | const prefix = getMessage(key, [], this)
|
88 | let message = `${prefix}: ${context.syscall} returned ` +
|
89 | `${context.code} (${context.message})`
|
90 |
|
91 | if (context.path !== undefined) { message += ` ${context.path}` }
|
92 | if (context.dest !== undefined) { message += ` => ${context.dest}` }
|
93 |
|
94 | captureLargerStackTrace(this)
|
95 |
|
96 | this.code = key
|
97 |
|
98 | ObjectDefineProperties(this, {
|
99 | [kIsNodeError]: {
|
100 | value: true,
|
101 | enumerable: false,
|
102 | writable: false,
|
103 | configurable: true
|
104 | },
|
105 | name: {
|
106 | value: 'SystemError',
|
107 | enumerable: false,
|
108 | writable: true,
|
109 | configurable: true
|
110 | },
|
111 | message: {
|
112 | value: message,
|
113 | enumerable: false,
|
114 | writable: true,
|
115 | configurable: true
|
116 | },
|
117 | info: {
|
118 | value: context,
|
119 | enumerable: true,
|
120 | configurable: true,
|
121 | writable: false
|
122 | },
|
123 | errno: {
|
124 | get () {
|
125 | return context.errno
|
126 | },
|
127 | set: (value) => {
|
128 | context.errno = value
|
129 | },
|
130 | enumerable: true,
|
131 | configurable: true
|
132 | },
|
133 | syscall: {
|
134 | get () {
|
135 | return context.syscall
|
136 | },
|
137 | set: (value) => {
|
138 | context.syscall = value
|
139 | },
|
140 | enumerable: true,
|
141 | configurable: true
|
142 | }
|
143 | })
|
144 |
|
145 | if (context.path !== undefined) {
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | ObjectDefineProperty(this, 'path', {
|
152 | get () {
|
153 | return context.path != null
|
154 | ? context.path.toString()
|
155 | : context.path
|
156 | },
|
157 | set: (value) => {
|
158 | context.path = value
|
159 | ? lazyBuffer().from(value.toString())
|
160 | : undefined
|
161 | },
|
162 | enumerable: true,
|
163 | configurable: true
|
164 | })
|
165 | }
|
166 |
|
167 | if (context.dest !== undefined) {
|
168 | ObjectDefineProperty(this, 'dest', {
|
169 | get () {
|
170 | return context.dest != null
|
171 | ? context.dest.toString()
|
172 | : context.dest
|
173 | },
|
174 | set: (value) => {
|
175 | context.dest = value
|
176 | ? lazyBuffer().from(value.toString())
|
177 | : undefined
|
178 | },
|
179 | enumerable: true,
|
180 | configurable: true
|
181 | })
|
182 | }
|
183 | }
|
184 |
|
185 | toString () {
|
186 | return `${this.name} [${this.code}]: ${this.message}`
|
187 | }
|
188 |
|
189 | [SymbolFor('nodejs.util.inspect.custom')] (recurseTimes, ctx) {
|
190 | return lazyInternalUtilInspect().inspect(this, {
|
191 | ...ctx,
|
192 | getters: true,
|
193 | customInspect: false
|
194 | })
|
195 | }
|
196 | }
|
197 |
|
198 | function makeSystemErrorWithCode (key) {
|
199 | return class NodeError extends SystemError {
|
200 | constructor (ctx) {
|
201 | super(key, ctx)
|
202 | }
|
203 | }
|
204 | }
|
205 |
|
206 | function makeNodeErrorWithCode (Base, key) {
|
207 | return function NodeError (...args) {
|
208 | const limit = Error.stackTraceLimit
|
209 | if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0
|
210 | const error = new Base()
|
211 |
|
212 | if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit
|
213 | const message = getMessage(key, args, error)
|
214 | ObjectDefineProperties(error, {
|
215 | [kIsNodeError]: {
|
216 | value: true,
|
217 | enumerable: false,
|
218 | writable: false,
|
219 | configurable: true
|
220 | },
|
221 | message: {
|
222 | value: message,
|
223 | enumerable: false,
|
224 | writable: true,
|
225 | configurable: true
|
226 | },
|
227 | toString: {
|
228 | value () {
|
229 | return `${this.name} [${key}]: ${this.message}`
|
230 | },
|
231 | enumerable: false,
|
232 | writable: true,
|
233 | configurable: true
|
234 | }
|
235 | })
|
236 | captureLargerStackTrace(error)
|
237 | error.code = key
|
238 | return error
|
239 | }
|
240 | }
|
241 |
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 | function hideStackFrames (fn) {
|
248 |
|
249 |
|
250 | const hidden = nodeInternalPrefix + fn.name
|
251 | ObjectDefineProperty(fn, 'name', { value: hidden })
|
252 | return fn
|
253 | }
|
254 |
|
255 |
|
256 |
|
257 | function E (sym, val, def, ...otherClasses) {
|
258 |
|
259 |
|
260 | messages.set(sym, val)
|
261 | if (def === SystemError) {
|
262 | def = makeSystemErrorWithCode(sym)
|
263 | } else {
|
264 | def = makeNodeErrorWithCode(def, sym)
|
265 | }
|
266 |
|
267 | if (otherClasses.length !== 0) {
|
268 | otherClasses.forEach((clazz) => {
|
269 | def[clazz.name] = makeNodeErrorWithCode(clazz, sym)
|
270 | })
|
271 | }
|
272 | codes[sym] = def
|
273 | }
|
274 |
|
275 | function getMessage (key, args, self) {
|
276 | const msg = messages.get(key)
|
277 |
|
278 | if (assert === undefined) assert = require('#internal/assert')
|
279 |
|
280 | if (typeof msg === 'function') {
|
281 | assert(
|
282 | msg.length <= args.length,
|
283 | `Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
284 | `match the required ones (${msg.length}).`
|
285 | )
|
286 | return ReflectApply(msg, self, args)
|
287 | }
|
288 |
|
289 | const expectedLength =
|
290 | (StringPrototypeMatch(msg, /%[dfijoOs]/g) || []).length
|
291 | assert(
|
292 | expectedLength === args.length,
|
293 | `Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
294 | `match the required ones (${expectedLength}).`
|
295 | )
|
296 | if (args.length === 0) { return msg }
|
297 |
|
298 | ArrayPrototypeUnshift(args, msg)
|
299 | return ReflectApply(lazyInternalUtilInspect().format, null, args)
|
300 | }
|
301 |
|
302 | const captureLargerStackTrace = hideStackFrames(
|
303 | function captureLargerStackTrace (err) {
|
304 | const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable()
|
305 | if (stackTraceLimitIsWritable) {
|
306 | userStackTraceLimit = Error.stackTraceLimit
|
307 | Error.stackTraceLimit = Infinity
|
308 | }
|
309 | ErrorCaptureStackTrace(err)
|
310 |
|
311 | if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit
|
312 |
|
313 | return err
|
314 | })
|
315 |
|
316 |
|
317 | function hideInternalStackFrames (error) {
|
318 | overrideStackTrace.set(error, (error, stackFrames) => {
|
319 | let frames = stackFrames
|
320 | if (typeof stackFrames === 'object') {
|
321 | frames = ArrayPrototypeFilter(
|
322 | stackFrames,
|
323 | (frm) => !StringPrototypeStartsWith(frm.getFileName() || '',
|
324 | 'node:internal')
|
325 | )
|
326 | }
|
327 | ArrayPrototypeUnshift(frames, error)
|
328 | return ArrayPrototypeJoin(frames, '\n at ')
|
329 | })
|
330 | }
|
331 |
|
332 | module.exports = {
|
333 | codes,
|
334 | inspectWithNoCustomRetry,
|
335 | kIsNodeError
|
336 | }
|
337 |
|
338 | E('ERR_TEST_FAILURE', function (error, failureType) {
|
339 | hideInternalStackFrames(this)
|
340 | assert(typeof failureType === 'string',
|
341 | "The 'failureType' argument must be of type string.")
|
342 |
|
343 | let msg = error?.message ?? error
|
344 |
|
345 | if (typeof msg !== 'string') {
|
346 | msg = inspectWithNoCustomRetry(msg)
|
347 | }
|
348 |
|
349 | this.failureType = failureType
|
350 | this.cause = error
|
351 | return msg
|
352 | }, Error)
|