diff --git a/CHANGELOG.md b/CHANGELOG.md index 70d7ff1fc2e..4722f5cb2d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ### Core libraries +### `dart:html` + +* [#44319][]: `convertNativeToDart_Dictionary()` now converts objects + recursively, this fixes APIs like MediaStreamTrack.getCapabilities + that convert between Maps and browser Dictionaries. + +[44319]: (https://github.com/dart-lang/sdk/issues/44319) + #### `dart:async` * The uncaught error handlers of `Zone`s are now run in the parent zone diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart index f0ed6d22f8b..36cf262aec8 100644 --- a/sdk/lib/html/html_common/conversions_dart2js.dart +++ b/sdk/lib/html/html_common/conversions_dart2js.dart @@ -1,14 +1,36 @@ part of html_common; -/// Converts a JavaScript object with properties into a Dart Map. -/// Not suitable for nested objects. +/// Converts native values to their Dart equivalent +/// +/// This includes other maps, lists, or values that don't need a conversion e.g. +/// bool, String. +_convertNativeToDart_Value(value) { + if (value == null) return value; + if (value is String || value is num || value is bool) return value; + if (isJavaScriptSimpleObject(value)) { + return convertNativeToDart_Dictionary(value); + } + if (JS('bool', 'Array.isArray(#)', value)) { + List values = []; + for (var i = 0; i < JS('int', '#.length', value); i++) { + values.add(_convertNativeToDart_Value(JS('var', '#[#]', value, i))); + } + + return values; + } + return value; +} + +/// Recursively converts a JavaScript object with properties into a Dart Map. +/// This includes maps, lists, and other values that don't need a conversion. Map? convertNativeToDart_Dictionary(object) { if (object == null) return null; var dict = {}; var keys = JS( 'JSExtendableArray', 'Object.getOwnPropertyNames(#)', object); for (final key in keys) { - dict[key] = JS('var', '#[#]', object, key); + dict[JS('String', '#', key)] = + _convertNativeToDart_Value(JS('var', '#[#]', object, key)); } return dict; } diff --git a/tests/lib/html/convert_native_to_dart_dictionary_test.dart b/tests/lib/html/convert_native_to_dart_dictionary_test.dart new file mode 100644 index 00000000000..b61fea1df2a --- /dev/null +++ b/tests/lib/html/convert_native_to_dart_dictionary_test.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:html_common'; +import 'package:expect/expect.dart'; +import 'package:expect/minitest.dart'; + +var obj = { + 'val1': 'hello', + 'val2': 'there', + 'val3': { + 'sub1': 'general kenobi', + 'sub2': 'you are', + 'sub3': 'a bold one', + 'sub4': { + 'nilval': null, + 'boolval': false, + } + }, + 'val4': [ + 'execute', + 'order', + '66', + {'number': 33} + ] +}; + +main() { + test('dart to native -> native to dart', () { + var toNative = convertDartToNative_Dictionary(obj); + var toDart = convertNativeToDart_Dictionary(toNative); + + Expect.deepEquals(obj, toDart); + }); +} diff --git a/tests/lib_2/html/convert_native_to_dart_dictionary_test.dart b/tests/lib_2/html/convert_native_to_dart_dictionary_test.dart new file mode 100644 index 00000000000..b61fea1df2a --- /dev/null +++ b/tests/lib_2/html/convert_native_to_dart_dictionary_test.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:html_common'; +import 'package:expect/expect.dart'; +import 'package:expect/minitest.dart'; + +var obj = { + 'val1': 'hello', + 'val2': 'there', + 'val3': { + 'sub1': 'general kenobi', + 'sub2': 'you are', + 'sub3': 'a bold one', + 'sub4': { + 'nilval': null, + 'boolval': false, + } + }, + 'val4': [ + 'execute', + 'order', + '66', + {'number': 33} + ] +}; + +main() { + test('dart to native -> native to dart', () { + var toNative = convertDartToNative_Dictionary(obj); + var toDart = convertNativeToDart_Dictionary(toNative); + + Expect.deepEquals(obj, toDart); + }); +}