main function
Implementation
Future<void> main(List<String> args) async {
// Set up command line argument parser
final parser = DocGeneratorCommand().argParser;
final argResults = parser.parse(args);
if (argResults['help'] as bool) {
print('Documentation Generator');
print('Usage: dart doc_generator.dart [options]');
print(parser.usage);
return;
}
final paths = argResults['path'] as List<String>;
final outputPath = argResults['output'] as String;
// Collect and analyze Dart files
final dartFiles = <File>[];
for (final path in paths) {
final directory = Directory(path);
if (await directory.exists()) {
await for (final entity in directory.list(recursive: true)) {
if (entity is File && entity.path.endsWith('.dart')) {
dartFiles.add(entity);
}
}
} else {
print('Warning: Directory does not exist: $path');
}
}
if (dartFiles.isEmpty) {
print('No Dart files found in the specified paths.');
return;
}
print('Found ${dartFiles.length} Dart files to analyze.');
final normalizedPaths = paths.map((path) {
final dir = Directory(path);
return p.normalize(dir.absolute.path);
}).toList();
final contextCollection = AnalysisContextCollection(
includedPaths: normalizedPaths,
);
final classes = <DocComponent>[];
// Analyze each file
for (final file in dartFiles) {
final path = p.normalize(file.absolute.path);
if (path.endsWith('.g.dart')) {
continue; // Skip generated files, as they are not API-related
}
try {
final context = contextCollection.contextFor(path);
final library = await context.currentSession.getResolvedLibrary(path);
if (library is! ResolvedLibraryResult) {
throw StateError('Library not resolved.');
}
final classesInLibrary = LibraryReader(library.element).classes;
for (final classItem in classesInLibrary) {
classes.add(DocComponent(
name: classItem.name,
isNullSafe: true,
description:
classItem.documentationComment?.replaceAll("///", "") ?? "",
constructors: classItem.constructors
.map((e) => DocConstructor(
name: e.name.toString(),
signature: e.parameters
.map((param) => DocParameter(
description: param.documentationComment ?? "",
name: param.name.toString(),
type: param.type.toString(),
named: param.isNamed,
required: param.isRequired,
))
.toList(),
features: [
if (e.isConst) "const",
if (e.isFactory) "factory",
if (e.isExternal) "external",
],
))
.toList(),
properties: classItem.fields
.map((e) => DocProperty(
name: e.name.toString(),
type: e.type.toString(),
description: e.documentationComment ?? "",
features: [
if (e.isStatic) "static",
if (e.isCovariant) "covariant",
if (e.isFinal) "final",
if (e.isConst) "const",
if (e.isLate) "late",
],
))
.toList(),
methods: classItem.methods.map((e) => e.name.toString()).toList(),
));
}
} catch (e) {
print('Error analyzing file ${file.path}: $e');
}
}
print('Found ${classes.length} classes.');
// Generate output
final outputLibrary = Library((libraryBuilder) {
libraryBuilder.body.add(Field((field) => field
..name = "docComponents"
..modifier = FieldModifier.constant
..assignment = literalList([
for (final classItem in classes)
refer("DocComponent").newInstance([], {
"name": literalString(classItem.name),
"isNullSafe": literalBool(classItem.isNullSafe),
"description": literalString(classItem.description),
"properties": literalList(classItem.properties
.map((e) => refer("DocProperty").newInstance([], {
"name": literalString(e.name),
"type": literalString(e.type),
"description": literalString(e.description),
"features": literalList(
e.features.map((e) => literalString(e)).toList()),
}))
.toList()),
"constructors": literalList(classItem.constructors
.map((e) => refer("DocConstructor").newInstance([], {
"name": literalString(e.name),
"signature": literalList(e.signature
.map((e) => refer("DocParameter").newInstance(
[],
{
"name": literalString(e.name),
"type": literalString(e.type),
"description": literalString(e.description),
"named": literalBool(e.named),
"required": literalBool(e.required),
},
))
.toList()),
"features": literalList(
e.features.map((e) => literalString(e)).toList()),
}))
.toList()),
"methods": literalList(
classItem.methods.map((e) => literalString(e)).toList()),
})
]).code));
});
final emitter = DartEmitter.scoped();
final output = DartFormatter().format('${outputLibrary.accept(emitter)}');
// Write output file
File(outputPath).writeAsStringSync(libraryTypes + "\n" + output);
print('Generated documentation file: $outputPath');
}