|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import v8 from 'node:v8' |
|
import assert from 'node:assert' |
|
|
|
|
|
import {URL} from 'node:url' |
|
import {format, inspect} from 'node:util' |
|
|
|
const own = {}.hasOwnProperty |
|
|
|
const classRegExp = /^([A-Z][a-z\d]*)+$/ |
|
|
|
const kTypes = new Set([ |
|
'string', |
|
'function', |
|
'number', |
|
'object', |
|
|
|
'Function', |
|
'Object', |
|
'boolean', |
|
'bigint', |
|
'symbol' |
|
]) |
|
|
|
export const codes = {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function formatList(array, type = 'and') { |
|
return array.length < 3 |
|
? array.join(` ${type} `) |
|
: `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}` |
|
} |
|
|
|
|
|
const messages = new Map() |
|
const nodeInternalPrefix = '__node_internal_' |
|
|
|
let userStackTraceLimit |
|
|
|
codes.ERR_INVALID_ARG_TYPE = createError( |
|
'ERR_INVALID_ARG_TYPE', |
|
|
|
|
|
|
|
|
|
|
|
(name, expected, actual) => { |
|
assert(typeof name === 'string', "'name' must be a string") |
|
if (!Array.isArray(expected)) { |
|
expected = [expected] |
|
} |
|
|
|
let message = 'The ' |
|
if (name.endsWith(' argument')) { |
|
|
|
message += `${name} ` |
|
} else { |
|
const type = name.includes('.') ? 'property' : 'argument' |
|
message += `"${name}" ${type} ` |
|
} |
|
|
|
message += '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.has(value)) { |
|
types.push(value.toLowerCase()) |
|
} else if (classRegExp.exec(value) === null) { |
|
assert( |
|
value !== 'object', |
|
'The value "object" should be written as "Object"' |
|
) |
|
other.push(value) |
|
} else { |
|
instances.push(value) |
|
} |
|
} |
|
|
|
|
|
|
|
if (instances.length > 0) { |
|
const pos = types.indexOf('object') |
|
if (pos !== -1) { |
|
types.slice(pos, 1) |
|
instances.push('Object') |
|
} |
|
} |
|
|
|
if (types.length > 0) { |
|
message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList( |
|
types, |
|
'or' |
|
)}` |
|
if (instances.length > 0 || other.length > 0) message += ' or ' |
|
} |
|
|
|
if (instances.length > 0) { |
|
message += `an instance of ${formatList(instances, 'or')}` |
|
if (other.length > 0) message += ' or ' |
|
} |
|
|
|
if (other.length > 0) { |
|
if (other.length > 1) { |
|
message += `one of ${formatList(other, 'or')}` |
|
} else { |
|
if (other[0].toLowerCase() !== other[0]) message += 'an ' |
|
message += `${other[0]}` |
|
} |
|
} |
|
|
|
message += `. Received ${determineSpecificType(actual)}` |
|
|
|
return message |
|
}, |
|
TypeError |
|
) |
|
|
|
codes.ERR_INVALID_MODULE_SPECIFIER = createError( |
|
'ERR_INVALID_MODULE_SPECIFIER', |
|
|
|
|
|
|
|
|
|
|
|
(request, reason, base = undefined) => { |
|
return `Invalid module "${request}" ${reason}${ |
|
base ? ` imported from ${base}` : '' |
|
}` |
|
}, |
|
TypeError |
|
) |
|
|
|
codes.ERR_INVALID_PACKAGE_CONFIG = createError( |
|
'ERR_INVALID_PACKAGE_CONFIG', |
|
|
|
|
|
|
|
|
|
|
|
(path, base, message) => { |
|
return `Invalid package config ${path}${ |
|
base ? ` while importing ${base}` : '' |
|
}${message ? `. ${message}` : ''}` |
|
}, |
|
Error |
|
) |
|
|
|
codes.ERR_INVALID_PACKAGE_TARGET = createError( |
|
'ERR_INVALID_PACKAGE_TARGET', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(packagePath, key, target, isImport = false, base = undefined) => { |
|
const relatedError = |
|
typeof target === 'string' && |
|
!isImport && |
|
target.length > 0 && |
|
!target.startsWith('./') |
|
if (key === '.') { |
|
assert(isImport === false) |
|
return ( |
|
`Invalid "exports" main target ${JSON.stringify(target)} defined ` + |
|
`in the package config ${packagePath}package.json${ |
|
base ? ` imported from ${base}` : '' |
|
}${relatedError ? '; targets must start with "./"' : ''}` |
|
) |
|
} |
|
|
|
return `Invalid "${ |
|
isImport ? 'imports' : 'exports' |
|
}" target ${JSON.stringify( |
|
target |
|
)} defined for '${key}' in the package config ${packagePath}package.json${ |
|
base ? ` imported from ${base}` : '' |
|
}${relatedError ? '; targets must start with "./"' : ''}` |
|
}, |
|
Error |
|
) |
|
|
|
codes.ERR_MODULE_NOT_FOUND = createError( |
|
'ERR_MODULE_NOT_FOUND', |
|
|
|
|
|
|
|
|
|
|
|
(path, base, exactUrl = false) => { |
|
return `Cannot find ${ |
|
exactUrl ? 'module' : 'package' |
|
} '${path}' imported from ${base}` |
|
}, |
|
Error |
|
) |
|
|
|
codes.ERR_NETWORK_IMPORT_DISALLOWED = createError( |
|
'ERR_NETWORK_IMPORT_DISALLOWED', |
|
"import of '%s' by %s is not supported: %s", |
|
Error |
|
) |
|
|
|
codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError( |
|
'ERR_PACKAGE_IMPORT_NOT_DEFINED', |
|
|
|
|
|
|
|
|
|
|
|
(specifier, packagePath, base) => { |
|
return `Package import specifier "${specifier}" is not defined${ |
|
packagePath ? ` in package ${packagePath}package.json` : '' |
|
} imported from ${base}` |
|
}, |
|
TypeError |
|
) |
|
|
|
codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError( |
|
'ERR_PACKAGE_PATH_NOT_EXPORTED', |
|
|
|
|
|
|
|
|
|
|
|
(packagePath, subpath, base = undefined) => { |
|
if (subpath === '.') |
|
return `No "exports" main defined in ${packagePath}package.json${ |
|
base ? ` imported from ${base}` : '' |
|
}` |
|
return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${ |
|
base ? ` imported from ${base}` : '' |
|
}` |
|
}, |
|
Error |
|
) |
|
|
|
codes.ERR_UNSUPPORTED_DIR_IMPORT = createError( |
|
'ERR_UNSUPPORTED_DIR_IMPORT', |
|
"Directory import '%s' is not supported " + |
|
'resolving ES modules imported from %s', |
|
Error |
|
) |
|
|
|
codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError( |
|
'ERR_UNSUPPORTED_RESOLVE_REQUEST', |
|
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.', |
|
TypeError |
|
) |
|
|
|
codes.ERR_UNKNOWN_FILE_EXTENSION = createError( |
|
'ERR_UNKNOWN_FILE_EXTENSION', |
|
|
|
|
|
|
|
|
|
(extension, path) => { |
|
return `Unknown file extension "${extension}" for ${path}` |
|
}, |
|
TypeError |
|
) |
|
|
|
codes.ERR_INVALID_ARG_VALUE = createError( |
|
'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 |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function createError(sym, value, constructor) { |
|
|
|
|
|
messages.set(sym, value) |
|
|
|
return makeNodeErrorWithCode(constructor, sym) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function makeNodeErrorWithCode(Base, key) { |
|
|
|
return NodeError |
|
|
|
|
|
|
|
function NodeError(...parameters) { |
|
const limit = Error.stackTraceLimit |
|
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0 |
|
const error = new Base() |
|
|
|
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit |
|
const message = getMessage(key, parameters, error) |
|
Object.defineProperties(error, { |
|
|
|
|
|
message: { |
|
value: message, |
|
enumerable: false, |
|
writable: true, |
|
configurable: true |
|
}, |
|
toString: { |
|
|
|
value() { |
|
return `${this.name} [${key}]: ${this.message}` |
|
}, |
|
enumerable: false, |
|
writable: true, |
|
configurable: true |
|
} |
|
}) |
|
|
|
captureLargerStackTrace(error) |
|
|
|
error.code = key |
|
return error |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
function isErrorStackTraceLimitWritable() { |
|
|
|
|
|
try { |
|
if (v8.startupSnapshot.isBuildingSnapshot()) { |
|
return false |
|
} |
|
} catch {} |
|
|
|
const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit') |
|
if (desc === undefined) { |
|
return Object.isExtensible(Error) |
|
} |
|
|
|
return own.call(desc, 'writable') && desc.writable !== undefined |
|
? desc.writable |
|
: desc.set !== undefined |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function hideStackFrames(wrappedFunction) { |
|
|
|
|
|
const hidden = nodeInternalPrefix + wrappedFunction.name |
|
Object.defineProperty(wrappedFunction, 'name', {value: hidden}) |
|
return wrappedFunction |
|
} |
|
|
|
const captureLargerStackTrace = hideStackFrames( |
|
|
|
|
|
|
|
|
|
|
|
function (error) { |
|
const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable() |
|
if (stackTraceLimitIsWritable) { |
|
userStackTraceLimit = Error.stackTraceLimit |
|
Error.stackTraceLimit = Number.POSITIVE_INFINITY |
|
} |
|
|
|
Error.captureStackTrace(error) |
|
|
|
|
|
if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit |
|
|
|
return error |
|
} |
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getMessage(key, parameters, self) { |
|
const message = messages.get(key) |
|
assert(message !== undefined, 'expected `message` to be found') |
|
|
|
if (typeof message === 'function') { |
|
assert( |
|
message.length <= parameters.length, |
|
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` + |
|
`match the required ones (${message.length}).` |
|
) |
|
return Reflect.apply(message, self, parameters) |
|
} |
|
|
|
const regex = /%[dfijoOs]/g |
|
let expectedLength = 0 |
|
while (regex.exec(message) !== null) expectedLength++ |
|
assert( |
|
expectedLength === parameters.length, |
|
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` + |
|
`match the required ones (${expectedLength}).` |
|
) |
|
if (parameters.length === 0) return message |
|
|
|
parameters.unshift(message) |
|
return Reflect.apply(format, null, parameters) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function determineSpecificType(value) { |
|
if (value === null || value === undefined) { |
|
return String(value) |
|
} |
|
|
|
if (typeof value === 'function' && value.name) { |
|
return `function ${value.name}` |
|
} |
|
|
|
if (typeof value === 'object') { |
|
if (value.constructor && value.constructor.name) { |
|
return `an instance of ${value.constructor.name}` |
|
} |
|
|
|
return `${inspect(value, {depth: -1})}` |
|
} |
|
|
|
let inspected = inspect(value, {colors: false}) |
|
|
|
if (inspected.length > 28) { |
|
inspected = `${inspected.slice(0, 25)}...` |
|
} |
|
|
|
return `type ${typeof value} (${inspected})` |
|
} |
|
|