Move generator options into generator.dart (#2100)
* Remove --hosted-url as it is actually unused
* Move templatesDir option to generator context
* Separate html generator options from generic ones
* Move base generator context options to generator.dart
* Move initEmptyGenerators
* Make initHtmlGenerators take HtmlGeneratorContext instead
* Recombine options into one GeneratorContext
* Temporarily dupe useBaseHrefs in GeneratorContext
diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart
index 2c10570..66a8a8a 100644
--- a/lib/dartdoc.dart
+++ b/lib/dartdoc.dart
@@ -13,6 +13,7 @@
import 'dart:io';
import 'package:dartdoc/src/dartdoc_options.dart';
+import 'package:dartdoc/src/empty_generator.dart';
import 'package:dartdoc/src/generator.dart';
import 'package:dartdoc/src/html/html_generator.dart';
import 'package:dartdoc/src/logging.dart';
@@ -36,8 +37,7 @@
// Update when pubspec version changes by running `pub run build_runner build`
const String dartdocVersion = packageVersion;
-/// Helper class to initialize the default generators since they require
-/// GeneratorContext.
+/// Helper class that consolidates option contexts for instantiating generators.
class DartdocGeneratorOptionContext extends DartdocOptionContext
with GeneratorContext {
DartdocGeneratorOptionContext(DartdocOptionSet optionSet, Directory dir)
@@ -64,7 +64,7 @@
/// and returns a Dartdoc object with them.
static Future<Dartdoc> withDefaultGenerators(
DartdocGeneratorOptionContext config) async {
- List<Generator> generators = await initGenerators(config);
+ List<Generator> generators = await initHtmlGenerators(config);
return Dartdoc._(config, generators);
}
diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart
index 409f876..7385131 100644
--- a/lib/src/dartdoc_options.dart
+++ b/lib/src/dartdoc_options.dart
@@ -1421,8 +1421,6 @@
bool isPackageExcluded(String name) =>
excludePackages.any((pattern) => name == pattern);
- String get templatesDir => optionSet['templatesDir'].valueAt(context);
-
// TODO(jdkoren): temporary while we confirm href base behavior doesn't break important clients
bool get useBaseHref => optionSet['useBaseHref'].valueAt(context);
}
@@ -1627,17 +1625,6 @@
'exist. Executables for different platforms are specified by '
'giving the platform name as a key, and a list of strings as the '
'command.'),
- DartdocOptionArgOnly<String>("templatesDir", null,
- isDir: true,
- mustExist: true,
- hide: true,
- help:
- 'Path to a directory containing templates to use instead of the default ones. '
- 'Directory must contain an html file for each of the following: 404error, category, '
- 'class, constant, constructor, enum, function, index, library, method, mixin, '
- 'property, top_level_constant, 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).'),
DartdocOptionArgOnly<bool>('useBaseHref', false,
help:
'Use <base href> in generated files (legacy behavior). This option '
diff --git a/lib/src/empty_generator.dart b/lib/src/empty_generator.dart
index d879574..666df06 100644
--- a/lib/src/empty_generator.dart
+++ b/lib/src/empty_generator.dart
@@ -2,6 +2,7 @@
import 'dart:async';
+import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/generator.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart';
@@ -39,3 +40,7 @@
@override
final Map<String, Warnable> writtenFiles = {};
}
+
+Future<List<Generator>> initEmptyGenerators(DartdocOptionContext config) async {
+ return [EmptyGenerator()];
+}
diff --git a/lib/src/generator.dart b/lib/src/generator.dart
index d062ae9..6ea61e1 100644
--- a/lib/src/generator.dart
+++ b/lib/src/generator.dart
@@ -6,9 +6,14 @@
library dartdoc.generator;
import 'dart:async' show Stream, Future;
+import 'dart:io' show Directory;
+import 'dart:isolate';
+import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/model/model.dart' show PackageGraph;
+import 'package:dartdoc/src/package_meta.dart';
import 'package:dartdoc/src/warnings.dart';
+import 'package:path/path.dart' as path;
/// An abstract class that defines a generator that generates documentation for
/// a given package.
@@ -25,3 +30,110 @@
/// Fetches all filenames written by this generator.
Map<String, Warnable> get writtenFiles;
}
+
+/// Dartdoc options related to generators generally.
+mixin GeneratorContext on DartdocOptionContextBase {
+ List<String> get footer => optionSet['footer'].valueAt(context);
+
+ /// _footerText is only used to construct synthetic options.
+ // ignore: unused_element
+ List<String> get _footerText => optionSet['footerText'].valueAt(context);
+
+ List<String> get footerTextPaths =>
+ optionSet['footerTextPaths'].valueAt(context);
+
+ List<String> get header => optionSet['header'].valueAt(context);
+
+ bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(context);
+
+ String get favicon => optionSet['favicon'].valueAt(context);
+
+ String get relCanonicalPrefix =>
+ optionSet['relCanonicalPrefix'].valueAt(context);
+
+ String get templatesDir => optionSet['templatesDir'].valueAt(context);
+
+ // TODO(jdkoren): duplicated temporarily so that GeneratorContext is enough for configuration.
+ bool get useBaseHref => optionSet['useBaseHref'].valueAt(context);
+}
+
+Uri _sdkFooterCopyrightUri;
+
+Future<void> _setSdkFooterCopyrightUri() async {
+ if (_sdkFooterCopyrightUri == null) {
+ // TODO(jdkoren): find a way to make this not specific to HTML, or have
+ // alternatives for other supported formats.
+ _sdkFooterCopyrightUri = await Isolate.resolvePackageUri(
+ Uri.parse('package:dartdoc/resources/sdk_footer_text.html'));
+ }
+}
+
+Future<List<DartdocOption>> createGeneratorOptions() async {
+ await _setSdkFooterCopyrightUri();
+ return <DartdocOption>[
+ DartdocOptionArgFile<List<String>>('footer', [],
+ isFile: true,
+ help:
+ 'Paths to files with content to add to page footers, but possibly '
+ 'outside of dedicated footer elements for the generator (e.g. '
+ 'outside of <footer> for an HTML generator). To add text content '
+ 'to dedicated footer elements, use --footer-text instead.',
+ mustExist: true,
+ splitCommas: true),
+ DartdocOptionArgFile<List<String>>('footerText', [],
+ isFile: true,
+ help: 'Paths to files with content to add to page footers (next to the '
+ 'package name and version).',
+ mustExist: true,
+ splitCommas: true),
+ DartdocOptionSyntheticOnly<List<String>>(
+ 'footerTextPaths',
+ (DartdocSyntheticOption<List<String>> option, Directory dir) {
+ final List<String> footerTextPaths = <String>[];
+ final PackageMeta topLevelPackageMeta =
+ option.root['topLevelPackageMeta'].valueAt(dir);
+ // TODO(jcollins-g): Eliminate special casing for SDK and use config file.
+ if (topLevelPackageMeta.isSdk == true) {
+ footerTextPaths
+ .add(path.canonicalize(_sdkFooterCopyrightUri.toFilePath()));
+ }
+ footerTextPaths.addAll(option.parent['footerText'].valueAt(dir));
+ return footerTextPaths;
+ },
+ isFile: true,
+ help: 'paths to footer-text-files (adding special case for SDK)',
+ mustExist: true,
+ ),
+ DartdocOptionArgFile<List<String>>('header', [],
+ isFile: true,
+ help: 'Paths to files with content to add to page headers.',
+ splitCommas: true),
+ DartdocOptionArgOnly<bool>('prettyIndexJson', false,
+ help:
+ 'Generates `index.json` with indentation and newlines. The file is '
+ 'larger, but it\'s also easier to diff.',
+ negatable: false),
+ DartdocOptionArgFile<String>('favicon', null,
+ isFile: true,
+ help: 'A path to a favicon for the generated docs.',
+ mustExist: true),
+ DartdocOptionArgOnly<String>('relCanonicalPrefix', null,
+ help:
+ 'If provided, add a rel="canonical" prefixed with provided value. '
+ 'Consider using if building many versions of the docs for public '
+ 'SEO; learn more at https://goo.gl/gktN6F.'),
+ DartdocOptionArgOnly<String>("templatesDir", null,
+ isDir: true,
+ mustExist: true,
+ hide: true,
+ help:
+ 'Path to a directory with templates to use instead of the default '
+ 'ones. Directory must contain a file for each of the following: '
+ '404error, category, class, constant, constructor, enum, function, '
+ 'index, library, method, mixin, property, top_level_constant, '
+ '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).'),
+ ];
+}
diff --git a/lib/src/html/html_generator.dart b/lib/src/html/html_generator.dart
index 8cac333..29be73c 100644
--- a/lib/src/html/html_generator.dart
+++ b/lib/src/html/html_generator.dart
@@ -131,7 +131,6 @@
}
class HtmlGeneratorOptions implements HtmlOptions {
- final String url;
final String faviconPath;
final bool prettyIndexJson;
final String templatesDir;
@@ -146,8 +145,7 @@
final bool useBaseHref;
HtmlGeneratorOptions(
- {this.url,
- this.relCanonicalPrefix,
+ {this.relCanonicalPrefix,
this.faviconPath,
String toolVersion,
this.prettyIndexJson = false,
@@ -156,109 +154,23 @@
: this.toolVersion = toolVersion ?? 'unknown';
}
-Future<List<Generator>> initEmptyGenerators(DartdocOptionContext config) async {
- return [EmptyGenerator()];
-}
-
/// Initialize and setup the generators.
-Future<List<Generator>> initGenerators(GeneratorContext config) async {
+Future<List<Generator>> initHtmlGenerators(GeneratorContext context) async {
// TODO(jcollins-g): Rationalize based on GeneratorContext all the way down
// through the generators.
HtmlGeneratorOptions options = HtmlGeneratorOptions(
- url: config.hostedUrl,
- relCanonicalPrefix: config.relCanonicalPrefix,
+ relCanonicalPrefix: context.relCanonicalPrefix,
toolVersion: dartdocVersion,
- faviconPath: config.favicon,
- prettyIndexJson: config.prettyIndexJson,
- templatesDir: config.templatesDir,
- useBaseHref: config.useBaseHref);
-
+ faviconPath: context.favicon,
+ prettyIndexJson: context.prettyIndexJson,
+ templatesDir: context.templatesDir,
+ useBaseHref: context.useBaseHref);
return [
await HtmlGenerator.create(
options: options,
- headers: config.header,
- footers: config.footer,
- footerTexts: config.footerTextPaths,
+ headers: context.header,
+ footers: context.footer,
+ footerTexts: context.footerTextPaths,
)
];
}
-
-Uri _sdkFooterCopyrightUri;
-Future<void> _setSdkFooterCopyrightUri() async {
- if (_sdkFooterCopyrightUri == null) {
- _sdkFooterCopyrightUri = await Isolate.resolvePackageUri(
- Uri.parse('package:dartdoc/resources/sdk_footer_text.html'));
- }
-}
-
-abstract class GeneratorContext implements DartdocOptionContext {
- String get favicon => optionSet['favicon'].valueAt(context);
- List<String> get footer => optionSet['footer'].valueAt(context);
-
- /// _footerText is only used to construct synthetic options.
- // ignore: unused_element
- List<String> get _footerText => optionSet['footerText'].valueAt(context);
- List<String> get footerTextPaths =>
- optionSet['footerTextPaths'].valueAt(context);
- List<String> get header => optionSet['header'].valueAt(context);
- String get hostedUrl => optionSet['hostedUrl'].valueAt(context);
- bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(context);
- String get relCanonicalPrefix =>
- optionSet['relCanonicalPrefix'].valueAt(context);
-}
-
-Future<List<DartdocOption>> createGeneratorOptions() async {
- await _setSdkFooterCopyrightUri();
- return <DartdocOption>[
- DartdocOptionArgFile<String>('favicon', null,
- isFile: true,
- help: 'A path to a favicon for the generated docs.',
- mustExist: true),
- DartdocOptionArgFile<List<String>>('footer', [],
- isFile: true,
- help: 'paths to footer files containing HTML text.',
- mustExist: true,
- splitCommas: true),
- DartdocOptionArgFile<List<String>>('footerText', [],
- isFile: true,
- help:
- 'paths to footer-text files (optional text next to the package name '
- 'and version).',
- mustExist: true,
- splitCommas: true),
- DartdocOptionSyntheticOnly<List<String>>(
- 'footerTextPaths',
- (DartdocSyntheticOption<List<String>> option, Directory dir) {
- final List<String> footerTextPaths = <String>[];
- final PackageMeta topLevelPackageMeta =
- option.root['topLevelPackageMeta'].valueAt(dir);
- // TODO(jcollins-g): Eliminate special casing for SDK and use config file.
- if (topLevelPackageMeta.isSdk == true) {
- footerTextPaths
- .add(path.canonicalize(_sdkFooterCopyrightUri.toFilePath()));
- }
- footerTextPaths.addAll(option.parent['footerText'].valueAt(dir));
- return footerTextPaths;
- },
- isFile: true,
- help: 'paths to footer-text-files (adding special case for SDK)',
- mustExist: true,
- ),
- DartdocOptionArgFile<List<String>>('header', [],
- isFile: true,
- help: 'paths to header files containing HTML text.',
- splitCommas: true),
- DartdocOptionArgOnly<String>('hostedUrl', null,
- help:
- 'URL where the docs will be hosted (used to generate the sitemap).'),
- DartdocOptionArgOnly<bool>('prettyIndexJson', false,
- help:
- "Generates `index.json` with indentation and newlines. The file is larger, but it's also easier to diff.",
- negatable: false),
- DartdocOptionArgOnly<String>('relCanonicalPrefix', null,
- help:
- 'If provided, add a rel="canonical" prefixed with provided value. '
- 'Consider using if\nbuilding many versions of the docs for public '
- 'SEO; learn more at https://goo.gl/gktN6F.'),
- ];
-}