@@ -999,6 +999,47 @@ static Maybe<bool> ReadIterable(Environment* env,
999
999
return Just (true );
1000
1000
}
1001
1001
1002
+ bool GetTransferList (Environment* env,
1003
+ Local<Context> context,
1004
+ Local<Value> transfer_list_v,
1005
+ TransferList* transfer_list_out) {
1006
+ if (transfer_list_v->IsNullOrUndefined ()) {
1007
+ // Browsers ignore null or undefined, and otherwise accept an array or an
1008
+ // options object.
1009
+ return true ;
1010
+ }
1011
+
1012
+ if (!transfer_list_v->IsObject ()) {
1013
+ THROW_ERR_INVALID_ARG_TYPE (
1014
+ env, " Optional transferList argument must be an iterable" );
1015
+ return false ;
1016
+ }
1017
+
1018
+ bool was_iterable;
1019
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_list_v)
1020
+ .To (&was_iterable))
1021
+ return false ;
1022
+ if (!was_iterable) {
1023
+ Local<Value> transfer_option;
1024
+ if (!transfer_list_v.As <Object>()
1025
+ ->Get (context, env->transfer_string ())
1026
+ .ToLocal (&transfer_option))
1027
+ return false ;
1028
+ if (!transfer_option->IsUndefined ()) {
1029
+ if (!ReadIterable (env, context, *transfer_list_out, transfer_option)
1030
+ .To (&was_iterable))
1031
+ return false ;
1032
+ if (!was_iterable) {
1033
+ THROW_ERR_INVALID_ARG_TYPE (
1034
+ env, " Optional options.transfer argument must be an iterable" );
1035
+ return false ;
1036
+ }
1037
+ }
1038
+ }
1039
+
1040
+ return true ;
1041
+ }
1042
+
1002
1043
void MessagePort::PostMessage (const FunctionCallbackInfo<Value>& args) {
1003
1044
Environment* env = Environment::GetCurrent (args);
1004
1045
Local<Object> obj = args.This ();
@@ -1009,33 +1050,10 @@ void MessagePort::PostMessage(const FunctionCallbackInfo<Value>& args) {
1009
1050
" MessagePort.postMessage" );
1010
1051
}
1011
1052
1012
- if (!args[1 ]->IsNullOrUndefined () && !args[1 ]->IsObject ()) {
1013
- // Browsers ignore null or undefined, and otherwise accept an array or an
1014
- // options object.
1015
- return THROW_ERR_INVALID_ARG_TYPE (env,
1016
- " Optional transferList argument must be an iterable" );
1017
- }
1018
-
1019
1053
TransferList transfer_list;
1020
- if (args[1 ]->IsObject ()) {
1021
- bool was_iterable;
1022
- if (!ReadIterable (env, context, transfer_list, args[1 ]).To (&was_iterable))
1023
- return ;
1024
- if (!was_iterable) {
1025
- Local<Value> transfer_option;
1026
- if (!args[1 ].As <Object>()->Get (context, env->transfer_string ())
1027
- .ToLocal (&transfer_option)) return ;
1028
- if (!transfer_option->IsUndefined ()) {
1029
- if (!ReadIterable (env, context, transfer_list, transfer_option)
1030
- .To (&was_iterable)) return ;
1031
- if (!was_iterable) {
1032
- return THROW_ERR_INVALID_ARG_TYPE (env,
1033
- " Optional options.transfer argument must be an iterable" );
1034
- }
1035
- }
1036
- }
1054
+ if (!GetTransferList (env, context, args[1 ], &transfer_list)) {
1055
+ return ;
1037
1056
}
1038
-
1039
1057
MessagePort* port = Unwrap<MessagePort>(args.This ());
1040
1058
// Even if the backing MessagePort object has already been deleted, we still
1041
1059
// want to serialize the message to ensure spec-compliant behavior w.r.t.
@@ -1472,6 +1490,48 @@ static void SetDeserializerCreateObjectFunction(
1472
1490
env->set_messaging_deserialize_create_object (args[0 ].As <Function>());
1473
1491
}
1474
1492
1493
+ static void StructuredClone (const FunctionCallbackInfo<Value>& args) {
1494
+ Isolate* isolate = args.GetIsolate ();
1495
+ Local<Context> context = isolate->GetCurrentContext ();
1496
+ Realm* realm = Realm::GetCurrent (context);
1497
+ Environment* env = realm->env ();
1498
+
1499
+ if (args.Length () == 0 ) {
1500
+ return THROW_ERR_MISSING_ARGS (env, " The value argument must be specified" );
1501
+ }
1502
+
1503
+ Local<Value> value = args[0 ];
1504
+
1505
+ TransferList transfer_list;
1506
+ if (!args[1 ]->IsNullOrUndefined ()) {
1507
+ if (!args[1 ]->IsObject ()) {
1508
+ return THROW_ERR_INVALID_ARG_TYPE (
1509
+ env, " The options argument must be either an object or undefined" );
1510
+ }
1511
+ Local<Object> options = args[1 ].As <Object>();
1512
+ Local<Value> transfer_list_v;
1513
+ if (!options->Get (context, env->transfer_string ())
1514
+ .ToLocal (&transfer_list_v)) {
1515
+ return ;
1516
+ }
1517
+
1518
+ // TODO(joyeecheung): implement this in JS land to avoid the C++ -> JS
1519
+ // cost to convert a sequence into an array.
1520
+ if (!GetTransferList (env, context, transfer_list_v, &transfer_list)) {
1521
+ return ;
1522
+ }
1523
+ }
1524
+
1525
+ std::shared_ptr<Message> msg = std::make_shared<Message>();
1526
+ Local<Value> result;
1527
+ if (msg->Serialize (env, context, value, transfer_list, Local<Object>())
1528
+ .IsNothing () ||
1529
+ !msg->Deserialize (env, context, nullptr ).ToLocal (&result)) {
1530
+ return ;
1531
+ }
1532
+ args.GetReturnValue ().Set (result);
1533
+ }
1534
+
1475
1535
static void MessageChannel (const FunctionCallbackInfo<Value>& args) {
1476
1536
Environment* env = Environment::GetCurrent (args);
1477
1537
if (!args.IsConstructCall ()) {
@@ -1554,6 +1614,7 @@ static void InitMessaging(Local<Object> target,
1554
1614
" setDeserializerCreateObjectFunction" ,
1555
1615
SetDeserializerCreateObjectFunction);
1556
1616
SetMethod (context, target, " broadcastChannel" , BroadcastChannel);
1617
+ SetMethod (context, target, " structuredClone" , StructuredClone);
1557
1618
1558
1619
{
1559
1620
Local<Function> domexception = GetDOMException (context).ToLocalChecked ();
@@ -1578,6 +1639,7 @@ static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1578
1639
registry->Register (MessagePort::ReceiveMessage);
1579
1640
registry->Register (MessagePort::MoveToContext);
1580
1641
registry->Register (SetDeserializerCreateObjectFunction);
1642
+ registry->Register (StructuredClone);
1581
1643
}
1582
1644
1583
1645
} // anonymous namespace
0 commit comments