blob: ee64dc84ce822eb8b4ade5e86b796db4acaa8480 [file] [log] [blame]
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type_system.dart';
import 'package:build/build.dart';
import 'package:mobx_codegen/src/store_class_visitor.dart';
import 'package:mobx_codegen/src/template/store_file.dart';
import 'package:mobx_codegen/src/template/store.dart';
import 'package:mobx_codegen/src/type_names.dart';
import 'package:source_gen/source_gen.dart';
class StoreGenerator extends Generator {
@override
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async {
if (library.allElements.isEmpty) {
return '';
}
final typeSystem = library.element.typeSystem;
final file = StoreFileTemplate(
storeSources: _generateCodeForLibrary(library, typeSystem).toSet());
return file.toString();
}
Iterable<String> _generateCodeForLibrary(
LibraryReader library,
TypeSystem typeSystem,
) sync* {
for (final classElement in library.classes) {
if (isMixinStoreClass(classElement)) {
yield* _generateCodeForMixinStore(library, classElement, typeSystem);
}
}
}
Iterable<String> _generateCodeForMixinStore(
LibraryReader library,
ClassElement baseClass,
TypeSystem typeSystem,
) sync* {
final typeNameFinder = LibraryScopedNameFinder(library.element);
final otherClasses = library.classes.where((c) => c != baseClass);
try {
final mixedClass = otherClasses.firstWhere((c) {
// If our base class has different type parameterization requirements than
// the class we're evaluating provides, we know it's not a subclass.
if (baseClass.typeParameters.length !=
c.supertype!.typeArguments.length) {
return false;
}
// Apply the subclass' type arguments to the base type (if there are none
// this has no impact), and perform a supertype check.
return typeSystem.isSubtypeOf(
c.thisType,
baseClass.instantiate(
typeArguments: c.supertype!.typeArguments,
nullabilitySuffix: NullabilitySuffix.none),
);
});
yield _generateCodeFromTemplate(
mixedClass.name, baseClass, MixinStoreTemplate(), typeNameFinder);
// ignore: avoid_catching_errors
} on StateError {
// ignore the case when no element is found
}
}
String _generateCodeFromTemplate(
String publicTypeName,
ClassElement userStoreClass,
StoreTemplate template,
LibraryScopedNameFinder typeNameFinder,
) {
final visitor = StoreClassVisitor(
publicTypeName, userStoreClass, template, typeNameFinder);
userStoreClass
..accept(visitor)
..visitChildren(visitor);
return visitor.source;
}
}