blob: 012eda05395c8c156f54d56539a3d2a1e246d197 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dartdoc.html_generator;
import 'dart:async' show Future, StreamController, Stream;
import 'dart:io' show File;
import 'package:path/path.dart' as pathLib;
import '../generator.dart';
import '../model.dart';
import 'html_generator_instance.dart';
import 'template_data.dart';
import 'templates.dart';
typedef String Renderer(String input);
// Generation order for libraries:
// constants
// typedefs
// properties
// functions
// enums
// classes
// exceptions
//
// Generation order for classes:
// constants
// static properties
// static methods
// properties
// constructors
// operators
// methods
class HtmlGenerator extends Generator {
final Templates _templates;
final HtmlGeneratorOptions _options;
HtmlGeneratorInstance _instance;
final StreamController<File> _onFileCreated =
new StreamController(sync: true);
@override
Stream<File> get onFileCreated => _onFileCreated.stream;
@override
final Set<String> writtenFiles = new Set<String>();
static Future<HtmlGenerator> create(
{HtmlGeneratorOptions options,
List<String> headers,
List<String> footers,
List<String> footerTexts}) async {
var templates = await Templates.create(
headerPaths: headers,
footerPaths: footers,
footerTextPaths: footerTexts);
return new HtmlGenerator._(
options ?? new HtmlGeneratorOptions(), templates);
}
HtmlGenerator._(this._options, this._templates);
@override
/// Actually write out the documentation for [packageGraph].
/// Stores the HtmlGeneratorInstance so we can access it in [writtenFiles].
Future generate(PackageGraph packageGraph, String outputDirectoryPath) async {
assert(_instance == null);
var enabled = true;
void write(String filePath, Object content, {bool allowOverwrite}) {
allowOverwrite ??= false;
if (!enabled) {
throw new StateError('`write` was called after `generate` completed.');
}
// If you see this assert, we're probably being called to build non-canonical
// docs somehow. Check data.self.isCanonical and callers for bugs.
assert(allowOverwrite || !writtenFiles.contains(filePath));
var file = new File(pathLib.join(outputDirectoryPath, filePath));
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 new ArgumentError.value(
content, 'content', '`content` must be `String` or `List<int>`.');
}
_onFileCreated.add(file);
writtenFiles.add(filePath);
}
try {
_instance =
new HtmlGeneratorInstance(_options, _templates, packageGraph, write);
await _instance.generate();
} finally {
enabled = false;
}
}
}
class HtmlGeneratorOptions implements HtmlOptions {
final String url;
final String faviconPath;
final bool prettyIndexJson;
@override
final bool displayAsPackages;
@override
final String relCanonicalPrefix;
@override
final String toolVersion;
HtmlGeneratorOptions(
{this.url,
this.relCanonicalPrefix,
this.faviconPath,
String toolVersion,
this.displayAsPackages: false,
this.prettyIndexJson: false})
: this.toolVersion = toolVersion ?? 'unknown';
}