Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 37 additions & 25 deletions packages/dragon_logs/lib/src/storage/opfs_interop.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'package:web/web.dart';

/// JavaScript async iterator result type
@JS()
@anonymous
extension type JSIteratorResult._(JSObject _) implements JSObject {
extension type JSIteratorResult<T extends JSAny?>._(JSObject _)
implements JSObject {
external bool get done;
external JSAny? get value;
external T? get value;
}

/// JavaScript async iterator type
@JS()
@anonymous
extension type JSAsyncIterator._(JSObject _) implements JSObject {
external JSPromise<JSIteratorResult> next();
extension type JSAsyncIterator<T extends JSAny?>._(JSObject _)
implements JSObject {
external JSPromise<JSIteratorResult<T>> next();
}

/// Extensions for FileSystemDirectoryHandle to provide missing async iterator methods
Expand All @@ -23,21 +24,21 @@ extension type JSAsyncIterator._(JSObject _) implements JSObject {
extension FileSystemDirectoryHandleExtension on FileSystemDirectoryHandle {
/// Returns an async iterator for the values (handles) in this directory.
/// Equivalent to calling `directoryHandle.values()` in JavaScript.
external JSAsyncIterator values();
external JSAsyncIterator<FileSystemHandle> values();

/// Returns an async iterator for the keys (names) in this directory.
/// Equivalent to calling `directoryHandle.keys()` in JavaScript.
external JSAsyncIterator keys();
external JSAsyncIterator<JSString> keys();

/// Returns an async iterator for the entries (name-handle pairs) in this directory.
/// Equivalent to calling `directoryHandle.entries()` in JavaScript.
external JSAsyncIterator entries();
external JSAsyncIterator<JSArray<JSAny?>> entries();
}

/// Helper extensions to convert JavaScript async iterators to Dart async iterables
extension JSAsyncIteratorExtension on JSAsyncIterator {
extension JSAsyncIteratorExtension<T extends JSAny?> on JSAsyncIterator<T> {
/// Converts a JavaScript async iterator to a Dart Stream
Stream<JSAny?> asStream() async* {
Stream<T?> asStream() async* {
while (true) {
final result = await next().toDart;
if (result.done) break;
Expand All @@ -49,26 +50,37 @@ extension JSAsyncIteratorExtension on JSAsyncIterator {
/// Extension to provide async iteration capabilities for FileSystemDirectoryHandle values
extension FileSystemDirectoryHandleValuesIterable on FileSystemDirectoryHandle {
/// Returns a Stream of FileSystemHandle objects for async iteration over directory contents
Stream<FileSystemHandle> valuesStream() {
return values().asStream().map((jsValue) => jsValue as FileSystemHandle);
Stream<FileSystemHandle> valuesStream() async* {
await for (final handle in values().asStream()) {
if (handle != null) {
yield handle;
}
}
}

/// Returns a Stream of file/directory names for async iteration over directory contents
Stream<String> keysStream() {
return keys().asStream().map((jsValue) => (jsValue as JSString).toDart);
Stream<String> keysStream() async* {
await for (final key in keys().asStream()) {
if (key != null) {
yield key.toDart;
}
}
}

/// Returns a Stream of [name, handle] pairs for async iteration over directory contents
static const int nameIndex = 0;
static const int handleIndex = 1;
Stream<(String, FileSystemHandle)> entriesStream() {
return entries().asStream().map((jsValue) {
// The entries() iterator returns [name, handle] arrays
// Use js_interop_unsafe to access array elements by numeric index
final jsObject = jsValue as JSObject;
final name = jsObject.getProperty<JSString>(nameIndex.toJS).toDart;
final handle = jsObject.getProperty<FileSystemHandle>(handleIndex.toJS);
return (name, handle);
});
Stream<(String, FileSystemHandle)> entriesStream() async* {
await for (final entry in entries().asStream()) {
if (entry == null || entry.length < 2) {
continue;
}

final nameValue = entry[0];
final handleValue = entry[1];
if (!nameValue.isA<JSString>() || !handleValue.isA<FileSystemHandle>()) {
continue;
}

yield (nameValue.dartify()! as String, handleValue as FileSystemHandle);
}
}
}
2 changes: 1 addition & 1 deletion packages/komodo_defi_framework/app_build/build_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"coins": {
"fetch_at_build_enabled": true,
"update_commit_on_build": true,
"bundled_coins_repo_commit": "c394bc48ba010966af83500eaae9da45a40d03d3",
"bundled_coins_repo_commit": "e027082339558cc79d653d0e871f0d211562fe2f",
"coins_repo_api_url": "https://api.github.com/repos/GLEECBTC/coins",
"coins_repo_content_url": "https://raw.githubusercontent.com/GLEECBTC/coins",
"coins_repo_branch": "master",
Expand Down
28 changes: 16 additions & 12 deletions packages/komodo_defi_framework/lib/src/js/js_interop_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import 'package:logging/logging.dart';

final Logger _jsInteropLogger = Logger('JsInteropUtils');

@js_interop.JS('Promise.resolve')
external js_interop.JSPromise<js_interop.JSAny?> _resolveJsPromise(
js_interop.JSAny? value,
);

/// Parses a JS interop response into a JsonMap.
///
/// Accepts:
Expand All @@ -16,14 +21,9 @@ final Logger _jsInteropLogger = Logger('JsInteropUtils');
/// - String (JSON encoded)
///
/// Throws a [FormatException] if the response cannot be parsed into a JSON map.
JsonMap parseJsInteropJson(dynamic jsResponse) {
JsonMap parseJsInteropJson(js_interop.JSAny? jsResponse) {
try {
dynamic value = jsResponse;

// If we received a JS value, convert to Dart first
if (value is js_interop.JSAny?) {
value = value?.dartify();
}
final dynamic value = jsResponse?.dartify();

if (value is String) {
final decoded = jsonDecode(value);
Expand All @@ -45,7 +45,10 @@ JsonMap parseJsInteropJson(dynamic jsResponse) {
}

/// Generic helper that parses a JS response and maps it to a Dart model.
T parseJsInteropCall<T>(dynamic jsResponse, T Function(JsonMap) fromJson) {
T parseJsInteropCall<T>(
js_interop.JSAny? jsResponse,
T Function(JsonMap) fromJson,
) {
final map = parseJsInteropJson(jsResponse);
return fromJson(map);
}
Expand Down Expand Up @@ -76,11 +79,12 @@ List<dynamic> _deepConvertList(List<dynamic> list) {
/// - If [jsValue] is not a JSPromise, it is dartified directly
/// - Returns the dartified dynamic value
Future<dynamic> resolveJsAnyMaybePromise(js_interop.JSAny? jsValue) async {
if (jsValue is js_interop.JSPromise) {
final resolved = await jsValue.toDart;
return resolved?.dartify();
if (jsValue == null || jsValue.isUndefinedOrNull) {
return null;
}
return jsValue?.dartify();

final resolved = await _resolveJsPromise(jsValue).toDart;
return resolved?.dartify();
}

/// Generic helper to resolve a JS interop value (maybe a Promise) and map it.
Expand Down
Loading
Loading