mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
71785889c8
PR-URL: https://github.com/nodejs/node/pull/55044 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: LiviaMedeiros <livia@cirno.name>
191 lines
5.5 KiB
JavaScript
191 lines
5.5 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ArrayPrototypeForEach,
|
|
Error,
|
|
EvalError,
|
|
FunctionPrototypeCall,
|
|
ObjectAssign,
|
|
ObjectCreate,
|
|
ObjectDefineProperty,
|
|
ObjectGetOwnPropertyDescriptor,
|
|
ObjectGetOwnPropertyNames,
|
|
ObjectGetPrototypeOf,
|
|
ObjectKeys,
|
|
ObjectPrototypeToString,
|
|
RangeError,
|
|
ReferenceError,
|
|
SafeSet,
|
|
StringFromCharCode,
|
|
StringPrototypeSubstring,
|
|
SymbolFor,
|
|
SymbolToStringTag,
|
|
SyntaxError,
|
|
TypeError,
|
|
TypedArrayPrototypeGetBuffer,
|
|
TypedArrayPrototypeGetByteLength,
|
|
TypedArrayPrototypeGetByteOffset,
|
|
URIError,
|
|
} = primordials;
|
|
|
|
const { Buffer } = require('buffer');
|
|
const { inspect: { custom: customInspectSymbol } } = require('util');
|
|
|
|
const kSerializedError = 0;
|
|
const kSerializedObject = 1;
|
|
const kInspectedError = 2;
|
|
const kInspectedSymbol = 3;
|
|
const kCustomInspectedObject = 4;
|
|
|
|
const kSymbolStringLength = 'Symbol('.length;
|
|
|
|
const errors = {
|
|
Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError,
|
|
};
|
|
const errorConstructorNames = new SafeSet(ObjectKeys(errors));
|
|
|
|
function TryGetAllProperties(object, target = object) {
|
|
const all = { __proto__: null };
|
|
if (object === null)
|
|
return all;
|
|
ObjectAssign(all,
|
|
TryGetAllProperties(ObjectGetPrototypeOf(object), target));
|
|
const keys = ObjectGetOwnPropertyNames(object);
|
|
ArrayPrototypeForEach(keys, (key) => {
|
|
let descriptor;
|
|
try {
|
|
// TODO: create a null-prototype descriptor with needed properties only
|
|
descriptor = ObjectGetOwnPropertyDescriptor(object, key);
|
|
} catch { return; }
|
|
const getter = descriptor.get;
|
|
if (getter && key !== '__proto__') {
|
|
try {
|
|
descriptor.value = FunctionPrototypeCall(getter, target);
|
|
delete descriptor.get;
|
|
delete descriptor.set;
|
|
} catch {
|
|
// Continue regardless of error.
|
|
}
|
|
}
|
|
if (key === 'cause') {
|
|
descriptor.value = serializeError(descriptor.value);
|
|
all[key] = descriptor;
|
|
} else if ('value' in descriptor &&
|
|
typeof descriptor.value !== 'function' && typeof descriptor.value !== 'symbol') {
|
|
all[key] = descriptor;
|
|
}
|
|
});
|
|
return all;
|
|
}
|
|
|
|
function GetConstructors(object) {
|
|
const constructors = [];
|
|
|
|
for (let current = object;
|
|
current !== null;
|
|
current = ObjectGetPrototypeOf(current)) {
|
|
const desc = ObjectGetOwnPropertyDescriptor(current, 'constructor');
|
|
if (desc?.value) {
|
|
ObjectDefineProperty(constructors, constructors.length, {
|
|
__proto__: null,
|
|
value: desc.value, enumerable: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
return constructors;
|
|
}
|
|
|
|
function GetName(object) {
|
|
const desc = ObjectGetOwnPropertyDescriptor(object, 'name');
|
|
return desc?.value;
|
|
}
|
|
|
|
let internalUtilInspect;
|
|
function inspect(...args) {
|
|
internalUtilInspect ??= require('internal/util/inspect');
|
|
return internalUtilInspect.inspect(...args);
|
|
}
|
|
|
|
let serialize;
|
|
function serializeError(error) {
|
|
serialize ??= require('v8').serialize;
|
|
if (typeof error === 'symbol') {
|
|
return Buffer.from(StringFromCharCode(kInspectedSymbol) + inspect(error), 'utf8');
|
|
}
|
|
try {
|
|
if (typeof error === 'object' &&
|
|
ObjectPrototypeToString(error) === '[object Error]') {
|
|
const constructors = GetConstructors(error);
|
|
for (let i = 0; i < constructors.length; i++) {
|
|
const name = GetName(constructors[i]);
|
|
if (errorConstructorNames.has(name)) {
|
|
const serialized = serialize({
|
|
constructor: name,
|
|
properties: TryGetAllProperties(error),
|
|
});
|
|
return Buffer.concat([Buffer.from([kSerializedError]), serialized]);
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
// Continue regardless of error.
|
|
}
|
|
try {
|
|
if (error != null && customInspectSymbol in error) {
|
|
return Buffer.from(StringFromCharCode(kCustomInspectedObject) + inspect(error), 'utf8');
|
|
}
|
|
} catch {
|
|
// Continue regardless of error.
|
|
}
|
|
try {
|
|
const serialized = serialize(error);
|
|
return Buffer.concat([Buffer.from([kSerializedObject]), serialized]);
|
|
} catch {
|
|
// Continue regardless of error.
|
|
}
|
|
return Buffer.from(StringFromCharCode(kInspectedError) + inspect(error), 'utf8');
|
|
}
|
|
|
|
function fromBuffer(error) {
|
|
return Buffer.from(TypedArrayPrototypeGetBuffer(error),
|
|
TypedArrayPrototypeGetByteOffset(error) + 1,
|
|
TypedArrayPrototypeGetByteLength(error) - 1);
|
|
}
|
|
|
|
let deserialize;
|
|
function deserializeError(error) {
|
|
deserialize ??= require('v8').deserialize;
|
|
switch (error[0]) {
|
|
case kSerializedError: {
|
|
const { constructor, properties } = deserialize(error.subarray(1));
|
|
const ctor = errors[constructor];
|
|
ObjectDefineProperty(properties, SymbolToStringTag, {
|
|
__proto__: null,
|
|
value: { __proto__: null, value: 'Error', configurable: true },
|
|
enumerable: true,
|
|
});
|
|
if ('cause' in properties && 'value' in properties.cause) {
|
|
properties.cause.value = deserializeError(properties.cause.value);
|
|
}
|
|
return ObjectCreate(ctor.prototype, properties);
|
|
}
|
|
case kSerializedObject:
|
|
return deserialize(error.subarray(1));
|
|
case kInspectedError:
|
|
return fromBuffer(error).toString('utf8');
|
|
case kInspectedSymbol: {
|
|
const buf = fromBuffer(error);
|
|
return SymbolFor(StringPrototypeSubstring(buf.toString('utf8'), kSymbolStringLength, buf.length - 1));
|
|
}
|
|
case kCustomInspectedObject:
|
|
return {
|
|
__proto__: null,
|
|
[customInspectSymbol]: () => fromBuffer(error).toString('utf8'),
|
|
};
|
|
}
|
|
require('assert').fail('This should not happen');
|
|
}
|
|
|
|
module.exports = { serializeError, deserializeError };
|