1'use strict' 2 3const { format, inspect, AggregateError: CustomAggregateError } = require('./util') 4 5/* 6 This file is a reduced and adapted version of the main lib/internal/errors.js file defined at 7 8 https://github.com/nodejs/node/blob/master/lib/internal/errors.js 9 10 Don't try to replace with the original file and keep it up to date (starting from E(...) definitions) 11 with the upstream file. 12*/ 13 14const AggregateError = globalThis.AggregateError || CustomAggregateError 15const kIsNodeError = Symbol('kIsNodeError') 16const kTypes = [ 17 'string', 18 'function', 19 'number', 20 'object', 21 // Accept 'Function' and 'Object' as alternative to the lower cased version. 22 'Function', 23 'Object', 24 'boolean', 25 'bigint', 26 'symbol' 27] 28const classRegExp = /^([A-Z][a-z0-9]*)+$/ 29const nodeInternalPrefix = '__node_internal_' 30const codes = {} 31function assert(value, message) { 32 if (!value) { 33 throw new codes.ERR_INTERNAL_ASSERTION(message) 34 } 35} 36 37// Only use this for integers! Decimal numbers do not work with this function. 38function addNumericalSeparator(val) { 39 let res = '' 40 let i = val.length 41 const start = val[0] === '-' ? 1 : 0 42 for (; i >= start + 4; i -= 3) { 43 res = `_${val.slice(i - 3, i)}${res}` 44 } 45 return `${val.slice(0, i)}${res}` 46} 47function getMessage(key, msg, args) { 48 if (typeof msg === 'function') { 49 assert( 50 msg.length <= args.length, 51 // Default options do not count. 52 `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${msg.length}).` 53 ) 54 return msg(...args) 55 } 56 const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length 57 assert( 58 expectedLength === args.length, 59 `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${expectedLength}).` 60 ) 61 if (args.length === 0) { 62 return msg 63 } 64 return format(msg, ...args) 65} 66function E(code, message, Base) { 67 if (!Base) { 68 Base = Error 69 } 70 class NodeError extends Base { 71 constructor(...args) { 72 super(getMessage(code, message, args)) 73 } 74 toString() { 75 return `${this.name} [${code}]: ${this.message}` 76 } 77 } 78 Object.defineProperties(NodeError.prototype, { 79 name: { 80 value: Base.name, 81 writable: true, 82 enumerable: false, 83 configurable: true 84 }, 85 toString: { 86 value() { 87 return `${this.name} [${code}]: ${this.message}` 88 }, 89 writable: true, 90 enumerable: false, 91 configurable: true 92 } 93 }) 94 NodeError.prototype.code = code 95 NodeError.prototype[kIsNodeError] = true 96 codes[code] = NodeError 97} 98function hideStackFrames(fn) { 99 // We rename the functions that will be hidden to cut off the stacktrace 100 // at the outermost one 101 const hidden = nodeInternalPrefix + fn.name 102 Object.defineProperty(fn, 'name', { 103 value: hidden 104 }) 105 return fn 106} 107function aggregateTwoErrors(innerError, outerError) { 108 if (innerError && outerError && innerError !== outerError) { 109 if (Array.isArray(outerError.errors)) { 110 // If `outerError` is already an `AggregateError`. 111 outerError.errors.push(innerError) 112 return outerError 113 } 114 const err = new AggregateError([outerError, innerError], outerError.message) 115 err.code = outerError.code 116 return err 117 } 118 return innerError || outerError 119} 120class AbortError extends Error { 121 constructor(message = 'The operation was aborted', options = undefined) { 122 if (options !== undefined && typeof options !== 'object') { 123 throw new codes.ERR_INVALID_ARG_TYPE('options', 'Object', options) 124 } 125 super(message, options) 126 this.code = 'ABORT_ERR' 127 this.name = 'AbortError' 128 } 129} 130E('ERR_ASSERTION', '%s', Error) 131E( 132 'ERR_INVALID_ARG_TYPE', 133 (name, expected, actual) => { 134 assert(typeof name === 'string', "'name' must be a string") 135 if (!Array.isArray(expected)) { 136 expected = [expected] 137 } 138 let msg = 'The ' 139 if (name.endsWith(' argument')) { 140 // For cases like 'first argument' 141 msg += `${name} ` 142 } else { 143 msg += `"${name}" ${name.includes('.') ? 'property' : 'argument'} ` 144 } 145 msg += 'must be ' 146 const types = [] 147 const instances = [] 148 const other = [] 149 for (const value of expected) { 150 assert(typeof value === 'string', 'All expected entries have to be of type string') 151 if (kTypes.includes(value)) { 152 types.push(value.toLowerCase()) 153 } else if (classRegExp.test(value)) { 154 instances.push(value) 155 } else { 156 assert(value !== 'object', 'The value "object" should be written as "Object"') 157 other.push(value) 158 } 159 } 160 161 // Special handle `object` in case other instances are allowed to outline 162 // the differences between each other. 163 if (instances.length > 0) { 164 const pos = types.indexOf('object') 165 if (pos !== -1) { 166 types.splice(types, pos, 1) 167 instances.push('Object') 168 } 169 } 170 if (types.length > 0) { 171 switch (types.length) { 172 case 1: 173 msg += `of type ${types[0]}` 174 break 175 case 2: 176 msg += `one of type ${types[0]} or ${types[1]}` 177 break 178 default: { 179 const last = types.pop() 180 msg += `one of type ${types.join(', ')}, or ${last}` 181 } 182 } 183 if (instances.length > 0 || other.length > 0) { 184 msg += ' or ' 185 } 186 } 187 if (instances.length > 0) { 188 switch (instances.length) { 189 case 1: 190 msg += `an instance of ${instances[0]}` 191 break 192 case 2: 193 msg += `an instance of ${instances[0]} or ${instances[1]}` 194 break 195 default: { 196 const last = instances.pop() 197 msg += `an instance of ${instances.join(', ')}, or ${last}` 198 } 199 } 200 if (other.length > 0) { 201 msg += ' or ' 202 } 203 } 204 switch (other.length) { 205 case 0: 206 break 207 case 1: 208 if (other[0].toLowerCase() !== other[0]) { 209 msg += 'an ' 210 } 211 msg += `${other[0]}` 212 break 213 case 2: 214 msg += `one of ${other[0]} or ${other[1]}` 215 break 216 default: { 217 const last = other.pop() 218 msg += `one of ${other.join(', ')}, or ${last}` 219 } 220 } 221 if (actual == null) { 222 msg += `. Received ${actual}` 223 } else if (typeof actual === 'function' && actual.name) { 224 msg += `. Received function ${actual.name}` 225 } else if (typeof actual === 'object') { 226 var _actual$constructor 227 if ( 228 (_actual$constructor = actual.constructor) !== null && 229 _actual$constructor !== undefined && 230 _actual$constructor.name 231 ) { 232 msg += `. Received an instance of ${actual.constructor.name}` 233 } else { 234 const inspected = inspect(actual, { 235 depth: -1 236 }) 237 msg += `. Received ${inspected}` 238 } 239 } else { 240 let inspected = inspect(actual, { 241 colors: false 242 }) 243 if (inspected.length > 25) { 244 inspected = `${inspected.slice(0, 25)}...` 245 } 246 msg += `. Received type ${typeof actual} (${inspected})` 247 } 248 return msg 249 }, 250 TypeError 251) 252E( 253 'ERR_INVALID_ARG_VALUE', 254 (name, value, reason = 'is invalid') => { 255 let inspected = inspect(value) 256 if (inspected.length > 128) { 257 inspected = inspected.slice(0, 128) + '...' 258 } 259 const type = name.includes('.') ? 'property' : 'argument' 260 return `The ${type} '${name}' ${reason}. Received ${inspected}` 261 }, 262 TypeError 263) 264E( 265 'ERR_INVALID_RETURN_VALUE', 266 (input, name, value) => { 267 var _value$constructor 268 const type = 269 value !== null && 270 value !== undefined && 271 (_value$constructor = value.constructor) !== null && 272 _value$constructor !== undefined && 273 _value$constructor.name 274 ? `instance of ${value.constructor.name}` 275 : `type ${typeof value}` 276 return `Expected ${input} to be returned from the "${name}"` + ` function but got ${type}.` 277 }, 278 TypeError 279) 280E( 281 'ERR_MISSING_ARGS', 282 (...args) => { 283 assert(args.length > 0, 'At least one arg needs to be specified') 284 let msg 285 const len = args.length 286 args = (Array.isArray(args) ? args : [args]).map((a) => `"${a}"`).join(' or ') 287 switch (len) { 288 case 1: 289 msg += `The ${args[0]} argument` 290 break 291 case 2: 292 msg += `The ${args[0]} and ${args[1]} arguments` 293 break 294 default: 295 { 296 const last = args.pop() 297 msg += `The ${args.join(', ')}, and ${last} arguments` 298 } 299 break 300 } 301 return `${msg} must be specified` 302 }, 303 TypeError 304) 305E( 306 'ERR_OUT_OF_RANGE', 307 (str, range, input) => { 308 assert(range, 'Missing "range" argument') 309 let received 310 if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) { 311 received = addNumericalSeparator(String(input)) 312 } else if (typeof input === 'bigint') { 313 received = String(input) 314 if (input > 2n ** 32n || input < -(2n ** 32n)) { 315 received = addNumericalSeparator(received) 316 } 317 received += 'n' 318 } else { 319 received = inspect(input) 320 } 321 return `The value of "${str}" is out of range. It must be ${range}. Received ${received}` 322 }, 323 RangeError 324) 325E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error) 326E('ERR_METHOD_NOT_IMPLEMENTED', 'The %s method is not implemented', Error) 327E('ERR_STREAM_ALREADY_FINISHED', 'Cannot call %s after a stream was finished', Error) 328E('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable', Error) 329E('ERR_STREAM_DESTROYED', 'Cannot call %s after a stream was destroyed', Error) 330E('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError) 331E('ERR_STREAM_PREMATURE_CLOSE', 'Premature close', Error) 332E('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF', Error) 333E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event', Error) 334E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error) 335E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError) 336module.exports = { 337 AbortError, 338 aggregateTwoErrors: hideStackFrames(aggregateTwoErrors), 339 hideStackFrames, 340 codes 341} 342