/
typedoc.ts
124 lines (109 loc) · 3.77 KB
/
typedoc.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
import { join, dirname, resolve } from "path";
import * as FS from "fs";
import { OptionsReader } from "..";
import { Logger } from "../../loggers";
import { Options } from "../options";
import { ok } from "assert";
/**
* Obtains option values from typedoc.json
* or typedoc.js (discouraged since ~0.14, don't fully deprecate until API has stabilized)
*/
export class TypeDocReader implements OptionsReader {
/**
* Should run before the tsconfig reader so that it can specify a tsconfig file to read.
*/
priority = 100;
name = "typedoc-json";
/**
* Read user configuration from a typedoc.json or typedoc.js configuration file.
* @param container
* @param logger
*/
read(container: Options, logger: Logger): void {
const path = container.getValue("options");
const file = this.findTypedocFile(path);
if (!file) {
if (container.isSet("options")) {
logger.error(
`The options file could not be found with the given path ${path}`
);
}
return;
}
const seen = new Set<string>();
this.readFile(file, container, logger, seen);
}
/**
* Read the given options file + any extended files.
* @param file
* @param container
* @param logger
*/
private readFile(
file: string,
container: Options & { setValue(key: string, value: unknown): void },
logger: Logger,
seen: Set<string>
) {
if (seen.has(file)) {
logger.error(
`Tried to load the options file ${file} multiple times.`
);
return;
}
seen.add(file);
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fileContent: unknown = require(file);
if (typeof fileContent !== "object" || !fileContent) {
logger.error(`The file ${file} is not an object.`);
return;
}
// clone option object to avoid of property changes in re-calling this file
const data: any = { ...fileContent };
delete data["$schema"]; // Useful for better autocompletion, should not be read as a key.
if ("extends" in data) {
const extended: string[] = getStringArray(data["extends"]);
for (const extendedFile of extended) {
// Extends is relative to the file it appears in.
this.readFile(
resolve(dirname(file), extendedFile),
container,
logger,
seen
);
}
delete data["extends"];
}
for (const [key, val] of Object.entries(data)) {
try {
container.setValue(
key as never,
val as never,
resolve(dirname(file))
);
} catch (error) {
ok(error instanceof Error);
logger.error(error.message);
}
}
}
/**
* Search for the typedoc.js or typedoc.json file from the given path
*
* @param path Path to the typedoc.(js|json) file. If path is a directory
* typedoc file will be attempted to be found at the root of this path
* @param logger
* @return the typedoc.(js|json) file path or undefined
*/
private findTypedocFile(path: string): string | undefined {
path = resolve(path);
return [
path,
join(path, "typedoc.json"),
join(path, "typedoc.js"),
].find((path) => FS.existsSync(path) && FS.statSync(path).isFile());
}
}
function getStringArray(arg: unknown): string[] {
return Array.isArray(arg) ? arg.map(String) : [String(arg)];
}