typedoc-plugin-external-module-map
Version:
Specify the Typedoc Module of a file using a regular expression on the filename
110 lines • 4.95 kB
JavaScript
import { Application, ContainerReflection, Context, Converter, Reflection, ReflectionKind } from "typedoc";
/**
* This plugin allows you to provide a mapping regexp between your source folder structure, and the module that should be
* reported in typedoc. It will match the first capture group of your regex and use that as the module name.
*
* Based on https://github.com/christopherthielen/typedoc-plugin-external-module-name
*
*
*/
export class ExternalModuleMapPlugin {
constructor() {
/** List of module reflections which are models to rename */
this.moduleRenames = new Array();
this.externalmap = '';
this.mapRegExs = new Array();
this.isMappingEnabled = false;
}
initialize(app) {
app.converter.on(Converter.EVENT_BEGIN, this.onBegin.bind(this));
app.converter.on(Converter.EVENT_CREATE_DECLARATION, this.onDeclarationBegin.bind(this));
app.converter.on(Converter.EVENT_RESOLVE_BEGIN, this.onBeginResolve.bind(this));
}
/**
* Triggered when the converter begins converting a project.
*
* @param context The context object describing the current state the converter is in.
*/
onBegin(context) {
this.moduleRenames = [];
//this.options.read();
this.externalmap = context.converter.application.options.getValue("external-modulemap");
if (!!this.externalmap) {
try {
console.log("INFO: applying regexp ", this.externalmap, " to calculate module names");
this.mapRegExs = Array.isArray(this.externalmap) ? this.externalmap.map(reg => new RegExp(reg)) : [new RegExp(this.externalmap)];
this.isMappingEnabled = true;
console.log("INFO: Enabled", this.isMappingEnabled);
}
catch (e) {
console.log("WARN: external map not recognized. Not processing.", e);
}
}
}
onDeclarationBegin(context, reflection, node) {
if (!this.isMappingEnabled) {
return;
}
if (!(reflection.kindOf(ReflectionKind.SomeModule))) {
return;
}
const symbol = reflection.project.getSymbolFromReflection(reflection);
for (const node of (symbol === null || symbol === void 0 ? void 0 : symbol.declarations) || []) {
const sourceFile = node.getSourceFile();
const fileName = sourceFile.fileName;
let match;
for (const reg of this.mapRegExs) {
match = reg.exec(fileName);
if (null != match) {
break;
}
}
if (null != match) {
console.log(' Mapping ', fileName, ' ==> ', match[1]);
this.moduleRenames.push({
renameTo: match[1],
reflection: reflection
});
}
}
}
/**
* Triggered when the converter begins resolving a project.
*
* @param context The context object describing the current state the converter is in.
*/
onBeginResolve(context) {
let projRefs = context.project.reflections;
let refsArray = Object.keys(projRefs).reduce((m, k) => { m.push(projRefs[k]); return m.filter((y) => y instanceof ContainerReflection); }, []);
// Process each rename
this.moduleRenames.forEach(item => {
let renaming = item.reflection;
// Find an existing module that already has the "rename to" name. Use it as the merge target.
let mergeTarget = refsArray.filter(ref => ref.kind === renaming.kind && ref.name === item.renameTo)[0];
// If there wasn't a merge target, just change the name of the current module and exit.
if (!mergeTarget) {
renaming.name = item.renameTo;
return;
}
if (!mergeTarget.children) {
mergeTarget.children = [];
}
// Since there is a merge target, relocate all the renaming module's children to the mergeTarget.
let childrenOfRenamed = refsArray.filter(ref => ref.parent === renaming);
childrenOfRenamed.forEach((ref) => {
// update links in both directions
//console.log(' merging ', mergeTarget, ref);
ref.parent = mergeTarget;
if (mergeTarget && mergeTarget.children) {
mergeTarget.children.push(ref);
}
});
// Now that all the children have been relocated to the mergeTarget, delete the empty module
// Make sure the module being renamed doesn't have children, or they will be deleted
if (renaming.children)
renaming.children.length = 0;
context.project.removeReflection(renaming);
});
}
}
//# sourceMappingURL=plugin.js.map