From 8cbab52eebd3e80cf405bae845e378b3e45a8bfa Mon Sep 17 00:00:00 2001 From: Hampus Lavin Date: Wed, 13 Nov 2024 15:50:18 +0100 Subject: [PATCH 1/2] feat: add docs generator --- lib/cli_tools.dart | 1 + lib/docs_generator.dart | 1 + .../documentation_generator.dart | 42 +++++ lib/src/logger/loggers/void_logger.dart | 2 +- .../generate_markdown_test.dart | 160 ++++++++++++++++++ 5 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 lib/docs_generator.dart create mode 100644 lib/src/documentation_generator/documentation_generator.dart create mode 100644 test/documentation_generator/generate_markdown_test.dart diff --git a/lib/cli_tools.dart b/lib/cli_tools.dart index 7b0cda6..3610fe4 100644 --- a/lib/cli_tools.dart +++ b/lib/cli_tools.dart @@ -5,3 +5,4 @@ export 'better_command_runner.dart'; export 'local_storage_manager.dart'; export 'logger.dart'; export 'package_version.dart'; +export 'docs_generator.dart'; diff --git a/lib/docs_generator.dart b/lib/docs_generator.dart new file mode 100644 index 0000000..eec2e22 --- /dev/null +++ b/lib/docs_generator.dart @@ -0,0 +1 @@ +export 'src/documentation_generator/documentation_generator.dart'; diff --git a/lib/src/documentation_generator/documentation_generator.dart b/lib/src/documentation_generator/documentation_generator.dart new file mode 100644 index 0000000..3988e9f --- /dev/null +++ b/lib/src/documentation_generator/documentation_generator.dart @@ -0,0 +1,42 @@ +import '../../better_command_runner.dart'; + +class CommandDocumentationGenerator { + final BetterCommandRunner commandRunner; + + CommandDocumentationGenerator(this.commandRunner); + + Map generateMarkdown() { + var commands = commandRunner.commands.values; + + var files = {}; + + for (var command in commands) { + StringBuffer markdown = StringBuffer(); + markdown.writeln('## Usage\n'); + + if (command.argParser.options.isNotEmpty) { + markdown.writeln('```console'); + markdown.writeln(command.usage); + markdown.writeln('```\n'); + } + + if (command.subcommands.isNotEmpty) { + var numberOfSubcommands = command.subcommands.length; + markdown.writeln('### Sub commands\n'); + for (var (i, subcommand) in command.subcommands.entries.indexed) { + markdown.writeln('#### `${subcommand.key}`\n'); + markdown.writeln('```console'); + markdown.writeln(subcommand.value.usage); + markdown.writeln('```'); + if (i < numberOfSubcommands - 1) { + markdown.writeln(); + } + } + } + + files['${command.name}.md'] = markdown.toString(); + } + + return files; + } +} diff --git a/lib/src/logger/loggers/void_logger.dart b/lib/src/logger/loggers/void_logger.dart index afeaf03..3f9f974 100644 --- a/lib/src/logger/loggers/void_logger.dart +++ b/lib/src/logger/loggers/void_logger.dart @@ -7,7 +7,7 @@ class VoidLogger extends Logger { VoidLogger() : super(LogLevel.debug); @override - int? get wrapTextColumn => null; + int? get wrapTextColumn => 80; @override void debug( diff --git a/test/documentation_generator/generate_markdown_test.dart b/test/documentation_generator/generate_markdown_test.dart new file mode 100644 index 0000000..de7a81c --- /dev/null +++ b/test/documentation_generator/generate_markdown_test.dart @@ -0,0 +1,160 @@ +import 'package:args/command_runner.dart'; +import 'package:cli_tools/cli_tools.dart'; +import 'package:test/test.dart'; + +class AddSpiceCommand extends Command { + @override + final String name = 'add'; + + @override + final String description = 'Add something to the spice mix'; + + AddSpiceCommand() { + argParser.addOption('curry', help: 'Include curry in the spice mix.'); + argParser.addOption('pepper', help: 'Include pepper in the spice mix.'); + } + + @override + void run() {} +} + +class RemoveSpiceCommand extends Command { + @override + final String name = 'remove'; + + @override + final String description = 'Remove something from the spice mix'; + + RemoveSpiceCommand() { + argParser.addOption('curry', help: 'Remove curry from the spice mix.'); + argParser.addOption('pepper', help: 'Remove pepper from the spice mix.'); + } + + @override + void run() {} +} + +class AddVegetableCommand extends Command { + @override + final String name = 'add'; + + @override + final String description = 'Add a vegetable to your dish.'; + + AddVegetableCommand() { + argParser.addOption('carrot', help: 'Adds a fresh carrot to the dish.'); + } + + @override + void run() {} +} + +class SpiceCommand extends BetterCommand { + @override + final String name = 'spice'; + + @override + final String description = 'Modifies the spice mix in your dish.'; + + SpiceCommand() { + addSubcommand(AddSpiceCommand()); + addSubcommand(RemoveSpiceCommand()); + } + + @override + void run() {} +} + +class VegetableCommand extends BetterCommand { + @override + final String name = 'vegetable'; + + @override + final String description = 'Add or remove vegatables to your dish.'; + + VegetableCommand() { + addSubcommand(AddVegetableCommand()); + } + + @override + void run() {} +} + +void main() { + group('Given commands when generating markdown', () { + late Map output; + + setUpAll(() async { + var commandRunner = + BetterCommandRunner('cookcli', 'A cli to create wonderful dishes.') + ..addCommand(SpiceCommand()) + ..addCommand(VegetableCommand()); + var generator = CommandDocumentationGenerator(commandRunner); + output = generator.generateMarkdown(); + }); + + test('then outputs each command into a separate file', () { + expect(output.keys, containsAll(['vegetable.md', 'spice.md'])); + }); + + test('then output starts with the main command', () async { + var vegetableCommandOutput = output['spice.md']; + + expect( + vegetableCommandOutput, + startsWith( + '## Usage\n' + '\n' + '```console\n' + 'Modifies the spice mix in your dish.\n' + '\n' + 'Usage: cookcli spice [arguments]\n' + '-h, --help Print this usage information.\n' + '\n' + 'Available subcommands:\n' + ' add Add something to the spice mix\n' + ' remove Remove something from the spice mix\n' + '\n' + 'Run "cookcli help" to see global options.\n' + '```\n' + '\n', + )); + }); + + test('then output ends with the sub commands', () async { + var vegetableCommandOutput = output['spice.md']; + + expect( + vegetableCommandOutput, + endsWith( + '### Sub commands\n' + '\n' + '#### `add`\n' + '\n' + '```console\n' + 'Add something to the spice mix\n' + '\n' + 'Usage: cookcli spice add [arguments]\n' + '-h, --help Print this usage information.\n' + ' --curry Include curry in the spice mix.\n' + ' --pepper Include pepper in the spice mix.\n' + '\n' + 'Run "cookcli help" to see global options.\n' + '```\n' + '\n' + '#### `remove`\n' + '\n' + '```console\n' + 'Remove something from the spice mix\n' + '\n' + 'Usage: cookcli spice remove [arguments]\n' + '-h, --help Print this usage information.\n' + ' --curry Remove curry from the spice mix.\n' + ' --pepper Remove pepper from the spice mix.\n' + '\n' + 'Run "cookcli help" to see global options.\n' + '```\n', + )); + }); + }); +} From 093d5f35106bc3cf38ba3d1fc12ec6168c6c1d66 Mon Sep 17 00:00:00 2001 From: Hampus Lavin Date: Fri, 15 Nov 2024 12:05:55 +0100 Subject: [PATCH 2/2] fix: remove unintended addition --- lib/src/logger/loggers/void_logger.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/logger/loggers/void_logger.dart b/lib/src/logger/loggers/void_logger.dart index 3f9f974..afeaf03 100644 --- a/lib/src/logger/loggers/void_logger.dart +++ b/lib/src/logger/loggers/void_logger.dart @@ -7,7 +7,7 @@ class VoidLogger extends Logger { VoidLogger() : super(LogLevel.debug); @override - int? get wrapTextColumn => 80; + int? get wrapTextColumn => null; @override void debug(