blob: 001bb6ca3b64ce83241efb3c2c4384b2c0763d8a [file] [edit]
// Copyright (c) 2026, 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.
// ignore_for_file: avoid_catching_errors
import 'dart:io';
import 'package:api_summary/api_summary.dart';
import 'package:args/args.dart';
import 'package:path/path.dart' as p;
Future<void> main(List<String> arguments) async {
try {
final results = _parser.parse(arguments);
if (results.flag('help')) {
print('Usage: api_summary [options]');
print(_parser.usage);
return;
}
await _run(results);
} on ApiSummaryVerificationException catch (e) {
stderr.writeln(e.message);
exitCode = 1;
} on FormatException catch (e) {
_usageError(e.message);
} on ArgumentError catch (e) {
_usageError('${e.message}');
}
}
void _usageError(String message) {
stderr.writeln('Error: $message');
stderr.writeln('\nUsage: api_summary [options]');
stderr.writeln(_parser.usage);
exitCode = 64;
}
Future<void> _run(ArgResults results) async {
if (results.rest.isNotEmpty) {
throw FormatException(
'Unexpected positional arguments: "${results.rest.join(' ')}". '
'Use --package-path (-p) to specify a package directory.',
);
}
final packagePath = results.option('package-path') ?? Directory.current.path;
final absolutePath = p.normalize(p.absolute(packagePath));
final formatName = results.option('format')!;
final format = ApiSummaryFormat.values.byName(formatName);
switch ((
write: results.flag('write'),
check: results.flag('check'),
output: results.option('output'),
)) {
case (write: true, check: true, output: _):
throw const FormatException('Cannot specify both --write and --check.');
case (write: true, check: false, output: _?):
throw const FormatException('Cannot specify both --write and --output.');
case (write: false, check: true, output: _?):
throw const FormatException('Cannot specify both --check and --output.');
case (write: false, check: true, output: null):
await expectApiSummaryClean(packagePath: absolutePath, format: format);
case (write: false, check: false, output: null):
final package = await apiSummary(absolutePath);
stdout.write(format.format(package));
case (write: true, check: false, output: null):
final package = await apiSummary(absolutePath);
_writeOutputFile(
p.join(absolutePath, format.defaultFileName),
format.format(package),
);
case (write: false, check: false, output: final outputPath?):
final package = await apiSummary(absolutePath);
final targetPath = p.isAbsolute(outputPath)
? p.normalize(outputPath)
: p.normalize(p.join(absolutePath, outputPath));
_writeOutputFile(targetPath, format.format(package));
}
}
void _writeOutputFile(String targetPath, String content) {
final outFile = File(targetPath);
outFile.parent.createSync(recursive: true);
outFile.writeAsStringSync(content);
}
final _parser = ArgParser()
..addOption(
'package-path',
abbr: 'p',
help:
'The path to the package to summarize. Defaults to the current '
'directory.',
)
..addOption(
'format',
abbr: 'f',
help: 'The output format for the summary.',
allowed: [for (final f in ApiSummaryFormat.values) f.name],
defaultsTo: ApiSummaryFormat.text.name,
)
..addOption(
'output',
abbr: 'o',
help: 'Write the summary to a file path instead of stdout.',
)
..addFlag(
'write',
abbr: 'w',
help:
'Write the summary to the default golden file (api.txt, api.json, or '
'api.yaml) in the package directory.',
negatable: false,
)
..addFlag(
'check',
abbr: 'c',
help:
'Verify that the golden file (api.txt, api.json, or api.yaml) matches '
'the current public API.',
negatable: false,
)
..addFlag(
'help',
abbr: 'h',
help: 'Print this usage information.',
negatable: false,
);