typedoc-plugin-merge-modules
Version:
Plugin for TypeDoc that merges the content of modules.
135 lines (134 loc) • 5.43 kB
JavaScript
import { Application, Converter, EntryPointStrategy, ReflectionKind, } from "typedoc";
import { ModuleCategoryMerger } from "./merger/module_category_merger.js";
import { ModuleMerger } from "./merger/module_merger.js";
import { ProjectMerger } from "./merger/project_merger.js";
import { PluginOptions } from "./plugin_options.js";
import { tryGetOriginalReflectionName } from "./utils.js";
/**
* The "Merge Modules" plugin.
*
* # What does it do?
*
* This plugin merges the content of modules.
*/
export class Plugin {
/** The options of the plugin. */
_options = new PluginOptions();
/**
* This is set to "true" if the merging logic of the plugin is executed after TypeDoc
* has already categorized the DeclarationReflections.
*/
_runsAfterCategorization = false;
/**
* Returns if the plugin is enabled.
* @returns True if the plugin is enabled, otherwise false.
*/
get isEnabled() {
return this._options.mode !== "off";
}
/**
* Returns if the merging logic of the plugin is executed after TypeDoc has categorized the DeclarationReflections.
* @returns True if the plugin is executed after categorization, otherwise false.
*/
get runsAfterCategorization() {
return this._runsAfterCategorization;
}
/**
* Initializes the plugin.
* @param typedoc The TypeDoc application.
*/
initialize(typedoc) {
this._options.addToApplication(typedoc);
this.subscribeToApplicationEvents(typedoc);
}
/**
* Subscribes to events of the application so that the plugin can do its work
* in the particular doc generation phases.
* @param typedoc The TypeDoc application.
*/
subscribeToApplicationEvents(typedoc) {
typedoc.on(Application.EVENT_BOOTSTRAP_END, (a) => {
this.onApplicationBootstrapEnd(a);
});
typedoc.converter.on(Converter.EVENT_CREATE_DECLARATION, (c, r) => {
this.onConverterCreateDeclaration(c, r);
});
// When TypeDoc is running with the following entry point strategies, it will create a separate converter
// and trigger the "Converter.EVENT_RESOLVE_BEGIN" event for each package that it merges into the final
// ProjectReflection instance.
// So for these strategies we need to subscribe to an event that is triggered after this merge is complete,
// in order to be able to access all modules from each package.
const typeDocUsesMultipleConverters = typedoc.entryPointStrategy === EntryPointStrategy.Merge ||
typedoc.entryPointStrategy === EntryPointStrategy.Packages;
if (typeDocUsesMultipleConverters) {
// The "Application.EVENT_PROJECT_REVIVE" event is triggered after the DeclarationReflections have been
// categorized by TypeDoc.
this._runsAfterCategorization = true;
typedoc.on(Application.EVENT_PROJECT_REVIVE, (p) => {
this.onConvertersDone(p);
});
}
else {
// The "Converter.EVENT_RESOLVE_BEGIN" event is triggered before the DeclarationReflections have been
// categorized by TypeDoc.
this._runsAfterCategorization = false;
typedoc.converter.on(Converter.EVENT_RESOLVE_BEGIN, (c) => {
this.onConvertersDone(c.project);
});
}
}
/**
* Triggered after plugins have been loaded and options have been read.
* @param typedoc The TypeDoc application.
*/
onApplicationBootstrapEnd(typedoc) {
this._options.readValuesFromApplication(typedoc);
}
/**
* Triggered when the converter has created a declaration reflection.
* @param context Describes the current state the converter is in.
* @param reflection The reflection that has been created.
*/
onConverterCreateDeclaration(context, reflection) {
if (this.isEnabled &&
this._options.renameDefaults &&
reflection.name === "default" &&
reflection.kindOf(ReflectionKind.ClassOrInterface |
ReflectionKind.Enum |
ReflectionKind.Function |
ReflectionKind.TypeAlias |
ReflectionKind.TypeLiteral |
ReflectionKind.Variable)) {
const originalName = tryGetOriginalReflectionName(context, reflection);
if (originalName) {
reflection.name = originalName;
}
}
}
/**
* Triggered after all converters are done.
* @param project The project on which the event is triggered.
*/
onConvertersDone(project) {
if (this.isEnabled) {
this.createMerger(project)?.execute();
}
}
/**
* Creates a merger object for the given project.
* @param project The project on which the merger should operate.
* @returns The merger object, or undefined if the plugin is turned off.
*/
createMerger(project) {
if (this._options.mode === "project") {
return new ProjectMerger(project, this);
}
else if (this._options.mode === "module") {
return new ModuleMerger(project, this);
}
else if (this._options.mode === "module-category") {
return new ModuleCategoryMerger(project, this);
}
return undefined;
}
}