Skip to content

feat(generator): support map-like and pair-iterable types#533

Draft
kevmoo wants to merge 4 commits intomainfrom
iterable_map_rebased
Draft

feat(generator): support map-like and pair-iterable types#533
kevmoo wants to merge 4 commits intomainfrom
iterable_map_rebased

Conversation

@kevmoo
Copy link
Copy Markdown
Member

@kevmoo kevmoo commented Apr 19, 2026

  • Automatically generate JSIterable implementations for types defined as iterable in Web IDL.
  • Generate asMap views for map-like types in js_interop_gen (e.g., URLSearchParams, FormData, Headers).
  • Generate toDart getters for pair-iterable types like XRHand.
  • Bump minimum SDK constraint to ^3.12.0-0 across packages to support new features like private named parameters.
  • Update CI workflows to test on beta and dev instead of 3.10.
  • Fix test failures related to SDK version string checks.
  • Clean up refactorings in translator.dart to preserve followedBy style for review.

- Automatically generate `JSIterable` implementations for types defined as iterable in Web IDL.
- Generate `asMap` views for map-like types in `js_interop_gen` (e.g., `URLSearchParams`, `FormData`, `Headers`).
- Generate `toDart` getters for pair-iterable types like `XRHand`.
- Bump minimum SDK constraint to `^3.12.0-0` across packages to support new features like private named parameters.
- Update CI workflows to test on `beta` and `dev` instead of `3.10`.
- Fix test failures related to SDK version string checks.
- Clean up refactorings in `translator.dart` to preserve `followedBy` style for review.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements automatic generation of JSIterable implementations and asMap views for Web IDL types, significantly improving the Dart developer experience for interfaces like Headers, FormData, and URLSearchParams. The generator was updated to handle multiple inheritance for JS types, and the SDK requirement was bumped to 3.12.0. Review feedback highlights several correctness issues in the generated map view classes, specifically regarding improper type casting of keys, missing conversions to JS types for interop calls, and potential null-safety crashes in the operator [] and remove implementations.

Comment on lines +1570 to +1582
..body = code.Code(
valueType.symbol == 'JSArray'
? '''
final k = key as $keyCastType;
final value = _jsObject.get(k);
if (value == null) return null;
return _jsObject.getAll(k);
'''
: '''
final value = _jsObject.get(key as $keyCastType);
return $getConversion;
''',
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The implementation of operator [] in the generated map view has several correctness issues:

  1. Incorrect Cast: It uses key as $keyCastType. If $keyCastType is an interop type like JSString (which happens when isFromIterable is false) and the user passes a Dart String, this will throw a TypeError. It should cast to the Dart type (keyType.symbol) instead.
  2. Missing Type Safety: Per Dart Map conventions, operator [] should return null if the key is not of the expected type, rather than throwing an exception.
  3. Missing JS Conversion: It passes the key directly to _jsObject.get(). If the interop method expects a JSString, it needs to be converted (e.g., via .toJS).
  4. Null Safety: In the else block, it doesn't check if value is null before applying $getConversion. If $getConversion involves a call like .toDartDouble, it will crash on missing keys.

Comment on lines +1612 to +1617
? code.Code('''
final keys = _jsObject.keys().toDartIterable.toList();
for (final k in keys) {
_jsObject.delete(${_toDartCall('k', keyInteropType.symbol)});
}
''')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In the clear() implementation for synthesized maps, the key k is incorrectly converted to a Dart type before being passed to _jsObject.delete(). Since k is obtained from toDartIterable on a JSIterator, it is already of the interop type (e.g., JSString). Converting it to a Dart String will cause the delete call to fail if it expects the interop type.

        ..body = info.isFromIterable
            ? code.Code('''
final keys = _jsObject.keys().toDartIterable.toList();
for (final k in keys) {
  _jsObject.delete(k);
}
''')
            : const code.Code('_jsObject.clear();'),

Comment on lines +1647 to +1662
valueType.symbol == 'JSArray'
? '''
final k = key as $keyCastType;
final values = _jsObject.getAll(k);
// ignore: prefer_is_empty
if (values.length == 0) return null;
_jsObject.delete(k);
return values;
'''
: '''
final k = key as $keyCastType;
final value = _jsObject.get(k);
_jsObject.delete(k);
return $getConversion;
''',
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The remove implementation suffers from the same issues as operator []: it uses an incorrect cast for the key, lacks a type check to return null gracefully, and misses the necessary conversion to JS types for the interop call.

Comment on lines +1509 to +1511
final keyConversion = info.isFromIterable
? 'key'
: _toJSCall('key', keyInteropType.symbol);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The keyConversion logic for isFromIterable types should still utilize _toJSCall. Even if the map is synthesized from an iterable, the underlying interop methods (like get or delete) may still expect JS types (like JSString) rather than Dart primitives.

    final keyConversion = _toJSCall('key', keyInteropType.symbol);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant