blob: 7f1101da84a1f1daed9b6ffdb4b45aaf4f5f1626 [file]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:jni_gen/src/elements/elements.dart';
/// A filter which tells if bindings for given [ClassDecl] are generated.
abstract class ClassFilter {
bool included(ClassDecl decl);
}
/// This filter includes the declarations for which [predicate] returns true.
class CustomClassFilter implements ClassFilter {
CustomClassFilter(this.predicate);
final bool Function(ClassDecl) predicate;
@override
bool included(ClassDecl decl) {
return predicate(decl);
}
}
bool _matchesCompletely(String string, Pattern pattern) {
final match = pattern.matchAsPrefix(string);
return match != null && match.group(0) == string;
}
/// Filter to include / exclude classes by matching on the binary name.
/// A binary name is like qualified name but with a `$` used to indicate nested
/// class instead of `.`, guaranteeing a unique name.
class ClassNameFilter implements ClassFilter {
ClassNameFilter.include(this.pattern) : onMatch = true;
ClassNameFilter.exclude(this.pattern) : onMatch = false;
final bool onMatch;
final Pattern pattern;
@override
bool included(ClassDecl decl) {
if (_matchesCompletely(decl.binaryName, pattern)) {
return onMatch;
}
return !onMatch;
}
}
abstract class MemberFilter<T extends ClassMember> {
bool included(ClassDecl classDecl, T member);
}
class MemberNameFilter<T extends ClassMember> implements MemberFilter<T> {
MemberNameFilter.include(this.classPattern, this.namePattern)
: onMatch = true;
MemberNameFilter.exclude(this.classPattern, this.namePattern)
: onMatch = false;
final bool onMatch;
final Pattern classPattern, namePattern;
@override
bool included(ClassDecl classDecl, T member) {
final matches = _matchesCompletely(classDecl.binaryName, classPattern) &&
_matchesCompletely(member.name, namePattern);
return matches ? onMatch : !onMatch;
}
}
class CustomMemberFilter<T extends ClassMember> implements MemberFilter<T> {
CustomMemberFilter(this.predicate);
bool Function(ClassDecl, T) predicate;
@override
bool included(ClassDecl classDecl, T member) => predicate(classDecl, member);
}
class CombinedClassFilter implements ClassFilter {
CombinedClassFilter.all(this.filters);
final List<ClassFilter> filters;
@override
bool included(ClassDecl decl) => filters.every((f) => f.included(decl));
}
class CombinedMemberFilter<T extends ClassMember> implements MemberFilter<T> {
CombinedMemberFilter(this.filters);
final List<MemberFilter<T>> filters;
@override
bool included(ClassDecl decl, T member) {
return filters.every((f) => f.included(decl, member));
}
}
typedef FieldFilter = MemberFilter<Field>;
typedef MethodFilter = MemberFilter<Method>;
/// Filter using binary name of the class and name of the field.
typedef FieldNameFilter = MemberNameFilter<Field>;
/// Filter using binary name of the class and name of the method.
typedef MethodNameFilter = MemberNameFilter<Method>;
/// Predicate based filter for field, which can access class declaration
/// and the field.
typedef CustomFieldFilter = CustomMemberFilter<Field>;
/// Predicate based filter for method, which can access class declaration
/// and the method.
typedef CustomMethodFilter = CustomMemberFilter<Method>;
/// This filter excludes fields if any one of sub-filters returns false.
typedef CombinedFieldFilter = CombinedMemberFilter<Field>;
/// This filter excludes methods if any one of sub-filters returns false.
typedef CombinedMethodFilter = CombinedMemberFilter<Method>;
MemberFilter<T> excludeAll<T extends ClassMember>(List<List<Pattern>> names) {
return CombinedMemberFilter<T>(
names.map((p) => MemberNameFilter<T>.exclude(p[0], p[1])).toList());
}
/// Options that affect the semantics of the generated code.
class WrapperOptions {
const WrapperOptions({
this.classFilter,
this.fieldFilter,
this.methodFilter,
this.classTransformer,
this.methodTransformer,
this.fieldTransformer,
this.importPaths = const {},
});
/// Mapping from java package names to dart packages.
/// A mapping `a.b` -> `package:a_b/' means that
/// any import `a.b.C` will be resolved as `package:a_b/a/b.dart` in dart.
/// Note that dart bindings use the same hierarchy as the java packages.
final Map<String, String> importPaths;
/// [ClassFilter] to decide if bindings for a class should be generated.
final ClassFilter? classFilter;
/// [FieldFilter] to decide if bindings for a field should be generated.
final FieldFilter? fieldFilter;
/// [MethodFilter] to decide if bindings for a method should be generated.
final MethodFilter? methodFilter;
// TODO(#26): This allows us to implement flexible renaming and more customization
// via the dart API.
final ClassDecl? Function(ClassDecl decl)? classTransformer;
final Method? Function(Method method)? methodTransformer;
final Field? Function(Field field)? fieldTransformer;
}