generate method
Generates both reflection metadata and concrete reflector classes.
This is the main entry point that processes all libraries in the mirror system (plus any force-loaded mirrors) and generates complete reflection metadata.
Parameters:
dartFiles
: A list of Dart files to process via analyzer
Returns: A list of LibraryDeclaration objects representing the reflected libraries
Example:
final libraries = await generator.generate(dartFiles);
for (final library in libraries) {
print('Library: ${library.uri}');
for (final declaration in library.declarations) {
print(' - ${declaration.name}');
}
}
Implementation
@override
Future<List<LibraryDeclaration>> generate(List<File> dartFiles) async {
// Initialize analyzer
await _initializeAnalyzer(dartFiles);
// Initialize tree shaker if needed
if (configuration.enableTreeShaking) {
_treeShaker = TreeShaker();
}
// Create package lookup
for (final package in packages) {
_packageCache[package.getName()] = package;
}
final libraries = <LibraryDeclaration>[];
onInfo('Generating declaration metadata with analyzer integration...');
for (final libraryMirror in loader) {
final fileUri = libraryMirror.uri;
try {
final mustSkip = "jetleaf_lang/src/runtime/";
if(libraryMirror.uri.toString() == "dart:mirrors" || libraryMirror.uri.toString().startsWith("package:$mustSkip") || libraryMirror.uri.toString().contains(mustSkip)) {
continue;
}
onInfo('Processing library: ${fileUri.toString()}');
LibraryDeclaration? libDecl;
if (_isBuiltInDartLibrary(fileUri)) {
// Handle built-in Dart libraries (dart:core, dart:io, etc.)
libDecl = await _generateBuiltInLibraryDeclaration(libraryMirror);
} else {
// Handle user libraries and package libraries
if (await shouldNotIncludeLibrary(fileUri, configuration) || isSkippableJetLeafPackage(fileUri)) {
continue;
}
String? fileContent;
try {
fileContent = await _readSourceCode(fileUri);
if ((isTest(fileContent) && configuration.skipTests) || hasMirrorImport(fileContent)) {
continue;
}
} catch (e) {
onError('Could not read file content for $fileUri: $e');
continue;
}
libDecl = await generateLibrary(libraryMirror);
}
libraries.add(libDecl);
_libraryCache[fileUri.toString()] = libDecl;
} catch (e, stackTrace) {
onError('Error processing library ${fileUri.toString()}: $e\n$stackTrace');
}
}
// Apply tree-shaking if enabled
Set<String> usedClasses = {};
if (configuration.enableTreeShaking && _treeShaker != null) {
final userPackageNames = packages
.where((p) => p.getIsRootPackage())
.map((p) => p.getName())
.toSet();
usedClasses = _treeShaker!.shake(libraries, userPackageNames);
onInfo('Tree-shaking enabled: ${usedClasses.length} classes marked as used');
}
// Write declarations to files if configured
if (configuration.writeDeclarationsToFiles) {
_fileWriter = DeclarationFileWriter(configuration.outputPath);
await _fileWriter!.writeDeclarations(libraries, usedClasses, configuration.enableTreeShaking);
onInfo('Declarations written to ${configuration.outputPath}/classes/');
}
// Check for unresolved generic classes
final unresolvedClasses = libraries
.where((l) => l.getIsPublic() && !l.getIsSynthetic() && l.getPackage().getIsRootPackage())
.flatMap((l) => l.getDeclarations())
.whereType<TypeDeclaration>()
.where((d) => GenericTypeParser.shouldCheckGeneric(d.getType()) && d.getIsPublic() && !d.getIsSynthetic());
if (unresolvedClasses.isNotEmpty) {
final warningMessage = '''
⚠️ Generic Class Discovery Issue ⚠️
Found ${unresolvedClasses.length} classes with unresolved runtime types:
${unresolvedClasses.map((d) => "• ${d.getSimpleName()} (${d.getQualifiedName()})").join("\n")}
These classes may need manual type resolution or have complex generic constraints.
''';
onWarning(warningMessage);
}
return libraries;
}