-
Notifications
You must be signed in to change notification settings - Fork 36
/
plugin.ts
128 lines (109 loc) · 4.44 KB
/
plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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 {
/** List of module reflections which are models to rename */
private moduleRenames: ModuleRename[];
private externalmap: string | string[];
private mapRegExs: RegExp[];
private isMappingEnabled: boolean ;
initialize(app: Application) {
app.converter.on(Converter.EVENT_BEGIN, this.onBegin);
app.converter.on(Converter.EVENT_CREATE_DECLARATION, this.onDeclarationBegin);
app.converter.on(Converter.EVENT_RESOLVE_BEGIN, this.onBeginResolve);
}
/**
* Triggered when the converter begins converting a project.
*
* @param context The context object describing the current state the converter is in.
*/
private onBegin(context: Context) {
this.moduleRenames = [];
//this.options.read();
this.externalmap = context.converter.application.options.getValue("external-modulemap") as (string | string[]);
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);
}
}
}
private onDeclarationBegin(context: Context, reflection: Reflection, node?) {
if (!this.isMappingEnabled) {
return;
}
if (!(reflection.kindOf(ReflectionKind.SomeModule))) {
return;
}
const symbol = reflection.project.getSymbolFromReflection(reflection);
for (const node of 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: <ContainerReflection>reflection
});
}
}
}
/**
* Triggered when the converter begins resolving a project.
*
* @param context The context object describing the current state the converter is in.
*/
private onBeginResolve(context: Context) {
let projRefs = context.project.reflections;
let refsArray: Reflection[] = 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 = <ContainerReflection>item.reflection;
// Find an existing module that already has the "rename to" name. Use it as the merge target.
let mergeTarget = <ContainerReflection>
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: Reflection) => {
// update links in both directions
//console.log(' merging ', mergeTarget, ref);
ref.parent = mergeTarget;
mergeTarget.children.push(<any>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);
});
}
}
interface ModuleRename {
renameTo: string;
reflection: ContainerReflection;
}