Skip to content

Revert "Revert "Refactor html generator into frontend and backend"" #2121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 62 additions & 22 deletions lib/dartdoc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +44,79 @@ class DartdocGeneratorOptionContext extends DartdocOptionContext
: super(optionSet, dir);
}

class DartdocFileWriter implements FileWriter {
final String outputDir;
final Map<String, Warnable> _fileElementMap = {};
@override
final Set<String> writtenFiles = Set();

DartdocFileWriter(this.outputDir);

@override
void write(String filePath, Object content,
{bool allowOverwrite, Warnable element}) {
// Replace '/' separators with proper separators for the platform.
String outFile = path.joinAll(filePath.split('/'));

allowOverwrite ??= false;
if (!allowOverwrite) {
if (_fileElementMap.containsKey(outFile)) {
assert(element != null,
'Attempted overwrite of ${outFile} without corresponding element');
Warnable originalElement = _fileElementMap[outFile];
Iterable<Warnable> referredFrom =
originalElement != null ? [originalElement] : null;
element?.warn(PackageWarning.duplicateFile,
message: outFile, referredFrom: referredFrom);
}
}
_fileElementMap[outFile] = element;

var file = File(path.join(outputDir, outFile));
var parent = file.parent;
if (!parent.existsSync()) {
parent.createSync(recursive: true);
}

if (content is String) {
file.writeAsStringSync(content);
} else if (content is List<int>) {
file.writeAsBytesSync(content);
} else {
throw ArgumentError.value(
content, 'content', '`content` must be `String` or `List<int>`.');
}

writtenFiles.add(outFile);
logProgress(outFile);
}
}

/// Generates Dart documentation for all public Dart libraries in the given
/// directory.
class Dartdoc extends PackageBuilder {
final List<Generator> generators;
final Generator generator;
final Set<String> writtenFiles = Set();
Directory outputDir;

// Fires when the self checks make progress.
final StreamController<String> _onCheckProgress =
StreamController(sync: true);

Dartdoc._(DartdocOptionContext config, this.generators) : super(config) {
Dartdoc._(DartdocOptionContext config, this.generator) : super(config) {
outputDir = Directory(config.output)..createSync(recursive: true);
generators.forEach((g) => g.onFileCreated.listen(logProgress));
}

/// An asynchronous factory method that builds Dartdoc's file writers
/// and returns a Dartdoc object with them.
static Future<Dartdoc> withDefaultGenerators(
DartdocGeneratorOptionContext config) async {
List<Generator> generators = await initHtmlGenerators(config);
return Dartdoc._(config, generators);
return Dartdoc._(config, await initHtmlGenerator(config));
}

/// An asynchronous factory method that builds
static Future<Dartdoc> withEmptyGenerator(DartdocOptionContext config) async {
List<Generator> generators = await initEmptyGenerators(config);
return Dartdoc._(config, generators);
}

/// Basic synchronous factory that gives a stripped down Dartdoc that won't
/// use generators. Useful for testing.
factory Dartdoc.withoutGenerators(DartdocOptionContext config) {
return Dartdoc._(config, []);
return Dartdoc._(config, await initEmptyGenerator(config));
}

Stream<String> get onCheckProgress => _onCheckProgress.stream;
Expand All @@ -94,19 +133,20 @@ class Dartdoc extends PackageBuilder {
double seconds;
packageGraph = await buildPackageGraph();
seconds = _stopwatch.elapsedMilliseconds / 1000.0;
logInfo(
"Initialized dartdoc with ${packageGraph.libraries.length} librar${packageGraph.libraries.length == 1 ? 'y' : 'ies'} "
int libs = packageGraph.libraries.length;
logInfo("Initialized dartdoc with ${libs} librar${libs == 1 ? 'y' : 'ies'} "
"in ${seconds.toStringAsFixed(1)} seconds");
_stopwatch.reset();

if (generators.isNotEmpty) {
final generator = this.generator;
if (generator != null) {
// Create the out directory.
if (!outputDir.existsSync()) outputDir.createSync(recursive: true);

for (var generator in generators) {
await generator.generate(packageGraph, outputDir.path);
writtenFiles.addAll(generator.writtenFiles.keys.map(path.normalize));
}
DartdocFileWriter writer = DartdocFileWriter(outputDir.path);
await generator.generate(packageGraph, writer);

writtenFiles.addAll(writer.writtenFiles);
if (config.validateLinks && writtenFiles.isNotEmpty) {
validateLinks(packageGraph, outputDir.path);
}
Expand All @@ -122,8 +162,8 @@ class Dartdoc extends PackageBuilder {
}

seconds = _stopwatch.elapsedMilliseconds / 1000.0;
logInfo(
"Documented ${packageGraph.localPublicLibraries.length} public librar${packageGraph.localPublicLibraries.length == 1 ? 'y' : 'ies'} "
libs = packageGraph.localPublicLibraries.length;
logInfo("Documented ${libs} public librar${libs == 1 ? 'y' : 'ies'} "
"in ${seconds.toStringAsFixed(1)} seconds");
return DartdocResults(config.topLevelPackageMeta, packageGraph, outputDir);
}
Expand Down
24 changes: 7 additions & 17 deletions lib/src/empty_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:async';

import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/generator.dart';
import 'package:dartdoc/src/logging.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart';
import 'package:dartdoc/src/warnings.dart';
Expand All @@ -13,34 +14,23 @@ import 'package:dartdoc/src/warnings.dart';
/// it were.
class EmptyGenerator extends Generator {
@override
Future generate(PackageGraph _packageGraph, String outputDirectoryPath) {
_onFileCreated.add(_packageGraph.defaultPackage.documentationAsHtml);
Future generate(PackageGraph _packageGraph, FileWriter writer) {
logProgress(_packageGraph.defaultPackage.documentationAsHtml);
for (var package in Set.from([_packageGraph.defaultPackage])
..addAll(_packageGraph.localPackages)) {
for (var category in filterNonDocumented(package.categories)) {
_onFileCreated.add(category.documentationAsHtml);
logProgress(category.documentationAsHtml);
}

for (Library lib in filterNonDocumented(package.libraries)) {
filterNonDocumented(lib.allModelElements)
.forEach((m) => _onFileCreated.add(m.documentationAsHtml));
.forEach((m) => logProgress(m.documentationAsHtml));
}
}
return null;
}

final StreamController<void> _onFileCreated = StreamController(sync: true);

@override

/// Implementation fires on each model element processed rather than
/// file creation.
Stream<void> get onFileCreated => _onFileCreated.stream;

@override
final Map<String, Warnable> writtenFiles = {};
}

Future<List<Generator>> initEmptyGenerators(DartdocOptionContext config) async {
return [EmptyGenerator()];
Future<Generator> initEmptyGenerator(DartdocOptionContext config) async {
return EmptyGenerator();
}
21 changes: 12 additions & 9 deletions lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ import 'package:dartdoc/src/package_meta.dart';
import 'package:dartdoc/src/warnings.dart';
import 'package:path/path.dart' as path;

abstract class FileWriter {
/// All filenames written by this generator.
Set<String> get writtenFiles;

/// Write [content] to a file at [filePath].
void write(String filePath, Object content,
{bool allowOverwrite, Warnable element});
}

/// An abstract class that defines a generator that generates documentation for
/// a given package.
///
/// Generators can generate documentation in different formats: html, json etc.
abstract class Generator {
/// Generate the documentation for the given package in the specified
/// directory. Completes the returned future when done.
Future generate(PackageGraph packageGraph, String outputDirectoryPath);

/// Fires when a file is created.
Stream<void> get onFileCreated;

/// Fetches all filenames written by this generator.
Map<String, Warnable> get writtenFiles;
/// Generate the documentation for the given package using the specified
/// writer. Completes the returned future when done.
Future generate(PackageGraph packageGraph, FileWriter writer);
}

/// Dartdoc options related to generators generally.
Expand Down
Loading