part of html_common; /// 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[JS('String', '#', key)] = _convertNativeToDart_Value( JS('var', '#[#]', object, key), ); } return dict; } /// Converts values that occur within a Dart map for map conversion. /// /// This includes other maps, lists, or values that don't need a conversion e.g. /// bool, String. _convertDartToNative_Value(Object? value) { if (value == null) return value; if (value is String || value is num || value is bool) return value; if (value is Map) return convertDartToNative_Dictionary(value); if (value is List) { var array = JS('var', '[]'); value.forEach((element) { JS('void', '#.push(#)', array, _convertDartToNative_Value(element)); }); value = array; } return value; } /// Converts a potentially nested Dart map to a JavaScript object with /// properties. /// /// This method requires that the values within the map are either maps /// themselves, lists, or do not need a conversion. convertDartToNative_Dictionary(Map? dict, [void postCreate(Object? f)?]) { if (dict == null) return null; var object = JS('var', '{}'); if (postCreate != null) { postCreate(object); } dict.forEach((key, value) { JS('void', '#[#] = #', object, key, _convertDartToNative_Value(value)); }); return object; } /** * Ensures that the input is a JavaScript Array. * * Creates a new JavaScript array if necessary, otherwise returns the original. */ List convertDartToNative_StringArray(List input) { // TODO(sra). Implement this. return input; } DateTime convertNativeToDart_DateTime(date) { int millisSinceEpoch = JS('int', '#.getTime()', date); return new DateTime.fromMillisecondsSinceEpoch(millisSinceEpoch, isUtc: true); } convertDartToNative_DateTime(DateTime date) { return JS('', 'new Date(#)', date.millisecondsSinceEpoch); } convertDartToNative_PrepareForStructuredClone(value) => new _StructuredCloneDart2Js().convertDartToNative_PrepareForStructuredClone( value, ); convertNativeToDart_AcceptStructuredClone(object, {mustCopy = false}) => new _AcceptStructuredCloneDart2Js() .convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy); class _StructuredCloneDart2Js extends _StructuredClone { JSObject newJsObject() => JS('JSObject', '{}'); void forEachObjectKey(object, action(key, value)) { for (final key in JS( 'returns:JSExtendableArray;new:true', 'Object.keys(#)', object, )) { action(key, JS('var', '#[#]', object, key)); } } void putIntoObject(object, key, value) => JS('void', '#[#] = #', object, key, value); newJsMap() => JS('var', '{}'); putIntoMap(map, key, value) => JS('void', '#[#] = #', map, key, value); newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length); cloneNotRequired(e) => (e is NativeByteBuffer || e is NativeTypedData || e is MessagePort || e is SharedArrayBuffer); } class _AcceptStructuredCloneDart2Js extends _AcceptStructuredClone { List newJsList(length) => JS('JSExtendableArray', 'new Array(#)', length); List newDartList(length) => newJsList(length); bool identicalInJs(a, b) => identical(a, b); void forEachJsField(object, action(key, value)) { for (final key in JS('JSExtendableArray', 'Object.keys(#)', object)) { action(key, JS('var', '#[#]', object, key)); } } } bool isJavaScriptDate(value) => JS('bool', '# instanceof Date', value); bool isJavaScriptRegExp(value) => JS('bool', '# instanceof RegExp', value); bool isJavaScriptArray(value) => JS('bool', '# instanceof Array', value); bool isJavaScriptSimpleObject(value) { var proto = JS('', 'Object.getPrototypeOf(#)', value); return JS('bool', '# === Object.prototype', proto) || JS('bool', '# === null', proto); } bool isImmutableJavaScriptArray(value) => JS('bool', r'!!(#.immutable$list)', value); bool isJavaScriptPromise(value) => JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value); const String _serializedScriptValue = 'num|String|bool|' 'JSExtendableArray|=Object|' 'Blob|File|NativeByteBuffer|NativeTypedData|MessagePort' // TODO(sra): Add Date, RegExp. ; const annotation_Creates_SerializedScriptValue = const Creates( _serializedScriptValue, ); const annotation_Returns_SerializedScriptValue = const Returns( _serializedScriptValue, );