@@ -1001,6 +1001,47 @@ static Maybe<bool> ReadIterable(Environment* env,
1001
1001
return Just (true );
1002
1002
}
1003
1003
1004
+ bool GetTransferList (Environment* env,
1005
+ Local<Context> context,
1006
+ Local<Value> transfer_list_v,
1007
+ TransferList* transfer_list_out) {
1008
+ if (transfer_list_v->IsNullOrUndefined ()) {
1009
+ // Browsers ignore null or undefined, and otherwise accept an array or an
1010
+ // options object.
1011
+ return true ;
1012
+ }
1013
+
1014
+ if (!transfer_list_v->IsObject ()) {
1015
+ THROW_ERR_INVALID_ARG_TYPE (
1016
+ env, " Optional transferList argument must be an iterable" );
1017
+ return false ;
1018
+ }
1019
+
1020
+ bool was_iterable;
1021
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_list_v)
1022
+ .To (&was_iterable))
1023
+ return false ;
1024
+ if (!was_iterable) {
1025
+ Local<Value> transfer_option;
1026
+ if (!transfer_list_v.As <Object>()
1027
+ ->Get (context, env->transfer_string ())
1028
+ .ToLocal (&transfer_option))
1029
+ return false ;
1030
+ if (!transfer_option->IsUndefined ()) {
1031
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_option)
1032
+ .To (&was_iterable))
1033
+ return false ;
1034
+ if (!was_iterable) {
1035
+ THROW_ERR_INVALID_ARG_TYPE (
1036
+ env, " Optional options.transfer argument must be an iterable" );
1037
+ return false ;
1038
+ }
1039
+ }
1040
+ }
1041
+
1042
+ return true ;
1043
+ }
1044
+
1004
1045
void MessagePort::PostMessage (const FunctionCallbackInfo<Value>& args) {
1005
1046
Environment* env = Environment::GetCurrent (args);
1006
1047
Local<Object> obj = args.This ();
@@ -1011,33 +1052,10 @@ void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) {
1011
1052
" MessagePort.postMessage" );
1012
1053
}
1013
1054
1014
- if (!args[1 ]->IsNullOrUndefined () && !args[1 ]->IsObject ()) {
1015
- // Browsers ignore null or undefined, and otherwise accept an array or an
1016
- // options object.
1017
- return THROW_ERR_INVALID_ARG_TYPE (env,
1018
- " Optional transferList argument must be an iterable" );
1019
- }
1020
-
1021
1055
TransferList transfer_list;
1022
- if (args[1 ]->IsObject ()) {
1023
- bool was_iterable;
1024
- if (!ReadIterable (env, context, transfer_list, args[1 ]).To (&was_iterable))
1025
- return ;
1026
- if (!was_iterable) {
1027
- Local<Value> transfer_option;
1028
- if (!args[1 ].As <Object>()->Get (context, env->transfer_string ())
1029
- .ToLocal (&transfer_option)) return ;
1030
- if (!transfer_option->IsUndefined ()) {
1031
- if (!ReadIterable (env, context, transfer_list, transfer_option)
1032
- .To (&was_iterable)) return ;
1033
- if (!was_iterable) {
1034
- return THROW_ERR_INVALID_ARG_TYPE (env,
1035
- " Optional options.transfer argument must be an iterable" );
1036
- }
1037
- }
1038
- }
1056
+ if (!GetTransferList (env, context, args[1 ], &transfer_list)) {
1057
+ return ;
1039
1058
}
1040
-
1041
1059
MessagePort* port = Unwrap<MessagePort>(args.This ());
1042
1060
// Even if the backing MessagePort object has already been deleted, we still
1043
1061
// want to serialize the message to ensure spec-compliant behavior w.r.t.
@@ -1528,6 +1546,49 @@ static void SetDeserializerCreateObjectFunction(
1528
1546
env->set_messaging_deserialize_create_object (args[0 ].As <Function>());
1529
1547
}
1530
1548
1549
+ static void StructuredClone (const FunctionCallbackInfo<Value>& args) {
1550
+ Isolate* isolate = args.GetIsolate ();
1551
+ Local<Context> context = isolate->GetCurrentContext ();
1552
+ Realm* realm = Realm::GetCurrent (context);
1553
+ Environment* env = realm->env ();
1554
+
1555
+ if (args.Length () == 0 ) {
1556
+ return THROW_ERR_MISSING_ARGS (env, " The value argument must be specified" );
1557
+ }
1558
+
1559
+ Local<Value> value = args[0 ];
1560
+
1561
+ TransferList transfer_list;
1562
+ if (!args[1 ]->IsNullOrUndefined ()) {
1563
+ if (!args[1 ]->IsObject ()) {
1564
+ return THROW_ERR_INVALID_ARG_TYPE (
1565
+ env, " The options argument must be either an object or undefined" );
1566
+ }
1567
+ Local<Object> options = args[1 ].As <Object>();
1568
+ Local<Value> transfer_list_v;
1569
+ if (!options->Get (context, FIXED_ONE_BYTE_STRING (isolate, " transfer" ))
1570
+ .ToLocal (&transfer_list_v)) {
1571
+ return ;
1572
+ }
1573
+
1574
+ if (!GetTransferList (env, context, transfer_list_v, &transfer_list)) {
1575
+ return ;
1576
+ }
1577
+ }
1578
+
1579
+ std::shared_ptr<Message> msg = std::make_shared<Message>();
1580
+ Maybe<bool > serialization_maybe =
1581
+ msg->Serialize (env, context, value, transfer_list, Local<Object>());
1582
+
1583
+ if (serialization_maybe.IsNothing ()) {
1584
+ return ;
1585
+ }
1586
+ Local<Value> result;
1587
+ if (msg->Deserialize (env, context, nullptr ).ToLocal (&result)) {
1588
+ args.GetReturnValue ().Set (result);
1589
+ }
1590
+ }
1591
+
1531
1592
static void MessageChannel (const FunctionCallbackInfo<Value>& args) {
1532
1593
Environment* env = Environment::GetCurrent (args);
1533
1594
if (!args.IsConstructCall ()) {
@@ -1608,6 +1669,7 @@ static void InitMessaging(Local<Object> target,
1608
1669
" setDeserializerCreateObjectFunction" ,
1609
1670
SetDeserializerCreateObjectFunction);
1610
1671
SetMethod (context, target, " broadcastChannel" , BroadcastChannel);
1672
+ SetMethod (context, target, " structuredClone" , StructuredClone);
1611
1673
1612
1674
{
1613
1675
Local<Function> domexception = GetDOMException (context).ToLocalChecked ();
@@ -1631,6 +1693,7 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1631
1693
registry->Register (MessagePort::ReceiveMessage);
1632
1694
registry->Register (MessagePort::MoveToContext);
1633
1695
registry->Register (SetDeserializerCreateObjectFunction);
1696
+ registry->Register (StructuredClone);
1634
1697
}
1635
1698
1636
1699
} // anonymous namespace
0 commit comments