| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a4fed6c commit 47fea13
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,19 +13,31 @@ const { | |||
| 13 | 13 | ObjectGetOwnPropertyNames, | |
| 14 | 14 | ObjectGetPrototypeOf, | |
| 15 | 15 | ObjectKeys, | |
| 16 | + ObjectPrototypeHasOwnProperty, | ||
| 16 | 17 | ObjectPrototypeToString, | |
| 17 | 18 | RangeError, | |
| 18 | 19 | ReferenceError, | |
| 19 | 20 | SafeSet, | |
| 21 | + StringFromCharCode, | ||
| 22 | + StringPrototypeSubstring, | ||
| 20 | 23 | SymbolToStringTag, | |
| 21 | 24 | SyntaxError, | |
| 25 | + SymbolFor, | ||
| 22 | 26 | TypeError, | |
| 27 | + TypedArrayPrototypeGetBuffer, | ||
| 28 | + TypedArrayPrototypeGetByteOffset, | ||
| 29 | + TypedArrayPrototypeGetByteLength, | ||
| 23 | 30 | URIError, | |
| 24 | 31 | } = primordials; | |
| 32 | + const { inspect: { custom: customInspectSymbol } } = require('util'); | ||
| 25 | 33 | ||
| 26 | 34 | const kSerializedError = 0; | |
| 27 | 35 | const kSerializedObject = 1; | |
| 28 | 36 | const kInspectedError = 2; | |
| 37 | + const kInspectedSymbol = 3; | ||
| 38 | + const kCustomInspectedObject = 4; | ||
| 39 | + | ||
| 40 | + const kSymbolStringLength = 'Symbol('.length; | ||
| 29 | 41 | ||
| 30 | 42 | const errors = { | |
| 31 | 43 | Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError, | |
@@ -42,19 +54,24 @@ function TryGetAllProperties(object, target = object) { | |||
| 42 | 54 | ArrayPrototypeForEach(keys, (key) => { | |
| 43 | 55 | let descriptor; | |
| 44 | 56 | try { | |
| 57 | + // TODO: create a null-prototype descriptor with needed properties only | ||
| 45 | 58 | descriptor = ObjectGetOwnPropertyDescriptor(object, key); | |
| 46 | 59 | } catch { return; } | |
| 47 | 60 | const getter = descriptor.get; | |
| 48 | 61 | if (getter && key !== '__proto__') { | |
| 49 | 62 | try { | |
| 50 | 63 | descriptor.value = FunctionPrototypeCall(getter, target); | |
| 64 | + delete descriptor.get; | ||
| 65 | + delete descriptor.set; | ||
| 51 | 66 | } catch { | |
| 52 | 67 | // Continue regardless of error. | |
| 53 | 68 | } | |
| 54 | 69 | } | |
| 55 | - if ('value' in descriptor && typeof descriptor.value !== 'function') { | ||
| 56 | - delete descriptor.get; | ||
| 57 | - delete descriptor.set; | ||
| 70 | + if (key === 'cause') { | ||
| 71 | + descriptor.value = serializeError(descriptor.value); | ||
| 72 | + all[key] = descriptor; | ||
| 73 | + } else if ('value' in descriptor && | ||
| 74 | + typeof descriptor.value !== 'function' && typeof descriptor.value !== 'symbol') { | ||
| 58 | 75 | all[key] = descriptor; | |
| 59 | 76 | } | |
| 60 | 77 | }); | |
@@ -95,6 +112,9 @@ function inspect(...args) { | |||
| 95 | 112 | let serialize; | |
| 96 | 113 | function serializeError(error) { | |
| 97 | 114 | if (!serialize) serialize = require('v8').serialize; | |
| 115 | + if (typeof error === 'symbol') { | ||
| 116 | + return Buffer.from(StringFromCharCode(kInspectedSymbol) + inspect(error), 'utf8'); | ||
| 117 | + } | ||
| 98 | 118 | try { | |
| 99 | 119 | if (typeof error === 'object' && | |
| 100 | 120 | ObjectPrototypeToString(error) === '[object Error]') { | |
@@ -113,14 +133,27 @@ function serializeError(error) { | |||
| 113 | 133 | } catch { | |
| 114 | 134 | // Continue regardless of error. | |
| 115 | 135 | } | |
| 136 | + try { | ||
| 137 | + if (error != null && | ||
| 138 | + ObjectPrototypeHasOwnProperty(error, customInspectSymbol)) { | ||
| 139 | + return Buffer.from(StringFromCharCode(kCustomInspectedObject) + inspect(error), 'utf8'); | ||
| 140 | + } | ||
| 141 | + } catch { | ||
| 142 | + // Continue regardless of error. | ||
| 143 | + } | ||
| 116 | 144 | try { | |
| 117 | 145 | const serialized = serialize(error); | |
| 118 | 146 | return Buffer.concat([Buffer.from([kSerializedObject]), serialized]); | |
| 119 | 147 | } catch { | |
| 120 | 148 | // Continue regardless of error. | |
| 121 | 149 | } | |
| 122 | - return Buffer.concat([Buffer.from([kInspectedError]), | ||
| 123 | - Buffer.from(inspect(error), 'utf8')]); | ||
| 150 | + return Buffer.from(StringFromCharCode(kInspectedError) + inspect(error), 'utf8'); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + function fromBuffer(error) { | ||
| 154 | + return Buffer.from(TypedArrayPrototypeGetBuffer(error), | ||
| 155 | + TypedArrayPrototypeGetByteOffset(error) + 1, | ||
| 156 | + TypedArrayPrototypeGetByteLength(error) - 1); | ||
| 124 | 157 | } | |
| 125 | 158 | ||
| 126 | 159 | let deserialize; | |
@@ -132,19 +165,27 @@ function deserializeError(error) { | |||
| 132 | 165 | const ctor = errors[constructor]; | |
| 133 | 166 | ObjectDefineProperty(properties, SymbolToStringTag, { | |
| 134 | 167 | __proto__: null, | |
| 135 | - value: { value: 'Error', configurable: true }, | ||
| 168 | + value: { __proto__: null, value: 'Error', configurable: true }, | ||
| 136 | 169 | enumerable: true, | |
| 137 | 170 | }); | |
| 171 | + if ('cause' in properties && 'value' in properties.cause) { | ||
| 172 | + properties.cause.value = deserializeError(properties.cause.value); | ||
| 173 | + } | ||
| 138 | 174 | return ObjectCreate(ctor.prototype, properties); | |
| 139 | 175 | } | |
| 140 | 176 | case kSerializedObject: | |
| 141 | 177 | return deserialize(error.subarray(1)); | |
| 142 | - case kInspectedError: { | ||
| 143 | - const buf = Buffer.from(error.buffer, | ||
| 144 | - error.byteOffset + 1, | ||
| 145 | - error.byteLength - 1); | ||
| 146 | - return buf.toString('utf8'); | ||
| 178 | + case kInspectedError: | ||
| 179 | + return fromBuffer(error).toString('utf8'); | ||
| 180 | + case kInspectedSymbol: { | ||
| 181 | + const buf = fromBuffer(error); | ||
| 182 | + return SymbolFor(StringPrototypeSubstring(buf.toString('utf8'), kSymbolStringLength, buf.length - 1)); | ||
| 147 | 183 | } | |
| 184 | + case kCustomInspectedObject: | ||
| 185 | + return { | ||
| 186 | + __proto__: null, | ||
| 187 | + [customInspectSymbol]: () => fromBuffer(error).toString('utf8'), | ||
| 188 | + }; | ||
| 148 | 189 | } | |
| 149 | 190 | require('assert').fail('This should not happen'); | |
| 150 | 191 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | 'use strict'; | |
| 3 | 3 | require('../common'); | |
| 4 | 4 | const assert = require('assert'); | |
| 5 | + const { inspect } = require('util'); | ||
| 5 | 6 | const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; | |
| 6 | 7 | const { serializeError, deserializeError } = require('internal/error_serdes'); | |
| 7 | 8 | ||
@@ -15,6 +16,9 @@ assert.strictEqual(cycle(1.4), 1.4); | |||
| 15 | 16 | assert.strictEqual(cycle(null), null); | |
| 16 | 17 | assert.strictEqual(cycle(undefined), undefined); | |
| 17 | 18 | assert.strictEqual(cycle('foo'), 'foo'); | |
| 19 | + assert.strictEqual(cycle(Symbol.for('foo')), Symbol.for('foo')); | ||
| 20 | + assert.strictEqual(cycle(Symbol('foo')).toString(), Symbol('foo').toString()); | ||
| 21 | + | ||
| 18 | 22 | ||
| 19 | 23 | let err = new Error('foo'); | |
| 20 | 24 | for (let i = 0; i < 10; i++) { | |
@@ -43,6 +47,52 @@ assert.strictEqual(cycle(new SubError('foo')).name, 'Error'); | |||
| 43 | 47 | assert.deepStrictEqual(cycle({ message: 'foo' }), { message: 'foo' }); | |
| 44 | 48 | assert.strictEqual(cycle(Function), '[Function: Function]'); | |
| 45 | 49 | ||
| 50 | + class ErrorWithCause extends Error { | ||
| 51 | + get cause() { | ||
| 52 | + return new Error('err'); | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + class ErrorWithThowingCause extends Error { | ||
| 56 | + get cause() { | ||
| 57 | + throw new Error('err'); | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + class ErrorWithCyclicCause extends Error { | ||
| 61 | + get cause() { | ||
| 62 | + return new ErrorWithCyclicCause(); | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + const errorWithCause = Object | ||
| 66 | + .defineProperty(new Error('Error with cause'), 'cause', { get() { return { foo: 'bar' }; } }); | ||
| 67 | + const errorWithThrowingCause = Object | ||
| 68 | + .defineProperty(new Error('Error with cause'), 'cause', { get() { throw new Error('err'); } }); | ||
| 69 | + const errorWithCyclicCause = Object | ||
| 70 | + .defineProperty(new Error('Error with cause'), 'cause', { get() { return errorWithCyclicCause; } }); | ||
| 71 | + | ||
| 72 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: 0 })).cause, 0); | ||
| 73 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: -1 })).cause, -1); | ||
| 74 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: 1.4 })).cause, 1.4); | ||
| 75 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: null })).cause, null); | ||
| 76 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: undefined })).cause, undefined); | ||
| 77 | + assert.strictEqual(Object.hasOwn(cycle(new Error('Error with cause', { cause: undefined })), 'cause'), true); | ||
| 78 | + assert.strictEqual(cycle(new Error('Error with cause', { cause: 'foo' })).cause, 'foo'); | ||
| 79 | + assert.deepStrictEqual(cycle(new Error('Error with cause', { cause: new Error('err') })).cause, new Error('err')); | ||
| 80 | + assert.deepStrictEqual(cycle(errorWithCause).cause, { foo: 'bar' }); | ||
| 81 | + assert.strictEqual(Object.hasOwn(cycle(errorWithThrowingCause), 'cause'), false); | ||
| 82 | + assert.strictEqual(Object.hasOwn(cycle(errorWithCyclicCause), 'cause'), true); | ||
| 83 | + assert.deepStrictEqual(cycle(new ErrorWithCause('Error with cause')).cause, new Error('err')); | ||
| 84 | + assert.strictEqual(cycle(new ErrorWithThowingCause('Error with cause')).cause, undefined); | ||
| 85 | + assert.strictEqual(Object.hasOwn(cycle(new ErrorWithThowingCause('Error with cause')), 'cause'), false); | ||
| 86 | + // When the cause is cyclic, it is serialized until Maxiumum call stack size is reached | ||
| 87 | + let depth = 0; | ||
| 88 | + let e = cycle(new ErrorWithCyclicCause('Error with cause')); | ||
| 89 | + while (e.cause) { | ||
| 90 | + e = e.cause; | ||
| 91 | + depth++; | ||
| 92 | + } | ||
| 93 | + assert(depth > 1); | ||
| 94 | + | ||
| 95 | + | ||
| 46 | 96 | { | |
| 47 | 97 | const err = new ERR_INVALID_ARG_TYPE('object', 'Object', 42); | |
| 48 | 98 | assert.match(String(err), /^TypeError \[ERR_INVALID_ARG_TYPE\]:/); | |
@@ -66,3 +116,12 @@ assert.strictEqual(cycle(Function), '[Function: Function]'); | |||
| 66 | 116 | serializeError(new DynamicError()); | |
| 67 | 117 | assert.strictEqual(called, true); | |
| 68 | 118 | } | |
| 119 | + | ||
| 120 | + | ||
| 121 | + const data = { | ||
| 122 | + foo: 'bar', | ||
| 123 | + [inspect.custom]() { | ||
| 124 | + return 'barbaz'; | ||
| 125 | + } | ||
| 126 | + }; | ||
| 127 | + assert.strictEqual(inspect(cycle(data)), 'barbaz'); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments