-
Notifications
You must be signed in to change notification settings - Fork 72
/
export-typedocs.ts
146 lines (122 loc) · 3.69 KB
/
export-typedocs.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { execSync } from 'child_process';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import * as path from 'path';
import { PackageJson } from 'type-fest';
import * as TypeDoc from 'typedoc';
/**
* Exports API references using TypeDoc.
*/
class ApiReferenceExporter {
/**
* TypeDoc application instance.
*/
app: TypeDoc.Application;
/**
* Universal configuration options for TypeDoc.
*/
universalConfig: Partial<TypeDoc.TypeDocOptions> = {
excludeExternals: true,
logLevel: 'Error',
};
/**
* @param pkg - Lerna package information.
* @param config - Configuration options for TypeDoc.
* @param settings - Additional custom settings, eg. `includeOpenAPIDoc`
*/
constructor(
private readonly pkg: LernaPackageInfo,
private readonly config: CustomTypeDocOptions['config'],
private readonly settings: CustomTypeDocOptions['settings'] = {},
) {
this.app = new TypeDoc.Application();
this.app.options.addReader(new TypeDoc.TSConfigReader());
Object.assign(this.config, {
...this.universalConfig,
tsconfig: path.resolve(
this.pkg.location,
this.config.tsconfig ?? 'tsconfig.json',
),
entryPoints: this.config.entryPoints.map(filePath =>
path.resolve(this.pkg.location, filePath),
),
} as typeof this.config);
}
/**
* Runs the exporter.
*/
async run() {
this.app.bootstrap(this.config);
const project = this.app.convert();
if (!project) {
throw new Error('Typedoc project reflection is not converted correctly.');
}
const outputDir = path.resolve(__dirname, 'docs', this.config.out);
// Generate docs
await this.app.generateDocs(project, outputDir);
// Post export
if (this.settings.includeOpenAPIDoc) {
const openAPIDocFile = path.resolve(this.pkg.location, 'openapi.md');
if (!existsSync(openAPIDocFile)) {
throw new Error('openapi.md is missing in '.concat(this.pkg.name));
}
let openAPIContent = readFileSync(openAPIDocFile, 'utf-8');
let lines = openAPIContent.split('\n');
// remove the first few lines as these are open api specific front matter
const frontMatterEndsAt = 15;
lines.splice(0, frontMatterEndsAt);
// join the remaining lines back into a string
openAPIContent = lines.join('\n');
// fix language name in codeblocks
openAPIContent = openAPIContent.replace(
/```.javascript--nodejs/gm,
'```js',
);
// write openapi.md to `outputDir`
writeFileSync(path.resolve(outputDir, 'openapi.md'), openAPIContent);
}
}
}
async function main() {
// Get All Public Packages
const packages: Array<LernaPackageInfo> = JSON.parse(
execSync(`npx lerna ls --json --loglevel silent`).toString(),
);
for (let pkg of packages) {
const packageJson: PackageJsonWithTypeDoc = await import(
path.resolve(pkg.location, 'package.json')
);
if (
packageJson.typedoc === undefined ||
packageJson.typedoc.config === undefined
) {
continue;
}
const exporter = new ApiReferenceExporter(
pkg,
packageJson.typedoc.config,
packageJson.typedoc.settings,
);
await exporter.run();
}
}
main();
// Types
interface LernaPackageInfo {
name: string;
version: string;
private: boolean;
location: string;
}
interface PackageJsonWithTypeDoc extends PackageJson {
typedoc?: CustomTypeDocOptions;
}
interface ExportSettings {
/**
* Settings this to `true` will tweak and copy the `openapi.md` in respective docs folder
*/
includeOpenAPIDoc?: boolean;
}
type CustomTypeDocOptions = {
config: Partial<TypeDoc.TypeDocOptions>;
settings: ExportSettings;
};