typedoc-toolbox 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/README.md +64 -0
- package/dist/index.cjs +225 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +192 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2025 - Present Hervé Perchec
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# typedoc-toolbox
|
|
2
|
+
|
|
3
|
+
[](http://herve-perchec.com/)
|
|
4
|
+
[](http://herve-perchec.com/)
|
|
5
|
+
[](https://gitlab.com/hperchec/typedoc-toolbox/-/releases)
|
|
6
|
+
[](https://gitlab.com/hperchec/typedoc-toolbox/commits/v0.0.1)
|
|
7
|
+

|
|
8
|
+
[](https://www.npmjs.com/package/typedoc-toolbox)
|
|
9
|
+
[](https://www.npmjs.com/package/typedoc-toolbox)
|
|
10
|
+
[](https://gitlab.com/hperchec/typedoc-toolbox/issues)
|
|
11
|
+
[](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/LICENSE)
|
|
12
|
+
|
|
13
|
+
## Table of contents
|
|
14
|
+
|
|
15
|
+
* [🍵 Introduction](#-introduction)
|
|
16
|
+
* [🚀 Get started](#-get-started)
|
|
17
|
+
* [🛠️ Usage](#️-usage)
|
|
18
|
+
* [🤝 Contribute](#-contribute)
|
|
19
|
+
* [👑 Author](#-author)
|
|
20
|
+
* [⚖️ License](#️-license)
|
|
21
|
+
* [📰 Changelog](#-changelog)
|
|
22
|
+
|
|
23
|
+
## 🍵 Introduction
|
|
24
|
+
|
|
25
|
+
This library is a collection of useful tools for [TypeDoc](https://typedoc.org/index.html).
|
|
26
|
+
|
|
27
|
+
## 🚀 Get started
|
|
28
|
+
|
|
29
|
+
This package is published on [NPM](https://www.npmjs.com/package/typedoc-toolbox).
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm install typedoc-toolbox
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 🛠️ Usage
|
|
36
|
+
|
|
37
|
+
> 💡 Please check the [API documentation](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/docs/api/gen/README.md).
|
|
38
|
+
|
|
39
|
+
## 🤝 Contribute
|
|
40
|
+
|
|
41
|
+
You would like to contribute to this project? You are welcome!
|
|
42
|
+
|
|
43
|
+
First, please check:
|
|
44
|
+
|
|
45
|
+
* the [contribution guide](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/CONTRIBUTING.md)
|
|
46
|
+
* the [code of conduct](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/CODE_OF_CONDUCT.md)
|
|
47
|
+
|
|
48
|
+
## 👑 Author
|
|
49
|
+
|
|
50
|
+
Made with ❤ by [Hervé Perchec](https://gitlab.com/herveperchec)
|
|
51
|
+
|
|
52
|
+
## ⚖️ License
|
|
53
|
+
|
|
54
|
+
[MIT](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/LICENSE)
|
|
55
|
+
|
|
56
|
+
## 📰 Changelog
|
|
57
|
+
|
|
58
|
+
See all changes to this project in the [CHANGELOG.md](https://gitlab.com/hperchec/typedoc-toolbox/-/blob/dd0823badca2649c726e982b074fb76665fbb1d6/CHANGELOG.md) file.
|
|
59
|
+
|
|
60
|
+
***
|
|
61
|
+
|
|
62
|
+
<!-- markdownlint-disable-next-line line-length -->
|
|
63
|
+
|
|
64
|
+
*README.md - this file was auto generated with [juisy](https://www.npmjs.com/package/juisy) README templater. Don't edit it.*
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* typedoc-toolbox v0.0.1
|
|
3
|
+
* MIT License
|
|
4
|
+
* Copyright © 2025-Present Hervé Perchec (https://gitlab.com/herveperchec)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
10
|
+
|
|
11
|
+
const os = require('node:os');
|
|
12
|
+
const fs = require('node:fs/promises');
|
|
13
|
+
const node_fs = require('node:fs');
|
|
14
|
+
const path = require('node:path');
|
|
15
|
+
const juisy = require('juisy');
|
|
16
|
+
const dayjs = require('dayjs');
|
|
17
|
+
const td = require('typedoc');
|
|
18
|
+
|
|
19
|
+
function _interopNamespaceDefault(e) {
|
|
20
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
|
|
21
|
+
if (e) {
|
|
22
|
+
for (const k in e) {
|
|
23
|
+
if (k !== 'default') {
|
|
24
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
25
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: () => e[k]
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
n.default = e;
|
|
33
|
+
return Object.freeze(n);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const td__namespace = /*#__PURE__*/_interopNamespaceDefault(td);
|
|
37
|
+
|
|
38
|
+
class TDOptionError extends Error {
|
|
39
|
+
}
|
|
40
|
+
class TDCompileError extends Error {
|
|
41
|
+
}
|
|
42
|
+
class TDValidationError extends Error {
|
|
43
|
+
}
|
|
44
|
+
class TDOutputError extends Error {
|
|
45
|
+
}
|
|
46
|
+
const dryRunsTempRootDir = path.join(os.tmpdir(), "typedoc-toolbox-dry-runs");
|
|
47
|
+
async function createApp(options = {}, readers = []) {
|
|
48
|
+
return await td__namespace.Application.bootstrapWithPlugins({
|
|
49
|
+
// By default, only errors are logged
|
|
50
|
+
logLevel: 3,
|
|
51
|
+
// No entry points
|
|
52
|
+
entryPoints: [],
|
|
53
|
+
// Prevent cleaning output directory
|
|
54
|
+
cleanOutputDir: false,
|
|
55
|
+
...options
|
|
56
|
+
}, [
|
|
57
|
+
// new td.TypeDocReader(),
|
|
58
|
+
// new td.PackageJsonReader(),
|
|
59
|
+
// new td.TSConfigReader()
|
|
60
|
+
...readers
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
function getRawConfig(app) {
|
|
64
|
+
return app.options.getRawValues();
|
|
65
|
+
}
|
|
66
|
+
async function run(app, options) {
|
|
67
|
+
options = options ?? { dry: false };
|
|
68
|
+
if (options.dry) {
|
|
69
|
+
app.logger.info("Dry run started");
|
|
70
|
+
}
|
|
71
|
+
const optionsSnapshot = app.options.snapshot();
|
|
72
|
+
let context;
|
|
73
|
+
const start = Date.now();
|
|
74
|
+
const throwRunError = (error) => {
|
|
75
|
+
logRunSummary(app.logger);
|
|
76
|
+
throw error;
|
|
77
|
+
};
|
|
78
|
+
if (app.logger.hasErrors()) {
|
|
79
|
+
throwRunError(new TDOptionError("TypeDoc option error"));
|
|
80
|
+
}
|
|
81
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
82
|
+
throwRunError(new TDOptionError("TypeDoc option error"));
|
|
83
|
+
}
|
|
84
|
+
const getConverterContext = (ctx) => {
|
|
85
|
+
context = ctx;
|
|
86
|
+
};
|
|
87
|
+
app.converter.on(td__namespace.Converter.EVENT_END, getConverterContext);
|
|
88
|
+
if (!await app.convert() || app.logger.hasErrors()) {
|
|
89
|
+
throwRunError(new TDCompileError("Compilation error"));
|
|
90
|
+
}
|
|
91
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
92
|
+
throwRunError(new TDCompileError("Compilation error"));
|
|
93
|
+
}
|
|
94
|
+
app.converter.off(td__namespace.Converter.EVENT_END, getConverterContext);
|
|
95
|
+
const project = context.project;
|
|
96
|
+
const preValidationWarnCount = app.logger.warningCount;
|
|
97
|
+
app.validate(project);
|
|
98
|
+
const hadValidationWarnings = app.logger.warningCount !== preValidationWarnCount || app.logger.validationWarningCount != 0;
|
|
99
|
+
if (app.logger.hasErrors()) {
|
|
100
|
+
throwRunError(new TDValidationError("Validation error"));
|
|
101
|
+
}
|
|
102
|
+
if (hadValidationWarnings && (app.options.getValue("treatWarningsAsErrors") || app.options.getValue("treatValidationWarningsAsErrors"))) {
|
|
103
|
+
throwRunError(new TDValidationError("Validation error"));
|
|
104
|
+
}
|
|
105
|
+
if (app.options.getValue("emit") !== "none") {
|
|
106
|
+
if (options.dry) {
|
|
107
|
+
await dryOutput(app, project);
|
|
108
|
+
} else {
|
|
109
|
+
await app.generateOutputs(project);
|
|
110
|
+
}
|
|
111
|
+
if (app.logger.hasErrors()) {
|
|
112
|
+
throwRunError(new TDOutputError("Output error"));
|
|
113
|
+
}
|
|
114
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
115
|
+
throwRunError(new TDOutputError("Output error"));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
app.options.restore(optionsSnapshot);
|
|
119
|
+
app.logger.verbose(`Full run took ${Date.now() - start}ms`);
|
|
120
|
+
return {
|
|
121
|
+
application: app,
|
|
122
|
+
context
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
async function dryOutput(app, project) {
|
|
126
|
+
const optionsSnapshot = app.options.snapshot();
|
|
127
|
+
app.options.setValue("cleanOutputDir", false);
|
|
128
|
+
if (!node_fs.existsSync(dryRunsTempRootDir)) {
|
|
129
|
+
await fs.mkdir(dryRunsTempRootDir);
|
|
130
|
+
}
|
|
131
|
+
const tempDirPath = path.join(dryRunsTempRootDir, dayjs().format("YYYYMMDDHHmmssSSS"));
|
|
132
|
+
await fs.mkdir(tempDirPath);
|
|
133
|
+
try {
|
|
134
|
+
app.logger.info(`Temporary folder "${tempDirPath}" succesfully created`);
|
|
135
|
+
const originalGetOutputSpecs = app.outputs.getOutputSpecs.bind(app.outputs);
|
|
136
|
+
app.outputs.getOutputSpecs = function() {
|
|
137
|
+
return originalGetOutputSpecs().map((outputSpec, index) => {
|
|
138
|
+
const extension = path.extname(outputSpec.path);
|
|
139
|
+
outputSpec.path = juisy.utils.path.toPosix(path.join(tempDirPath, `${outputSpec.name}_${index}${extension}`));
|
|
140
|
+
return outputSpec;
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
await app.generateOutputs(project);
|
|
144
|
+
app.logger.info(`Temporary folder "${tempDirPath}" succesfully deleted`);
|
|
145
|
+
app.outputs.getOutputSpecs = originalGetOutputSpecs;
|
|
146
|
+
app.options.restore(optionsSnapshot);
|
|
147
|
+
} finally {
|
|
148
|
+
await fs.rm(tempDirPath, { recursive: true, force: true });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function logRunSummary(logger) {
|
|
152
|
+
const { errorCount, warningCount } = logger;
|
|
153
|
+
if (errorCount) {
|
|
154
|
+
logger.error(
|
|
155
|
+
td__namespace.i18n.found_0_errors_and_1_warnings(
|
|
156
|
+
errorCount.toString(),
|
|
157
|
+
warningCount.toString()
|
|
158
|
+
)
|
|
159
|
+
);
|
|
160
|
+
} else if (warningCount) {
|
|
161
|
+
logger.warn(
|
|
162
|
+
td__namespace.i18n.found_0_errors_and_1_warnings(
|
|
163
|
+
errorCount.toString(),
|
|
164
|
+
warningCount.toString()
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function createReflectionUrlResolver(app) {
|
|
170
|
+
const outputSpecs = app.outputs.getOutputSpecs();
|
|
171
|
+
if (outputSpecs.length > 1) {
|
|
172
|
+
throw new Error(`Unable to create reflection URL resolver with multiple outputs [ ${outputSpecs.map((o) => `"${o.name}"`).join(", ")} ]. Please provide only one theme.`);
|
|
173
|
+
} else if (outputSpecs[0].name === "json") {
|
|
174
|
+
throw new Error(`Unable to create reflection URL resolver with JSON output.`);
|
|
175
|
+
}
|
|
176
|
+
const reflectionsCache = {};
|
|
177
|
+
const optionsSnapshot = app.options.snapshot();
|
|
178
|
+
app.options.setValue("emit", "docs");
|
|
179
|
+
let router;
|
|
180
|
+
let getFullUrl;
|
|
181
|
+
app.renderer.on(td__namespace.RendererEvent.BEGIN, () => {
|
|
182
|
+
router = app.renderer.router;
|
|
183
|
+
getFullUrl = router.getFullUrl.bind(router);
|
|
184
|
+
});
|
|
185
|
+
const { context } = await run(app, { dry: true });
|
|
186
|
+
app.options.restore(optionsSnapshot);
|
|
187
|
+
return function resolver(identifier) {
|
|
188
|
+
if (!reflectionsCache[identifier]) {
|
|
189
|
+
const tempRefl = new td__namespace.DeclarationReflection("__TEMP__", td__namespace.ReflectionKind.All, context.project);
|
|
190
|
+
tempRefl.comment = new td__namespace.Comment([
|
|
191
|
+
{ kind: "inline-tag", tag: "@link", text: identifier }
|
|
192
|
+
]);
|
|
193
|
+
app.converter.resolveLinks(tempRefl);
|
|
194
|
+
const resolvedTag = tempRefl.comment.summary[0];
|
|
195
|
+
const targetReflection = resolvedTag.target;
|
|
196
|
+
reflectionsCache[resolvedTag.text] = {
|
|
197
|
+
reflection: targetReflection,
|
|
198
|
+
url: targetReflection ? getFullUrl(targetReflection) : void 0
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return reflectionsCache[identifier].url;
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function getReflectionTag(tag, reflection) {
|
|
205
|
+
const comment = reflection.comment;
|
|
206
|
+
if (!comment) return;
|
|
207
|
+
return comment.getTag(tag);
|
|
208
|
+
}
|
|
209
|
+
function getReflectionTags(tag, reflection) {
|
|
210
|
+
const comment = reflection.comment;
|
|
211
|
+
if (!comment) return [];
|
|
212
|
+
return comment.getTags(tag);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
exports.TDCompileError = TDCompileError;
|
|
216
|
+
exports.TDOptionError = TDOptionError;
|
|
217
|
+
exports.TDOutputError = TDOutputError;
|
|
218
|
+
exports.TDValidationError = TDValidationError;
|
|
219
|
+
exports.createApp = createApp;
|
|
220
|
+
exports.createReflectionUrlResolver = createReflectionUrlResolver;
|
|
221
|
+
exports.dryRunsTempRootDir = dryRunsTempRootDir;
|
|
222
|
+
exports.getRawConfig = getRawConfig;
|
|
223
|
+
exports.getReflectionTag = getReflectionTag;
|
|
224
|
+
exports.getReflectionTags = getReflectionTags;
|
|
225
|
+
exports.run = run;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @importTarget .
|
|
4
|
+
*/
|
|
5
|
+
import * as td from 'typedoc';
|
|
6
|
+
/**
|
|
7
|
+
* All TypeDoc error types
|
|
8
|
+
*/
|
|
9
|
+
export type TDError = TDOptionError | TDCompileError | TDValidationError | TDOutputError;
|
|
10
|
+
/**
|
|
11
|
+
* TypeDoc option error
|
|
12
|
+
*/
|
|
13
|
+
export declare class TDOptionError extends Error {
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* TypeDoc compilation error
|
|
17
|
+
*/
|
|
18
|
+
export declare class TDCompileError extends Error {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* TypeDoc validation error
|
|
22
|
+
*/
|
|
23
|
+
export declare class TDValidationError extends Error {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* TypeDoc output error
|
|
27
|
+
*/
|
|
28
|
+
export declare class TDOutputError extends Error {
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* {@link createApp} function options
|
|
32
|
+
*/
|
|
33
|
+
export interface CreateAppOptions extends Omit<td.Configuration.TypeDocOptions, 'help' | 'version' | 'watch' | 'plugin'> {
|
|
34
|
+
plugin?: Array<string | ((app: td.Application) => Promise<void> | void)>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* {@link run} function options
|
|
38
|
+
*/
|
|
39
|
+
export interface RunOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Dry run (no emit). Default: `false`
|
|
42
|
+
*/
|
|
43
|
+
dry: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Type of function returned by {@link createReflectionUrlResolver}.
|
|
47
|
+
* @param identifier - The reflection identifier in a `@link` style
|
|
48
|
+
* @returns The resolved URL or undefined
|
|
49
|
+
*/
|
|
50
|
+
export type ReflectionUrlResolver = (identifier: string) => string | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* The path of temporary folder for dry runs
|
|
53
|
+
*/
|
|
54
|
+
export declare const dryRunsTempRootDir: string;
|
|
55
|
+
/**
|
|
56
|
+
* Create and boot a new TypeDoc application
|
|
57
|
+
*
|
|
58
|
+
* Default options:
|
|
59
|
+
* - **logLevel**: `3`
|
|
60
|
+
* - **entryPoints**: `[]`
|
|
61
|
+
* - **cleanOutputDir**: `false`
|
|
62
|
+
*
|
|
63
|
+
* @param options - The base options
|
|
64
|
+
* @param readers - The option readers
|
|
65
|
+
* @returns The created application
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* import * as td from 'typedoc'
|
|
69
|
+
*
|
|
70
|
+
* const app = await createApp()
|
|
71
|
+
* // With options
|
|
72
|
+
* const app = await createApp({
|
|
73
|
+
* // See CreateAppOptions
|
|
74
|
+
* })
|
|
75
|
+
* // With default readers
|
|
76
|
+
* const app = await createApp({}, [
|
|
77
|
+
* new td.TypeDocReader(),
|
|
78
|
+
* new td.PackageJsonReader(),
|
|
79
|
+
* new td.TSConfigReader()
|
|
80
|
+
* ])
|
|
81
|
+
*/
|
|
82
|
+
export declare function createApp(options?: CreateAppOptions, readers?: td.Configuration.OptionsReader[]): Promise<td.Application>;
|
|
83
|
+
/**
|
|
84
|
+
* Get all of the TypeDoc option values defined in the app option container.
|
|
85
|
+
* @param app - The TypeDoc Application instance
|
|
86
|
+
*/
|
|
87
|
+
export declare function getRawConfig(app: td.Application): Readonly<Partial<td.Configuration.TypeDocOptionValues>>;
|
|
88
|
+
/**
|
|
89
|
+
* Run a TypeDoc process like the CLI does.
|
|
90
|
+
*
|
|
91
|
+
* This code is widely inspired from
|
|
92
|
+
* [TypeDoc library sources](https://github.com/TypeStrong/typedoc/blob/v0.28.16/src/lib/cli.ts)
|
|
93
|
+
*
|
|
94
|
+
* Thanks to [Gerrit Birkeland](https://github.com/Gerrit0), the author of TypeDoc.
|
|
95
|
+
*
|
|
96
|
+
* @param app - The TypeDoc Application instance
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* const result = await run(app)
|
|
100
|
+
* // Dry run
|
|
101
|
+
* const result = await run(app, { dry: true })
|
|
102
|
+
*/
|
|
103
|
+
export declare function run(app: td.Application, options?: RunOptions): Promise<{
|
|
104
|
+
application: td.Application;
|
|
105
|
+
context: td.Context;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Create a reflection URL resolver from the given TypeDoc application instance.
|
|
109
|
+
* @returns The resolver function
|
|
110
|
+
* @example
|
|
111
|
+
* // With the default "html" output
|
|
112
|
+
* const resolver = await createReflectionUrlResolver(app)
|
|
113
|
+
* // For a "bar" constant in the "foo" module
|
|
114
|
+
* resolver('foo!bar') // => 'variables/foo.bar.html'
|
|
115
|
+
* // For a "bar" method of the "Foo" class in the "foo" module
|
|
116
|
+
* resolver('foo!Foo#bar') // => 'classes/foo.Foo.html#bar'
|
|
117
|
+
*/
|
|
118
|
+
export declare function createReflectionUrlResolver(app: td.Application): Promise<ReflectionUrlResolver>;
|
|
119
|
+
/**
|
|
120
|
+
* Get the tag in reflection comment
|
|
121
|
+
* @param tag - The tag to find
|
|
122
|
+
* @param reflection - The reflection object
|
|
123
|
+
* @returns The found comment tag or undefined
|
|
124
|
+
*/
|
|
125
|
+
export declare function getReflectionTag(tag: td.TagString, reflection: td.Reflection): td.CommentTag | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Get the tags in reflection comment
|
|
128
|
+
* @param tag - The tag to find
|
|
129
|
+
* @param reflection - The reflection object
|
|
130
|
+
* @returns The found comment tags or empty array
|
|
131
|
+
*/
|
|
132
|
+
export declare function getReflectionTags(tag: td.TagString, reflection: td.Reflection): td.CommentTag[];
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* typedoc-toolbox v0.0.1
|
|
3
|
+
* MIT License
|
|
4
|
+
* Copyright © 2025-Present Hervé Perchec (https://gitlab.com/herveperchec)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { utils } from 'juisy';
|
|
12
|
+
import dayjs from 'dayjs';
|
|
13
|
+
import * as td from 'typedoc';
|
|
14
|
+
|
|
15
|
+
class TDOptionError extends Error {
|
|
16
|
+
}
|
|
17
|
+
class TDCompileError extends Error {
|
|
18
|
+
}
|
|
19
|
+
class TDValidationError extends Error {
|
|
20
|
+
}
|
|
21
|
+
class TDOutputError extends Error {
|
|
22
|
+
}
|
|
23
|
+
const dryRunsTempRootDir = path.join(os.tmpdir(), "typedoc-toolbox-dry-runs");
|
|
24
|
+
async function createApp(options = {}, readers = []) {
|
|
25
|
+
return await td.Application.bootstrapWithPlugins({
|
|
26
|
+
// By default, only errors are logged
|
|
27
|
+
logLevel: 3,
|
|
28
|
+
// No entry points
|
|
29
|
+
entryPoints: [],
|
|
30
|
+
// Prevent cleaning output directory
|
|
31
|
+
cleanOutputDir: false,
|
|
32
|
+
...options
|
|
33
|
+
}, [
|
|
34
|
+
// new td.TypeDocReader(),
|
|
35
|
+
// new td.PackageJsonReader(),
|
|
36
|
+
// new td.TSConfigReader()
|
|
37
|
+
...readers
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
function getRawConfig(app) {
|
|
41
|
+
return app.options.getRawValues();
|
|
42
|
+
}
|
|
43
|
+
async function run(app, options) {
|
|
44
|
+
options = options ?? { dry: false };
|
|
45
|
+
if (options.dry) {
|
|
46
|
+
app.logger.info("Dry run started");
|
|
47
|
+
}
|
|
48
|
+
const optionsSnapshot = app.options.snapshot();
|
|
49
|
+
let context;
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
const throwRunError = (error) => {
|
|
52
|
+
logRunSummary(app.logger);
|
|
53
|
+
throw error;
|
|
54
|
+
};
|
|
55
|
+
if (app.logger.hasErrors()) {
|
|
56
|
+
throwRunError(new TDOptionError("TypeDoc option error"));
|
|
57
|
+
}
|
|
58
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
59
|
+
throwRunError(new TDOptionError("TypeDoc option error"));
|
|
60
|
+
}
|
|
61
|
+
const getConverterContext = (ctx) => {
|
|
62
|
+
context = ctx;
|
|
63
|
+
};
|
|
64
|
+
app.converter.on(td.Converter.EVENT_END, getConverterContext);
|
|
65
|
+
if (!await app.convert() || app.logger.hasErrors()) {
|
|
66
|
+
throwRunError(new TDCompileError("Compilation error"));
|
|
67
|
+
}
|
|
68
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
69
|
+
throwRunError(new TDCompileError("Compilation error"));
|
|
70
|
+
}
|
|
71
|
+
app.converter.off(td.Converter.EVENT_END, getConverterContext);
|
|
72
|
+
const project = context.project;
|
|
73
|
+
const preValidationWarnCount = app.logger.warningCount;
|
|
74
|
+
app.validate(project);
|
|
75
|
+
const hadValidationWarnings = app.logger.warningCount !== preValidationWarnCount || app.logger.validationWarningCount != 0;
|
|
76
|
+
if (app.logger.hasErrors()) {
|
|
77
|
+
throwRunError(new TDValidationError("Validation error"));
|
|
78
|
+
}
|
|
79
|
+
if (hadValidationWarnings && (app.options.getValue("treatWarningsAsErrors") || app.options.getValue("treatValidationWarningsAsErrors"))) {
|
|
80
|
+
throwRunError(new TDValidationError("Validation error"));
|
|
81
|
+
}
|
|
82
|
+
if (app.options.getValue("emit") !== "none") {
|
|
83
|
+
if (options.dry) {
|
|
84
|
+
await dryOutput(app, project);
|
|
85
|
+
} else {
|
|
86
|
+
await app.generateOutputs(project);
|
|
87
|
+
}
|
|
88
|
+
if (app.logger.hasErrors()) {
|
|
89
|
+
throwRunError(new TDOutputError("Output error"));
|
|
90
|
+
}
|
|
91
|
+
if (app.options.getValue("treatWarningsAsErrors") && app.logger.hasWarnings()) {
|
|
92
|
+
throwRunError(new TDOutputError("Output error"));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
app.options.restore(optionsSnapshot);
|
|
96
|
+
app.logger.verbose(`Full run took ${Date.now() - start}ms`);
|
|
97
|
+
return {
|
|
98
|
+
application: app,
|
|
99
|
+
context
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function dryOutput(app, project) {
|
|
103
|
+
const optionsSnapshot = app.options.snapshot();
|
|
104
|
+
app.options.setValue("cleanOutputDir", false);
|
|
105
|
+
if (!existsSync(dryRunsTempRootDir)) {
|
|
106
|
+
await fs.mkdir(dryRunsTempRootDir);
|
|
107
|
+
}
|
|
108
|
+
const tempDirPath = path.join(dryRunsTempRootDir, dayjs().format("YYYYMMDDHHmmssSSS"));
|
|
109
|
+
await fs.mkdir(tempDirPath);
|
|
110
|
+
try {
|
|
111
|
+
app.logger.info(`Temporary folder "${tempDirPath}" succesfully created`);
|
|
112
|
+
const originalGetOutputSpecs = app.outputs.getOutputSpecs.bind(app.outputs);
|
|
113
|
+
app.outputs.getOutputSpecs = function() {
|
|
114
|
+
return originalGetOutputSpecs().map((outputSpec, index) => {
|
|
115
|
+
const extension = path.extname(outputSpec.path);
|
|
116
|
+
outputSpec.path = utils.path.toPosix(path.join(tempDirPath, `${outputSpec.name}_${index}${extension}`));
|
|
117
|
+
return outputSpec;
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
await app.generateOutputs(project);
|
|
121
|
+
app.logger.info(`Temporary folder "${tempDirPath}" succesfully deleted`);
|
|
122
|
+
app.outputs.getOutputSpecs = originalGetOutputSpecs;
|
|
123
|
+
app.options.restore(optionsSnapshot);
|
|
124
|
+
} finally {
|
|
125
|
+
await fs.rm(tempDirPath, { recursive: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function logRunSummary(logger) {
|
|
129
|
+
const { errorCount, warningCount } = logger;
|
|
130
|
+
if (errorCount) {
|
|
131
|
+
logger.error(
|
|
132
|
+
td.i18n.found_0_errors_and_1_warnings(
|
|
133
|
+
errorCount.toString(),
|
|
134
|
+
warningCount.toString()
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
} else if (warningCount) {
|
|
138
|
+
logger.warn(
|
|
139
|
+
td.i18n.found_0_errors_and_1_warnings(
|
|
140
|
+
errorCount.toString(),
|
|
141
|
+
warningCount.toString()
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function createReflectionUrlResolver(app) {
|
|
147
|
+
const outputSpecs = app.outputs.getOutputSpecs();
|
|
148
|
+
if (outputSpecs.length > 1) {
|
|
149
|
+
throw new Error(`Unable to create reflection URL resolver with multiple outputs [ ${outputSpecs.map((o) => `"${o.name}"`).join(", ")} ]. Please provide only one theme.`);
|
|
150
|
+
} else if (outputSpecs[0].name === "json") {
|
|
151
|
+
throw new Error(`Unable to create reflection URL resolver with JSON output.`);
|
|
152
|
+
}
|
|
153
|
+
const reflectionsCache = {};
|
|
154
|
+
const optionsSnapshot = app.options.snapshot();
|
|
155
|
+
app.options.setValue("emit", "docs");
|
|
156
|
+
let router;
|
|
157
|
+
let getFullUrl;
|
|
158
|
+
app.renderer.on(td.RendererEvent.BEGIN, () => {
|
|
159
|
+
router = app.renderer.router;
|
|
160
|
+
getFullUrl = router.getFullUrl.bind(router);
|
|
161
|
+
});
|
|
162
|
+
const { context } = await run(app, { dry: true });
|
|
163
|
+
app.options.restore(optionsSnapshot);
|
|
164
|
+
return function resolver(identifier) {
|
|
165
|
+
if (!reflectionsCache[identifier]) {
|
|
166
|
+
const tempRefl = new td.DeclarationReflection("__TEMP__", td.ReflectionKind.All, context.project);
|
|
167
|
+
tempRefl.comment = new td.Comment([
|
|
168
|
+
{ kind: "inline-tag", tag: "@link", text: identifier }
|
|
169
|
+
]);
|
|
170
|
+
app.converter.resolveLinks(tempRefl);
|
|
171
|
+
const resolvedTag = tempRefl.comment.summary[0];
|
|
172
|
+
const targetReflection = resolvedTag.target;
|
|
173
|
+
reflectionsCache[resolvedTag.text] = {
|
|
174
|
+
reflection: targetReflection,
|
|
175
|
+
url: targetReflection ? getFullUrl(targetReflection) : void 0
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return reflectionsCache[identifier].url;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function getReflectionTag(tag, reflection) {
|
|
182
|
+
const comment = reflection.comment;
|
|
183
|
+
if (!comment) return;
|
|
184
|
+
return comment.getTag(tag);
|
|
185
|
+
}
|
|
186
|
+
function getReflectionTags(tag, reflection) {
|
|
187
|
+
const comment = reflection.comment;
|
|
188
|
+
if (!comment) return [];
|
|
189
|
+
return comment.getTags(tag);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { TDCompileError, TDOptionError, TDOutputError, TDValidationError, createApp, createReflectionUrlResolver, dryRunsTempRootDir, getRawConfig, getReflectionTag, getReflectionTags, run };
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typedoc-toolbox",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A collection of useful tools for TypeDoc library",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"require": "./dist/index.cjs",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"docs:readme": "node ./bin/cli docs generate:readme",
|
|
21
|
+
"docs:api": "node ./bin/cli docs generate:api -c ./docs/config/api/typedoc.config.js",
|
|
22
|
+
"docs:cli": "npm run -s docs:cli:private && npm run -s docs:cli:public",
|
|
23
|
+
"docs:cli:private": "node ./bin/cli docs generate:cli -c ./docs/config/cli/private/config.js",
|
|
24
|
+
"docs:cli:public": "node ./bin/cli docs generate:cli -c ./docs/config/cli/public/config.js",
|
|
25
|
+
"docs": "npm run -s docs:api && npm run -s docs:readme && npm run -s docs:cli",
|
|
26
|
+
"lint": "node ./bin/cli lint",
|
|
27
|
+
"lint:fix": "npm run -s lint -- --fix",
|
|
28
|
+
"lint:markdown": "node ./bin/cli lint:markdown",
|
|
29
|
+
"lint:markdown:fix": "npm run -s lint:markdown -- --fix",
|
|
30
|
+
"release": "node ./bin/cli release",
|
|
31
|
+
"changelog": "node ./bin/cli changelog",
|
|
32
|
+
"git-hooks:reset": "node ./bin/cli git-hooks reset",
|
|
33
|
+
"git-hooks:sync": "node ./bin/cli git-hooks sync",
|
|
34
|
+
"test": "node ./bin/cli test run",
|
|
35
|
+
"test:watch": "node ./bin/cli test",
|
|
36
|
+
"test:ui": "npm run -s test:watch -- --ui --coverage.enabled=true",
|
|
37
|
+
"test:coverage": "npm run -s test -- --coverage.enabled=true"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://gitlab.com/hperchec/typedoc-toolbox.git"
|
|
42
|
+
},
|
|
43
|
+
"author": {
|
|
44
|
+
"name": "Hervé Perchec",
|
|
45
|
+
"url": "https://gitlab.com/herveperchec"
|
|
46
|
+
},
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://gitlab.com/hperchec/typedoc-toolbox/issues"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://gitlab.com/hperchec/typedoc-toolbox",
|
|
52
|
+
"keywords": [
|
|
53
|
+
"typedoc",
|
|
54
|
+
"typedoc-plugin",
|
|
55
|
+
"tool",
|
|
56
|
+
"tools",
|
|
57
|
+
"toolbox",
|
|
58
|
+
"api",
|
|
59
|
+
"documentation"
|
|
60
|
+
],
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"dayjs": "^1.11.19",
|
|
63
|
+
"juisy": "^2.2.0",
|
|
64
|
+
"typedoc": "^0.28.16"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@release-it/conventional-changelog": "^9.0.4",
|
|
68
|
+
"@vitest/coverage-v8": "^3",
|
|
69
|
+
"@vitest/ui": "^3",
|
|
70
|
+
"eslint-plugin-jsdoc": "^50.8.0",
|
|
71
|
+
"eslint-plugin-tsdoc": "^0.5.0",
|
|
72
|
+
"remark-insert-headings": "^0.0.0",
|
|
73
|
+
"remark-toc": "^9.0.0",
|
|
74
|
+
"simple-git-hooks": "^2.13.1",
|
|
75
|
+
"typedoc-plugin-default-groups": "^1.0.2",
|
|
76
|
+
"typedoc-plugin-dt-links": "^2.0.39",
|
|
77
|
+
"typedoc-plugin-import-target": "^1.3.2",
|
|
78
|
+
"typedoc-plugin-markdown": "^4.9.0",
|
|
79
|
+
"typedoc-plugin-mdn-links": "^5.1.1",
|
|
80
|
+
"typedoc-plugin-remark": "^2.0.1",
|
|
81
|
+
"typescript-eslint": "^8.39.1",
|
|
82
|
+
"vite-plugin-checker": "^0.11.0",
|
|
83
|
+
"vite-plugin-dts": "^4.5.4",
|
|
84
|
+
"vitest": "^3"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"typedoc": "^0.28.16"
|
|
88
|
+
}
|
|
89
|
+
}
|