run method
Runs this command.
The return value is wrapped in a Future if necessary and returned by
CommandRunner.runCommand.
Implementation
@override
Future<int> run() async {
final logger = Logger();
final rest = argResults?.rest ?? const [];
final targetPath = rest.isEmpty ? '.' : rest.first;
final absolutePath = p.absolute(targetPath);
if (!Directory(absolutePath).existsSync()) {
logger.err('Directory not found: $absolutePath');
return 1;
}
final outputFormat = argResults!['output'] as String;
final reportFile = argResults!['report-file'] as String?;
final failOnError = argResults!['fail-on-error'] as bool;
final isJson = outputFormat == 'json';
final isHtml = outputFormat == 'html';
final isQuiet = isJson; // JSON goes to stdout — keep progress UI quiet.
final stopwatch = Stopwatch()..start();
// ----- Scan -----
final scanProgress = isQuiet ? null : logger.progress('Scanning project');
final scanner = Scanner();
final files = await scanner.scan(absolutePath);
scanProgress?.complete('Scanned ${files.length} Dart files');
if (files.isEmpty) {
if (!isJson) logger.warn('No Dart files found in $absolutePath');
return 0;
}
// ----- Parse -----
final parseProgress = isQuiet ? null : logger.progress('Parsing AST');
final parser = Parser();
final parsed = await parser.parseAll(files);
parseProgress?.complete('Parsed ${parsed.length} files');
// ----- Run rules -----
final rules = defaultRules();
final ruleProgress = isQuiet
? null
: logger.progress('Running ${rules.length} rules');
final engine = RulesEngine(rules);
final issues = engine.run(parsed);
ruleProgress?.complete('Found ${issues.length} issues');
// ----- Score & build report -----
final scores = ScoreCalculator().compute(issues);
final totalLines = parsed.fold<int>(0, (sum, f) => sum + f.lineCount);
stopwatch.stop();
final report = Report(
projectName: p.basename(absolutePath),
filesScanned: parsed.length,
linesAnalyzed: totalLines,
elapsed: stopwatch.elapsed,
issues: issues,
scores: scores,
timestamp: DateTime.now(),
);
// ----- Render -----
if (isHtml) {
final outPath = reportFile ?? 'flutter_audit_report.html';
final outFile = File(outPath);
await outFile.writeAsString(
HtmlReporter(projectRoot: absolutePath).render(report),
);
logger.info('');
logger.info('HTML report written to ${outFile.absolute.path}');
} else if (isJson) {
if (reportFile != null) {
await File(reportFile).writeAsString(JsonReporter().render(report));
} else {
stdout.write(JsonReporter().render(report));
stdout.writeln();
}
} else {
TerminalReporter(
projectRoot: absolutePath,
logger: logger,
).render(report);
}
// ----- Exit code -----
if (failOnError) {
final hasSerious = issues.any(
(i) => i.severity == Severity.error || i.severity == Severity.critical,
);
if (hasSerious) return 2;
}
return 0;
}