blob: ffc54781ce2c869f37c2908c3b6f24ab38d36fcc [file] [log] [blame]
// Copyright (c) 2019, 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.
import 'package:analyzer/file_system/file_system.dart';
import 'package:dartdoc/src/dartdoc_options.dart';
import 'package:dartdoc/src/generator/generator.dart';
import 'package:dartdoc/src/generator/generator_utils.dart' as generator_util;
import 'package:dartdoc/src/generator/template_data.dart';
import 'package:dartdoc/src/generator/templates.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/runtime_stats.dart';
import 'package:dartdoc/src/version.dart';
import 'package:dartdoc/src/warnings.dart';
import 'package:path/path.dart' as p show Context;
/// Configuration options for Dartdoc's default backend.
class DartdocGeneratorBackendOptions implements TemplateOptions {
@override
final String? relCanonicalPrefix;
@override
final String toolVersion;
final String? favicon;
final bool prettyIndexJson;
@override
final bool useBaseHref;
@override
final String customHeaderContent;
@override
final String customFooterContent;
@override
final String customInnerFooterText;
final String? resourcesDir;
final List<String> packageOrder;
DartdocGeneratorBackendOptions.fromContext(
DartdocGeneratorOptionContext context)
: relCanonicalPrefix = context.relCanonicalPrefix,
toolVersion = packageVersion,
favicon = context.favicon,
prettyIndexJson = context.prettyIndexJson,
useBaseHref = context.useBaseHref,
customHeaderContent = context.header,
customFooterContent = context.footer,
customInnerFooterText = context.footerText,
resourcesDir = context.resourcesDir,
packageOrder = context.packageOrder;
}
/// Outputs generated documentation.
abstract class GeneratorBackend {
final DartdocGeneratorBackendOptions options;
final Templates templates;
final FileWriter writer;
final ResourceProvider resourceProvider;
final p.Context _pathContext;
GeneratorBackend(
this.options, this.templates, this.writer, this.resourceProvider)
: _pathContext = resourceProvider.pathContext;
/// Binds template data and emits the content to the [writer].
void write(
FileWriter writer,
String filename,
TemplateData data,
String content, {
bool isSidebar = false,
}) {
if (!options.useBaseHref) {
content = content.replaceAll(
htmlBasePlaceholder,
// URLs in sidebars are tweaked in the front-end; other URLs use
// `htmlBase`.
isSidebar ? '' : data.htmlBase,
);
}
var e = data.self;
writer.write(filename, content, element: e is Warnable ? e : null);
}
/// Emits JSON describing the [categories] defined by the package.
void generateCategoryJson(List<Categorization> categories) {
var json = '[]';
if (categories.isNotEmpty) {
json = generator_util.generateCategoryJson(
categories, options.prettyIndexJson);
if (!options.useBaseHref) {
json = json.replaceAll(htmlBasePlaceholder, '');
}
}
writer.write(_pathContext.join('categories.json'), '$json\n');
}
/// Emits a JSON catalog of [indexedElements] for use with a search index.
void generateSearchIndex(List<Documentable> indexedElements) {
var json = generator_util.generateSearchIndexJson(
indexedElements,
packageOrder: options.packageOrder,
pretty: options.prettyIndexJson,
);
if (!options.useBaseHref) {
json = json.replaceAll(htmlBasePlaceholder, '');
}
writer.write(_pathContext.join('index.json'), '$json\n');
}
/// Emits documentation content for the [category].
void generateCategory(PackageGraph packageGraph, Category category) {
var data = CategoryTemplateData(options, packageGraph, category);
var content = templates.renderCategory(data);
write(writer, category.filePath, data, content);
if (category.filePath != category.redirectFilePath) {
var redirectContent = templates.renderCategoryRedirect(data);
write(writer, category.redirectFilePath, data, redirectContent);
}
runtimeStats.incrementAccumulator('writtenCategoryFileCount');
}
/// Emits documentation content for the [class_].
void generateClass(PackageGraph packageGraph, Library library, Class class_) {
var data = ClassTemplateData(options, packageGraph, library, class_);
var content = templates.renderClass(data);
write(writer, class_.filePath, data, content);
runtimeStats.incrementAccumulator('writtenClassFileCount');
}
/// Emits documentation content for the [constructor].
void generateConstructor(PackageGraph packageGraph, Library library,
Constructable constructable, Constructor constructor) {
var data = ConstructorTemplateData(
options, packageGraph, library, constructable, constructor);
var content = templates.renderConstructor(data);
write(writer, constructor.filePath, data, content);
runtimeStats.incrementAccumulator('writtenConstructorFileCount');
}
/// Emits documentation content for the [enum_].
void generateEnum(PackageGraph packageGraph, Library library, Enum enum_) {
var data = EnumTemplateData(options, packageGraph, library, enum_);
var content = templates.renderEnum(data);
write(writer, enum_.filePath, data, content);
runtimeStats.incrementAccumulator('writtenEnumFileCount');
}
/// Emits documentation content for the [extension].
void generateExtension(
PackageGraph packageGraph, Library library, Extension extension) {
var data = ExtensionTemplateData(options, packageGraph, library, extension);
var content = templates.renderExtension(data);
write(writer, extension.filePath, data, content);
runtimeStats.incrementAccumulator('writtenExtensionFileCount');
}
/// Emits documentation content for the [extensionType].
void generateExtensionType(
PackageGraph packageGraph, Library library, ExtensionType extensionType) {
var data = ExtensionTypeTemplateData(
options, packageGraph, library, extensionType);
var content = templates.renderExtensionType(data);
write(writer, extensionType.filePath, data, content);
runtimeStats.incrementAccumulator('writtenExtensionTypeFileCount');
}
/// Emits documentation content for the [function].
void generateFunction(
PackageGraph packageGraph, Library library, ModelFunction function) {
var data = FunctionTemplateData(options, packageGraph, library, function);
var content = templates.renderFunction(data);
write(writer, function.filePath, data, content);
runtimeStats.incrementAccumulator('writtenFunctionFileCount');
}
/// Emits documentation content for the [library], and the content for the
/// library's previous location (which just redirects to the new location).
void generateLibrary(PackageGraph packageGraph, Library library) {
var data = LibraryTemplateData(options, packageGraph, library);
var content = templates.renderLibrary(data);
var redirectContent = templates.renderLibraryRedirect(data);
write(writer, library.filePath, data, content);
write(writer, library.redirectingPath, data, redirectContent);
runtimeStats.incrementAccumulator('writtenLibraryFileCount');
}
/// Emits documentation content for the [method].
void generateMethod(PackageGraph packageGraph, Library library,
Container container, Method method) {
var data =
MethodTemplateData(options, packageGraph, library, container, method);
var content = templates.renderMethod(data);
write(writer, method.filePath, data, content);
runtimeStats.incrementAccumulator('writtenMethodFileCount');
}
/// Emits documentation content for the [mixin].
void generateMixin(PackageGraph packageGraph, Library library, Mixin mixin) {
var data = MixinTemplateData(options, packageGraph, library, mixin);
var content = templates.renderMixin(data);
write(writer, mixin.filePath, data, content);
runtimeStats.incrementAccumulator('writtenMixinFileCount');
}
/// Emits documentation content for the [package].
void generatePackage(PackageGraph packageGraph, Package package) {
var data = PackageTemplateData(options, packageGraph, package);
var content = templates.renderIndex(data);
write(writer, package.filePath, data, content);
runtimeStats.incrementAccumulator('writtenPackageFileCount');
}
/// Emits documentation content for the [field].
void generateProperty(PackageGraph packageGraph, Library library,
Container container, Field field) {
var data =
PropertyTemplateData(options, packageGraph, library, container, field);
var content = templates.renderProperty(data);
write(writer, field.filePath, data, content);
runtimeStats.incrementAccumulator('writtenPropertyFileCount');
}
/// Emits documentation content for the [property].
void generateTopLevelProperty(
PackageGraph packageGraph, Library library, TopLevelVariable property) {
var data =
TopLevelPropertyTemplateData(options, packageGraph, library, property);
var content = templates.renderTopLevelProperty(data);
write(writer, property.filePath, data, content);
runtimeStats.incrementAccumulator('writtenTopLevelPropertyFileCount');
}
/// Emits documentation content for the [typedef].
void generateTypeDef(
PackageGraph packageGraph, Library library, Typedef typedef) {
var data = TypedefTemplateData(options, packageGraph, library, typedef);
var content = templates.renderTypedef(data);
write(writer, typedef.filePath, data, content);
runtimeStats.incrementAccumulator('writtenTypedefFileCount');
}
/// Emits files not specific to a Dart language element (like a favicon, etc).
Future<void> generateAdditionalFiles();
}