toBridgedClass method

BridgedClass toBridgedClass(
  1. Type nativeType
)

Implementation

BridgedClass toBridgedClass(Type nativeType) {
  // Search current environment and enclosing ones
  Environment? current = this;
  while (current != null) {
    BridgedClass? bridgedClass =
        current._bridgedClassesLookupByType[nativeType];

    String nativeTypeName = nativeType.toString();

    if (bridgedClass == null && (nativeTypeName.substring(0, 1) == '_')) {
      if (nativeTypeName.endsWith('Impl')) {
        nativeTypeName = nativeTypeName.substringBeforeLast('Impl');
      }
      // Cluster HASHSET FIX: when matching nativeNames by prefix, choose the
      // LONGEST matching nativeName so a more-specific bridge (e.g. Iterator
      // with `_HashSetIterator` in nativeNames) wins over a less-specific
      // bridge whose nativeName is a shorter prefix (e.g. Set's `_HashSet`).
      // Mirror of tom_d4rt/lib/src/environment.dart.
      final cleanedName = nativeTypeName.substring(1).substringBefore('<');
      bridgedClass = current._bridgedClassesLookupByType.entries
          .firstWhereOrNull((e) => e.value.name == cleanedName)
          ?.value;
      bridgedClass ??= _longestNativeNamePrefixMatch(current, nativeTypeName);
    } else if (bridgedClass == null && nativeTypeName.contains('<')) {
      // Extract the base type name before '<' for accurate matching.
      // Using contains() was too broad — e.g., 'ListMapView<int>'.contains('View<')
      // would falsely match the Flutter View widget bridge.
      final baseTypeName = nativeTypeName.substring(
        0,
        nativeTypeName.indexOf('<'),
      );
      bridgedClass = current._bridgedClassesLookupByType.entries
          .firstWhereOrNull(
            (e) =>
                baseTypeName == e.value.name ||
                (e.value.nativeNames?.contains(baseTypeName) ?? false),
          )
          ?.value;
      // Suffix match fallback: e.g., CastList → List, ListIterator → Iterator
      // Handles types that embed the bridge name as a suffix.
      bridgedClass ??= current._bridgedClassesLookupByType.entries
          .firstWhereOrNull(
            (e) =>
                e.value.name.length >= 3 &&
                baseTypeName.endsWith(e.value.name) &&
                baseTypeName.length > e.value.name.length,
          )
          ?.value;
    }
    bridgedClass ??= current._bridgedClassesLookupByType.entries
        .firstWhereOrNull((e) => e.value.name == nativeTypeName)
        ?.value;
    // Cluster HASHSET FIX: pick the LONGEST nativeName prefix so a
    // specific bridge wins over a less-specific bridge whose nativeName
    // is a shorter prefix.
    bridgedClass ??= _longestNativeNamePrefixMatch(current, nativeTypeName);

    // G-DCLI-05 FIX: Handle non-underscore implementation types like
    // ProgressBothImpl, where the class name contains the bridge name.
    // Check if any registered bridge name is a prefix of the native type name.
    // e.g., "ProgressBothImpl" contains bridge name "Progress"
    if (bridgedClass == null) {
      bridgedClass = current._bridgedClassesLookupByType.entries
          .firstWhereOrNull((e) {
            final bridgeName = e.value.name;
            // Only match if the bridge name is a substantial prefix (>= 3 chars)
            // and the native type name starts with it followed by more chars
            return bridgeName.length >= 3 &&
                nativeTypeName.startsWith(bridgeName) &&
                nativeTypeName.length > bridgeName.length;
          })
          ?.value;
      if (bridgedClass != null) {
        Logger.debug(
          "[Environment] Matched native type '$nativeTypeName' to bridge '${bridgedClass.name}' via prefix matching",
        );
      }
    }

    if (bridgedClass != null) {
      return bridgedClass;
    }

    current = current._enclosing;
  }

  throw RuntimeD4rtException(
    'Cannot bridge native object: No registered bridged class found for native type $nativeType.',
  );
}