toBridgedClass method
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.',
);
}