@@ -1008,6 +1008,47 @@ static Maybe<bool> ReadIterable(Environment* env,
1008
1008
return Just (true );
1009
1009
}
1010
1010
1011
+ bool GetTransferList (Environment* env,
1012
+ Local<Context> context,
1013
+ Local<Value> transfer_list_v,
1014
+ TransferList* transfer_list_out) {
1015
+ if (transfer_list_v->IsNullOrUndefined ()) {
1016
+ // Browsers ignore null or undefined, and otherwise accept an array or an
1017
+ // options object.
1018
+ return true ;
1019
+ }
1020
+
1021
+ if (!transfer_list_v->IsObject ()) {
1022
+ THROW_ERR_INVALID_ARG_TYPE (
1023
+ env, " Optional transferList argument must be an iterable" );
1024
+ return false ;
1025
+ }
1026
+
1027
+ bool was_iterable;
1028
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_list_v)
1029
+ .To (&was_iterable))
1030
+ return false ;
1031
+ if (!was_iterable) {
1032
+ Local<Value> transfer_option;
1033
+ if (!transfer_list_v.As <Object>()
1034
+ ->Get (context, env->transfer_string ())
1035
+ .ToLocal (&transfer_option))
1036
+ return false ;
1037
+ if (!transfer_option->IsUndefined ()) {
1038
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_option)
1039
+ .To (&was_iterable))
1040
+ return false ;
1041
+ if (!was_iterable) {
1042
+ THROW_ERR_INVALID_ARG_TYPE (
1043
+ env, " Optional options.transfer argument must be an iterable" );
1044
+ return false ;
1045
+ }
1046
+ }
1047
+ }
1048
+
1049
+ return true ;
1050
+ }
1051
+
1011
1052
void MessagePort::PostMessage (const FunctionCallbackInfo<Value>& args) {
1012
1053
Environment* env = Environment::GetCurrent (args);
1013
1054
Local<Object> obj = args.This ();
@@ -1018,33 +1059,10 @@ void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) {
1018
1059
" MessagePort.postMessage" );
1019
1060
}
1020
1061
1021
- if (!args[1 ]->IsNullOrUndefined () && !args[1 ]->IsObject ()) {
1022
- // Browsers ignore null or undefined, and otherwise accept an array or an
1023
- // options object.
1024
- return THROW_ERR_INVALID_ARG_TYPE (env,
1025
- " Optional transferList argument must be an iterable" );
1026
- }
1027
-
1028
1062
TransferList transfer_list;
1029
- if (args[1 ]->IsObject ()) {
1030
- bool was_iterable;
1031
- if (!ReadIterable (env, context, transfer_list, args[1 ]).To (&was_iterable))
1032
- return ;
1033
- if (!was_iterable) {
1034
- Local<Value> transfer_option;
1035
- if (!args[1 ].As <Object>()->Get (context, env->transfer_string ())
1036
- .ToLocal (&transfer_option)) return ;
1037
- if (!transfer_option->IsUndefined ()) {
1038
- if (!ReadIterable (env, context, transfer_list, transfer_option)
1039
- .To (&was_iterable)) return ;
1040
- if (!was_iterable) {
1041
- return THROW_ERR_INVALID_ARG_TYPE (env,
1042
- " Optional options.transfer argument must be an iterable" );
1043
- }
1044
- }
1045
- }
1063
+ if (!GetTransferList (env, context, args[1 ], &transfer_list)) {
1064
+ return ;
1046
1065
}
1047
-
1048
1066
MessagePort* port = Unwrap<MessagePort>(args.This ());
1049
1067
// Even if the backing MessagePort object has already been deleted, we still
1050
1068
// want to serialize the message to ensure spec-compliant behavior w.r.t.
@@ -1535,6 +1553,48 @@ static void SetDeserializerCreateObjectFunction(
1535
1553
env->set_messaging_deserialize_create_object (args[0 ].As <Function>());
1536
1554
}
1537
1555
1556
+ static void StructuredClone (const FunctionCallbackInfo<Value>& args) {
1557
+ Isolate* isolate = args.GetIsolate ();
1558
+ Local<Context> context = isolate->GetCurrentContext ();
1559
+ Realm* realm = Realm::GetCurrent (context);
1560
+ Environment* env = realm->env ();
1561
+
1562
+ if (args.Length () == 0 ) {
1563
+ return THROW_ERR_MISSING_ARGS (env, " The value argument must be specified" );
1564
+ }
1565
+
1566
+ Local<Value> value = args[0 ];
1567
+
1568
+ TransferList transfer_list;
1569
+ if (!args[1 ]->IsNullOrUndefined ()) {
1570
+ if (!args[1 ]->IsObject ()) {
1571
+ return THROW_ERR_INVALID_ARG_TYPE (
1572
+ env, " The options argument must be either an object or undefined" );
1573
+ }
1574
+ Local<Object> options = args[1 ].As <Object>();
1575
+ Local<Value> transfer_list_v;
1576
+ if (!options->Get (context, env->transfer_string ())
1577
+ .ToLocal (&transfer_list_v)) {
1578
+ return ;
1579
+ }
1580
+
1581
+ // TODO(joyeecheung): implement this in JS land to avoid the C++ -> JS
1582
+ // cost to convert a sequence into an array.
1583
+ if (!GetTransferList (env, context, transfer_list_v, &transfer_list)) {
1584
+ return ;
1585
+ }
1586
+ }
1587
+
1588
+ std::shared_ptr<Message> msg = std::make_shared<Message>();
1589
+ Local<Value> result;
1590
+ if (msg->Serialize (env, context, value, transfer_list, Local<Object>())
1591
+ .IsNothing () ||
1592
+ !msg->Deserialize (env, context, nullptr ).ToLocal (&result)) {
1593
+ return ;
1594
+ }
1595
+ args.GetReturnValue ().Set (result);
1596
+ }
1597
+
1538
1598
static void MessageChannel (const FunctionCallbackInfo<Value>& args) {
1539
1599
Environment* env = Environment::GetCurrent (args);
1540
1600
if (!args.IsConstructCall ()) {
@@ -1615,6 +1675,7 @@ static void InitMessaging(Local<Object> target,
1615
1675
" setDeserializerCreateObjectFunction" ,
1616
1676
SetDeserializerCreateObjectFunction);
1617
1677
SetMethod (context, target, " broadcastChannel" , BroadcastChannel);
1678
+ SetMethod (context, target, " structuredClone" , StructuredClone);
1618
1679
1619
1680
{
1620
1681
Local<Function> domexception = GetDOMException (context).ToLocalChecked ();
@@ -1638,6 +1699,7 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1638
1699
registry->Register (MessagePort::ReceiveMessage);
1639
1700
registry->Register (MessagePort::MoveToContext);
1640
1701
registry->Register (SetDeserializerCreateObjectFunction);
1702
+ registry->Register (StructuredClone);
1641
1703
}
1642
1704
1643
1705
} // anonymous namespace
0 commit comments