Skip to content

Commit

Permalink
feat: add docs generator
Browse files Browse the repository at this point in the history
  • Loading branch information
hampuslavin committed Nov 13, 2024
1 parent fd8f906 commit 8cbab52
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/cli_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
1 change: 1 addition & 0 deletions lib/docs_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'src/documentation_generator/documentation_generator.dart';
42 changes: 42 additions & 0 deletions lib/src/documentation_generator/documentation_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import '../../better_command_runner.dart';

class CommandDocumentationGenerator {
final BetterCommandRunner commandRunner;

CommandDocumentationGenerator(this.commandRunner);

Map<String, String> generateMarkdown() {
var commands = commandRunner.commands.values;

var files = <String, String>{};

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;
}
}
2 changes: 1 addition & 1 deletion lib/src/logger/loggers/void_logger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class VoidLogger extends Logger {
VoidLogger() : super(LogLevel.debug);

@override
int? get wrapTextColumn => null;
int? get wrapTextColumn => 80;

@override
void debug(
Expand Down
160 changes: 160 additions & 0 deletions test/documentation_generator/generate_markdown_test.dart
Original file line number Diff line number Diff line change
@@ -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<String, String> 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 <subcommand> [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',
));
});
});
}

0 comments on commit 8cbab52

Please sign in to comment.