mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-31 02:17:01 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			381 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			381 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict'
 | |
| 
 | |
| const { format, inspect, AggregateError: CustomAggregateError } = require('./util')
 | |
| /*
 | |
|   This file is a reduced and adapted version of the main lib/internal/errors.js file defined at
 | |
| 
 | |
|   https://github.com/nodejs/node/blob/master/lib/internal/errors.js
 | |
| 
 | |
|   Don't try to replace with the original file and keep it up to date (starting from E(...) definitions)
 | |
|   with the upstream file.
 | |
| */
 | |
| 
 | |
| const AggregateError = globalThis.AggregateError || CustomAggregateError
 | |
| const kIsNodeError = Symbol('kIsNodeError')
 | |
| const kTypes = [
 | |
|   'string',
 | |
|   'function',
 | |
|   'number',
 | |
|   'object', // Accept 'Function' and 'Object' as alternative to the lower cased version.
 | |
|   'Function',
 | |
|   'Object',
 | |
|   'boolean',
 | |
|   'bigint',
 | |
|   'symbol'
 | |
| ]
 | |
| const classRegExp = /^([A-Z][a-z0-9]*)+$/
 | |
| const nodeInternalPrefix = '__node_internal_'
 | |
| const codes = {}
 | |
| 
 | |
| function assert(value, message) {
 | |
|   if (!value) {
 | |
|     throw new codes.ERR_INTERNAL_ASSERTION(message)
 | |
|   }
 | |
| } // Only use this for integers! Decimal numbers do not work with this function.
 | |
| 
 | |
| function addNumericalSeparator(val) {
 | |
|   let res = ''
 | |
|   let i = val.length
 | |
|   const start = val[0] === '-' ? 1 : 0
 | |
| 
 | |
|   for (; i >= start + 4; i -= 3) {
 | |
|     res = `_${val.slice(i - 3, i)}${res}`
 | |
|   }
 | |
| 
 | |
|   return `${val.slice(0, i)}${res}`
 | |
| }
 | |
| 
 | |
| function getMessage(key, msg, args) {
 | |
|   if (typeof msg === 'function') {
 | |
|     assert(
 | |
|       msg.length <= args.length, // Default options do not count.
 | |
|       `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${msg.length}).`
 | |
|     )
 | |
|     return msg(...args)
 | |
|   }
 | |
| 
 | |
|   const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length
 | |
|   assert(
 | |
|     expectedLength === args.length,
 | |
|     `Code: ${key}; The provided arguments length (${args.length}) does not match the required ones (${expectedLength}).`
 | |
|   )
 | |
| 
 | |
|   if (args.length === 0) {
 | |
|     return msg
 | |
|   }
 | |
| 
 | |
|   return format(msg, ...args)
 | |
| }
 | |
| 
 | |
| function E(code, message, Base) {
 | |
|   if (!Base) {
 | |
|     Base = Error
 | |
|   }
 | |
| 
 | |
|   class NodeError extends Base {
 | |
|     constructor(...args) {
 | |
|       super(getMessage(code, message, args))
 | |
|     }
 | |
| 
 | |
|     toString() {
 | |
|       return `${this.name} [${code}]: ${this.message}`
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   NodeError.prototype.name = Base.name
 | |
|   NodeError.prototype.code = code
 | |
|   NodeError.prototype[kIsNodeError] = true
 | |
| 
 | |
|   NodeError.prototype.toString = function () {
 | |
|     return `${this.name} [${code}]: ${this.message}`
 | |
|   }
 | |
| 
 | |
|   codes[code] = NodeError
 | |
| }
 | |
| 
 | |
| function hideStackFrames(fn) {
 | |
|   // We rename the functions that will be hidden to cut off the stacktrace
 | |
|   // at the outermost one
 | |
|   const hidden = nodeInternalPrefix + fn.name
 | |
|   Object.defineProperty(fn, 'name', {
 | |
|     value: hidden
 | |
|   })
 | |
|   return fn
 | |
| }
 | |
| 
 | |
| function aggregateTwoErrors(innerError, outerError) {
 | |
|   if (innerError && outerError && innerError !== outerError) {
 | |
|     if (Array.isArray(outerError.errors)) {
 | |
|       // If `outerError` is already an `AggregateError`.
 | |
|       outerError.errors.push(innerError)
 | |
|       return outerError
 | |
|     }
 | |
| 
 | |
|     const err = new AggregateError([outerError, innerError], outerError.message)
 | |
|     err.code = outerError.code
 | |
|     return err
 | |
|   }
 | |
| 
 | |
|   return innerError || outerError
 | |
| }
 | |
| 
 | |
| class AbortError extends Error {
 | |
|   constructor(message = 'The operation was aborted', options = undefined) {
 | |
|     if (options !== undefined && typeof options !== 'object') {
 | |
|       throw new codes.ERR_INVALID_ARG_TYPE('options', 'Object', options)
 | |
|     }
 | |
| 
 | |
|     super(message, options)
 | |
|     this.code = 'ABORT_ERR'
 | |
|     this.name = 'AbortError'
 | |
|   }
 | |
| }
 | |
| 
 | |
| E('ERR_ASSERTION', '%s', Error)
 | |
| E(
 | |
|   'ERR_INVALID_ARG_TYPE',
 | |
|   (name, expected, actual) => {
 | |
|     assert(typeof name === 'string', "'name' must be a string")
 | |
| 
 | |
|     if (!Array.isArray(expected)) {
 | |
|       expected = [expected]
 | |
|     }
 | |
| 
 | |
|     let msg = 'The '
 | |
| 
 | |
|     if (name.endsWith(' argument')) {
 | |
|       // For cases like 'first argument'
 | |
|       msg += `${name} `
 | |
|     } else {
 | |
|       msg += `"${name}" ${name.includes('.') ? 'property' : 'argument'} `
 | |
|     }
 | |
| 
 | |
|     msg += 'must be '
 | |
|     const types = []
 | |
|     const instances = []
 | |
|     const other = []
 | |
| 
 | |
|     for (const value of expected) {
 | |
|       assert(typeof value === 'string', 'All expected entries have to be of type string')
 | |
| 
 | |
|       if (kTypes.includes(value)) {
 | |
|         types.push(value.toLowerCase())
 | |
|       } else if (classRegExp.test(value)) {
 | |
|         instances.push(value)
 | |
|       } else {
 | |
|         assert(value !== 'object', 'The value "object" should be written as "Object"')
 | |
|         other.push(value)
 | |
|       }
 | |
|     } // Special handle `object` in case other instances are allowed to outline
 | |
|     // the differences between each other.
 | |
| 
 | |
|     if (instances.length > 0) {
 | |
|       const pos = types.indexOf('object')
 | |
| 
 | |
|       if (pos !== -1) {
 | |
|         types.splice(types, pos, 1)
 | |
|         instances.push('Object')
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (types.length > 0) {
 | |
|       switch (types.length) {
 | |
|         case 1:
 | |
|           msg += `of type ${types[0]}`
 | |
|           break
 | |
| 
 | |
|         case 2:
 | |
|           msg += `one of type ${types[0]} or ${types[1]}`
 | |
|           break
 | |
| 
 | |
|         default: {
 | |
|           const last = types.pop()
 | |
|           msg += `one of type ${types.join(', ')}, or ${last}`
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (instances.length > 0 || other.length > 0) {
 | |
|         msg += ' or '
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (instances.length > 0) {
 | |
|       switch (instances.length) {
 | |
|         case 1:
 | |
|           msg += `an instance of ${instances[0]}`
 | |
|           break
 | |
| 
 | |
|         case 2:
 | |
|           msg += `an instance of ${instances[0]} or ${instances[1]}`
 | |
|           break
 | |
| 
 | |
|         default: {
 | |
|           const last = instances.pop()
 | |
|           msg += `an instance of ${instances.join(', ')}, or ${last}`
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (other.length > 0) {
 | |
|         msg += ' or '
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     switch (other.length) {
 | |
|       case 0:
 | |
|         break
 | |
| 
 | |
|       case 1:
 | |
|         if (other[0].toLowerCase() !== other[0]) {
 | |
|           msg += 'an '
 | |
|         }
 | |
| 
 | |
|         msg += `${other[0]}`
 | |
|         break
 | |
| 
 | |
|       case 2:
 | |
|         msg += `one of ${other[0]} or ${other[1]}`
 | |
|         break
 | |
| 
 | |
|       default: {
 | |
|         const last = other.pop()
 | |
|         msg += `one of ${other.join(', ')}, or ${last}`
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (actual == null) {
 | |
|       msg += `. Received ${actual}`
 | |
|     } else if (typeof actual === 'function' && actual.name) {
 | |
|       msg += `. Received function ${actual.name}`
 | |
|     } else if (typeof actual === 'object') {
 | |
|       var _actual$constructor
 | |
| 
 | |
|       if (
 | |
|         (_actual$constructor = actual.constructor) !== null &&
 | |
|         _actual$constructor !== undefined &&
 | |
|         _actual$constructor.name
 | |
|       ) {
 | |
|         msg += `. Received an instance of ${actual.constructor.name}`
 | |
|       } else {
 | |
|         const inspected = inspect(actual, {
 | |
|           depth: -1
 | |
|         })
 | |
|         msg += `. Received ${inspected}`
 | |
|       }
 | |
|     } else {
 | |
|       let inspected = inspect(actual, {
 | |
|         colors: false
 | |
|       })
 | |
| 
 | |
|       if (inspected.length > 25) {
 | |
|         inspected = `${inspected.slice(0, 25)}...`
 | |
|       }
 | |
| 
 | |
|       msg += `. Received type ${typeof actual} (${inspected})`
 | |
|     }
 | |
| 
 | |
|     return msg
 | |
|   },
 | |
|   TypeError
 | |
| )
 | |
| E(
 | |
|   'ERR_INVALID_ARG_VALUE',
 | |
|   (name, value, reason = 'is invalid') => {
 | |
|     let inspected = inspect(value)
 | |
| 
 | |
|     if (inspected.length > 128) {
 | |
|       inspected = inspected.slice(0, 128) + '...'
 | |
|     }
 | |
| 
 | |
|     const type = name.includes('.') ? 'property' : 'argument'
 | |
|     return `The ${type} '${name}' ${reason}. Received ${inspected}`
 | |
|   },
 | |
|   TypeError
 | |
| )
 | |
| E(
 | |
|   'ERR_INVALID_RETURN_VALUE',
 | |
|   (input, name, value) => {
 | |
|     var _value$constructor
 | |
| 
 | |
|     const type =
 | |
|       value !== null &&
 | |
|       value !== undefined &&
 | |
|       (_value$constructor = value.constructor) !== null &&
 | |
|       _value$constructor !== undefined &&
 | |
|       _value$constructor.name
 | |
|         ? `instance of ${value.constructor.name}`
 | |
|         : `type ${typeof value}`
 | |
|     return `Expected ${input} to be returned from the "${name}"` + ` function but got ${type}.`
 | |
|   },
 | |
|   TypeError
 | |
| )
 | |
| E(
 | |
|   'ERR_MISSING_ARGS',
 | |
|   (...args) => {
 | |
|     assert(args.length > 0, 'At least one arg needs to be specified')
 | |
|     let msg
 | |
|     const len = args.length
 | |
|     args = (Array.isArray(args) ? args : [args]).map((a) => `"${a}"`).join(' or ')
 | |
| 
 | |
|     switch (len) {
 | |
|       case 1:
 | |
|         msg += `The ${args[0]} argument`
 | |
|         break
 | |
| 
 | |
|       case 2:
 | |
|         msg += `The ${args[0]} and ${args[1]} arguments`
 | |
|         break
 | |
| 
 | |
|       default:
 | |
|         {
 | |
|           const last = args.pop()
 | |
|           msg += `The ${args.join(', ')}, and ${last} arguments`
 | |
|         }
 | |
|         break
 | |
|     }
 | |
| 
 | |
|     return `${msg} must be specified`
 | |
|   },
 | |
|   TypeError
 | |
| )
 | |
| E(
 | |
|   'ERR_OUT_OF_RANGE',
 | |
|   (str, range, input) => {
 | |
|     assert(range, 'Missing "range" argument')
 | |
|     let received
 | |
| 
 | |
|     if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) {
 | |
|       received = addNumericalSeparator(String(input))
 | |
|     } else if (typeof input === 'bigint') {
 | |
|       received = String(input)
 | |
| 
 | |
|       if (input > 2n ** 32n || input < -(2n ** 32n)) {
 | |
|         received = addNumericalSeparator(received)
 | |
|       }
 | |
| 
 | |
|       received += 'n'
 | |
|     } else {
 | |
|       received = inspect(input)
 | |
|     }
 | |
| 
 | |
|     return `The value of "${str}" is out of range. It must be ${range}. Received ${received}`
 | |
|   },
 | |
|   RangeError
 | |
| )
 | |
| E('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times', Error)
 | |
| E('ERR_METHOD_NOT_IMPLEMENTED', 'The %s method is not implemented', Error)
 | |
| E('ERR_STREAM_ALREADY_FINISHED', 'Cannot call %s after a stream was finished', Error)
 | |
| E('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable', Error)
 | |
| E('ERR_STREAM_DESTROYED', 'Cannot call %s after a stream was destroyed', Error)
 | |
| E('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError)
 | |
| E('ERR_STREAM_PREMATURE_CLOSE', 'Premature close', Error)
 | |
| E('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF', Error)
 | |
| E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event', Error)
 | |
| E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error)
 | |
| E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError)
 | |
| module.exports = {
 | |
|   AbortError,
 | |
|   aggregateTwoErrors: hideStackFrames(aggregateTwoErrors),
 | |
|   hideStackFrames,
 | |
|   codes
 | |
| }
 |