Add config option for output format (#2132)

* Add config option for output format

Defaults to 'html', but also supports 'md' (using empty generator).
Option is hidden for now until a real generator for 'md' is wired up.

* Code review changes

* Add message to deprecated annotation
diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart
index f76c825..34bc0f9 100644
--- a/bin/dartdoc.dart
+++ b/bin/dartdoc.dart
@@ -87,7 +87,7 @@
   startLogging(config);
 
   Dartdoc dartdoc = config.generateDocs
-      ? await Dartdoc.withDefaultGenerators(config)
+      ? await Dartdoc.fromContext(config)
       : await Dartdoc.withEmptyGenerator(config);
   dartdoc.onCheckProgress.listen(logProgress);
   try {
diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart
index 721bcec..91ec031 100644
--- a/lib/dartdoc.dart
+++ b/lib/dartdoc.dart
@@ -109,16 +109,36 @@
 
   /// An asynchronous factory method that builds Dartdoc's file writers
   /// and returns a Dartdoc object with them.
+  @Deprecated('Prefer withContext() instead')
   static Future<Dartdoc> withDefaultGenerators(
       DartdocGeneratorOptionContext config) async {
     return Dartdoc._(config, await initHtmlGenerator(config));
   }
 
-  /// An asynchronous factory method that builds
+  /// Asynchronous factory method that builds Dartdoc with an empty generator.
   static Future<Dartdoc> withEmptyGenerator(DartdocOptionContext config) async {
     return Dartdoc._(config, await initEmptyGenerator(config));
   }
 
+  /// Asynchronous factory method that builds Dartdoc with a generator
+  /// determined by the given context.
+  static Future<Dartdoc> fromContext(
+      DartdocGeneratorOptionContext context) async {
+    Generator generator;
+    switch (context.format) {
+      case 'html':
+        generator = await initHtmlGenerator(context);
+        break;
+      case 'md':
+        // TODO(jdkoren): use a real generator
+        generator = await initEmptyGenerator(context);
+        break;
+      default:
+        throw DartdocFailure('Unsupported output format: ${context.format}');
+    }
+    return Dartdoc._(context, generator);
+  }
+
   Stream<String> get onCheckProgress => _onCheckProgress.stream;
 
   PackageGraph packageGraph;
diff --git a/lib/src/generator.dart b/lib/src/generator.dart
index f705f53..1904d3b 100644
--- a/lib/src/generator.dart
+++ b/lib/src/generator.dart
@@ -56,6 +56,9 @@
 
   String get templatesDir => optionSet['templatesDir'].valueAt(context);
 
+  /// Output format, e.g. 'html', 'md'
+  String get format => optionSet['format'].valueAt(context);
+
   // TODO(jdkoren): duplicated temporarily so that GeneratorContext is enough for configuration.
   bool get useBaseHref => optionSet['useBaseHref'].valueAt(context);
 }
@@ -137,6 +140,8 @@
             'top_level_property, typedef. Partial templates are supported; '
             'they must begin with an underscore, and references to them must '
             'omit the leading underscore (e.g. use {{>foo}} to reference the '
-            'partial template _foo.html).'),
+            'partial template named _foo).'),
+    // TODO(jdkoren): Unhide when we have good support for another format.
+    DartdocOptionArgOnly<String>('format', 'html', hide: true),
   ];
 }
diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart
index 7a3339e..377654e 100644
--- a/test/dartdoc_test.dart
+++ b/test/dartdoc_test.dart
@@ -45,9 +45,8 @@
 
     Future<Dartdoc> buildDartdoc(
         List<String> argv, Directory packageRoot, Directory tempDir) async {
-      return await Dartdoc.withDefaultGenerators(await generatorContextFromArgv(
-          argv
-            ..addAll(['--input', packageRoot.path, '--output', tempDir.path])));
+      return await Dartdoc.fromContext(await generatorContextFromArgv(argv
+        ..addAll(['--input', packageRoot.path, '--output', tempDir.path])));
     }
 
     group('Option handling', () {
@@ -425,5 +424,16 @@
       expect(level2.readAsStringSync(),
           contains('<link rel="canonical" href="$prefix/ex/Apple/m.html">'));
     });
+
+    test('generate docs with bad output format', () async {
+      try {
+        await buildDartdoc(['--format', 'bad'], testPackageDir, tempDir);
+        fail('dartdoc should fail with bad output format');
+      } catch (e) {
+        expect(e is DartdocFailure, isTrue);
+        expect((e as DartdocFailure).message,
+            startsWith('Unsupported output format'));
+      }
+    });
   }, timeout: Timeout.factor(8));
 }