lib,src: support DOMException ser-des
Added serialization and deserialization support for `DOMException`. Co-Authored-By: jazelly <xzha4350@gmail.com> PR-URL: https://github.com/nodejs/node/pull/58649 Fixes: https://github.com/nodejs/node/issues/49181 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jason Zhang <xzha4350@gmail.com>
This commit is contained in:
parent
3a7f8efe60
commit
5457443210
@ -525,4 +525,16 @@ export default [
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'lib/internal/per_context/domexception.js',
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
// Parameters passed to internal modules.
|
||||
privateSymbols: 'readonly',
|
||||
perIsolateSymbols: 'readonly',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -12,6 +12,18 @@ const {
|
||||
SymbolToStringTag,
|
||||
TypeError,
|
||||
} = primordials;
|
||||
const {
|
||||
transfer_mode_private_symbol,
|
||||
} = privateSymbols;
|
||||
const {
|
||||
messaging_clone_symbol,
|
||||
messaging_deserialize_symbol,
|
||||
} = perIsolateSymbols;
|
||||
|
||||
/**
|
||||
* Maps to BaseObject::TransferMode::kCloneable
|
||||
*/
|
||||
const kCloneable = 2;
|
||||
|
||||
function throwInvalidThisError(Base, type) {
|
||||
const err = new Base();
|
||||
@ -50,6 +62,7 @@ const disusedNamesSet = new SafeSet()
|
||||
|
||||
class DOMException {
|
||||
constructor(message = '', options = 'Error') {
|
||||
this[transfer_mode_private_symbol] = kCloneable;
|
||||
ErrorCaptureStackTrace(this);
|
||||
|
||||
if (options && typeof options === 'object') {
|
||||
@ -76,6 +89,28 @@ class DOMException {
|
||||
}
|
||||
}
|
||||
|
||||
[messaging_clone_symbol]() {
|
||||
// See serialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
|
||||
const internals = internalsMap.get(this);
|
||||
return {
|
||||
data: {
|
||||
message: internals.message,
|
||||
name: internals.name,
|
||||
stack: this.stack,
|
||||
},
|
||||
deserializeInfo: 'internal/worker/clone_dom_exception:DOMException',
|
||||
};
|
||||
}
|
||||
|
||||
[messaging_deserialize_symbol](data) {
|
||||
// See deserialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
|
||||
internalsMap.set(this, {
|
||||
message: data.message,
|
||||
name: data.name,
|
||||
});
|
||||
this.stack = data.stack;
|
||||
}
|
||||
|
||||
get name() {
|
||||
const internals = internalsMap.get(this);
|
||||
if (internals === undefined) {
|
||||
|
6
lib/internal/worker/clone_dom_exception.js
Normal file
6
lib/internal/worker/clone_dom_exception.js
Normal file
@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
// Delegate to the actual DOMException implementation.
|
||||
module.exports = {
|
||||
DOMException: internalBinding('messaging').DOMException,
|
||||
};
|
@ -767,13 +767,13 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
Local<ObjectTemplate> private_symbols = ObjectTemplate::New(isolate);
|
||||
Local<Object> private_symbols_object;
|
||||
#define V(PropertyName, _) \
|
||||
private_symbols->Set(isolate, #PropertyName, isolate_data->PropertyName());
|
||||
|
||||
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
|
||||
#undef V
|
||||
|
||||
Local<Object> private_symbols_object;
|
||||
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
|
||||
private_symbols_object->SetPrototypeV2(context, Null(isolate))
|
||||
.IsNothing()) {
|
||||
@ -783,6 +783,32 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
|
||||
return scope.Escape(private_symbols_object);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
|
||||
IsolateData* isolate_data) {
|
||||
CHECK(isolate_data);
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
EscapableHandleScope scope(isolate);
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
Local<ObjectTemplate> per_isolate_symbols = ObjectTemplate::New(isolate);
|
||||
#define V(PropertyName, _) \
|
||||
per_isolate_symbols->Set( \
|
||||
isolate, #PropertyName, isolate_data->PropertyName());
|
||||
|
||||
PER_ISOLATE_SYMBOL_PROPERTIES(V)
|
||||
#undef V
|
||||
|
||||
Local<Object> per_isolate_symbols_object;
|
||||
if (!per_isolate_symbols->NewInstance(context).ToLocal(
|
||||
&per_isolate_symbols_object) ||
|
||||
per_isolate_symbols_object->SetPrototypeV2(context, Null(isolate))
|
||||
.IsNothing()) {
|
||||
return MaybeLocal<Object>();
|
||||
}
|
||||
|
||||
return scope.Escape(per_isolate_symbols_object);
|
||||
}
|
||||
|
||||
Maybe<void> InitializePrimordials(Local<Context> context,
|
||||
IsolateData* isolate_data) {
|
||||
// Run per-context JS files.
|
||||
@ -812,6 +838,12 @@ Maybe<void> InitializePrimordials(Local<Context> context,
|
||||
return Nothing<void>();
|
||||
}
|
||||
|
||||
Local<Object> per_isolate_symbols;
|
||||
if (!InitializePerIsolateSymbols(context, isolate_data)
|
||||
.ToLocal(&per_isolate_symbols)) {
|
||||
return Nothing<void>();
|
||||
}
|
||||
|
||||
static const char* context_files[] = {"internal/per_context/primordials",
|
||||
"internal/per_context/domexception",
|
||||
"internal/per_context/messageport",
|
||||
@ -827,7 +859,8 @@ Maybe<void> InitializePrimordials(Local<Context> context,
|
||||
builtin_loader.SetEagerCompile();
|
||||
|
||||
for (const char** module = context_files; *module != nullptr; module++) {
|
||||
Local<Value> arguments[] = {exports, primordials, private_symbols};
|
||||
Local<Value> arguments[] = {
|
||||
exports, primordials, private_symbols, per_isolate_symbols};
|
||||
|
||||
if (builtin_loader
|
||||
.CompileAndCall(
|
||||
|
@ -416,6 +416,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
|
||||
FIXED_ONE_BYTE_STRING(isolate, "exports"),
|
||||
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
|
||||
FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
|
||||
FIXED_ONE_BYTE_STRING(isolate, "perIsolateSymbols"),
|
||||
};
|
||||
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
|
||||
strncmp(id,
|
||||
|
48
test/parallel/test-structuredClone-domexception.js
Normal file
48
test/parallel/test-structuredClone-domexception.js
Normal file
@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
function assertDOMException(actual, expected) {
|
||||
assert.strictEqual(actual instanceof DOMException, true);
|
||||
assert.strictEqual(actual.message, expected.message);
|
||||
assert.strictEqual(actual.name, expected.name);
|
||||
assert.strictEqual(actual.code, expected.code);
|
||||
assert.strictEqual(actual.stack, expected.stack);
|
||||
}
|
||||
|
||||
{
|
||||
// Clone basic DOMException
|
||||
const e = new DOMException('test');
|
||||
const clone = structuredClone(e);
|
||||
const clone2 = structuredClone(clone);
|
||||
assertDOMException(clone, e);
|
||||
assertDOMException(clone2, e);
|
||||
}
|
||||
|
||||
{
|
||||
// Clone a DOMException with a name
|
||||
const e = new DOMException('test', 'DataCloneError');
|
||||
const clone = structuredClone(e);
|
||||
const clone2 = structuredClone(clone);
|
||||
assertDOMException(clone, e);
|
||||
assertDOMException(clone2, e);
|
||||
}
|
||||
|
||||
{
|
||||
// Clone an arbitrary object with a DOMException prototype
|
||||
const obj = {};
|
||||
Object.setPrototypeOf(obj, DOMException.prototype);
|
||||
const clone = structuredClone(obj);
|
||||
assert.strictEqual(clone instanceof DOMException, false);
|
||||
}
|
||||
|
||||
{
|
||||
// Transfer a DOMException. DOMExceptions are not transferable.
|
||||
const e = new DOMException('test');
|
||||
assert.throws(() => {
|
||||
structuredClone(e, { transfer: [e] });
|
||||
}, {
|
||||
name: 'DataCloneError',
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user