typedoc 0.28.14 → 0.28.16
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/dist/lib/cli.js +2 -1
- package/dist/lib/converter/comments/index.d.ts +3 -2
- package/dist/lib/converter/comments/index.js +69 -18
- package/dist/lib/converter/comments/parser.js +45 -21
- package/dist/lib/converter/comments/textParser.d.ts +13 -9
- package/dist/lib/converter/comments/textParser.js +21 -16
- package/dist/lib/converter/converter.js +1 -0
- package/dist/lib/converter/factories/signature.d.ts +1 -0
- package/dist/lib/converter/factories/signature.js +13 -0
- package/dist/lib/converter/jsdoc.d.ts +1 -1
- package/dist/lib/converter/jsdoc.js +33 -2
- package/dist/lib/converter/plugins/CommentPlugin.js +13 -0
- package/dist/lib/converter/plugins/ImplementsPlugin.d.ts +1 -0
- package/dist/lib/converter/plugins/ImplementsPlugin.js +23 -4
- package/dist/lib/converter/plugins/IncludePlugin.js +4 -0
- package/dist/lib/converter/plugins/SourcePlugin.js +3 -3
- package/dist/lib/converter/symbols.js +9 -22
- package/dist/lib/converter/utils/repository.js +3 -0
- package/dist/lib/internationalization/locales/en.cjs +1 -0
- package/dist/lib/internationalization/locales/en.d.cts +1 -0
- package/dist/lib/models/Comment.d.ts +1 -1
- package/dist/lib/models/Comment.js +1 -1
- package/dist/lib/models/DeclarationReflection.d.ts +7 -0
- package/dist/lib/models/DeclarationReflection.js +9 -0
- package/dist/lib/output/events.d.ts +2 -0
- package/dist/lib/output/events.js +1 -0
- package/dist/lib/output/plugins/JavascriptIndexPlugin.js +1 -1
- package/dist/lib/output/themes/MarkedPlugin.js +15 -8
- package/dist/lib/output/themes/default/partials/icon.js +1 -1
- package/dist/lib/output/themes/default/partials/member.js +1 -0
- package/dist/lib/output/themes/default/partials/moduleReflection.js +1 -0
- package/dist/lib/output/themes/default/partials/navigation.js +1 -1
- package/dist/lib/serialization/schema.d.ts +1 -1
- package/dist/lib/utils/entry-point.js +1 -1
- package/dist/lib/utils/options/declaration.d.ts +4 -0
- package/dist/lib/utils/options/sources/typedoc.js +1 -0
- package/dist/lib/utils/options/tsdoc-defaults.d.ts +2 -2
- package/dist/lib/utils/options/tsdoc-defaults.js +1 -1
- package/dist/lib/utils-common/jsx.elements.d.ts +1 -0
- package/dist/lib/utils-common/logger.d.ts +12 -1
- package/dist/lib/utils-common/logger.js +9 -0
- package/dist/lib/utils-common/set.d.ts +1 -0
- package/dist/lib/utils-common/set.js +7 -0
- package/dist/lib/validation/documentation.js +2 -2
- package/dist/lib/validation/exports.js +2 -2
- package/dist/lib/validation/links.js +7 -7
- package/package.json +16 -14
- package/static/style.css +3 -3
- package/tsdoc.json +0 -4
- package/typedoc-config.schema.json +941 -0
package/dist/lib/cli.js
CHANGED
|
@@ -75,7 +75,8 @@ async function run(app) {
|
|
|
75
75
|
}
|
|
76
76
|
const preValidationWarnCount = app.logger.warningCount;
|
|
77
77
|
app.validate(project);
|
|
78
|
-
const hadValidationWarnings = app.logger.warningCount !== preValidationWarnCount
|
|
78
|
+
const hadValidationWarnings = app.logger.warningCount !== preValidationWarnCount ||
|
|
79
|
+
app.logger.validationWarningCount != 0;
|
|
79
80
|
if (app.logger.hasErrors()) {
|
|
80
81
|
return ExitCodes.ValidationError;
|
|
81
82
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { Comment, ReflectionKind } from "../../models/index.js";
|
|
3
|
-
import type { CommentStyle, JsDocCompatibility } from "../../utils/options/declaration.js";
|
|
3
|
+
import type { CommentStyle, JsDocCompatibility, ValidationOptions } from "../../utils/options/declaration.js";
|
|
4
4
|
import type { FileRegistry } from "../../models/FileRegistry.js";
|
|
5
|
-
import {
|
|
5
|
+
import { Logger } from "#utils";
|
|
6
6
|
import type { Context } from "../context.js";
|
|
7
7
|
export interface CommentParserConfig {
|
|
8
8
|
blockTags: Set<string>;
|
|
@@ -13,6 +13,7 @@ export interface CommentParserConfig {
|
|
|
13
13
|
suppressCommentWarningsInDeclarationFiles: boolean;
|
|
14
14
|
useTsLinkResolution: boolean;
|
|
15
15
|
commentStyle: CommentStyle;
|
|
16
|
+
validationOptions: ValidationOptions;
|
|
16
17
|
}
|
|
17
18
|
export interface CommentContext {
|
|
18
19
|
config: CommentParserConfig;
|
|
@@ -4,7 +4,7 @@ import { lexBlockComment } from "./blockLexer.js";
|
|
|
4
4
|
import { discoverComment, discoverFileComments, discoverNodeComment, discoverSignatureComment, } from "./discovery.js";
|
|
5
5
|
import { lexLineComments } from "./lineLexer.js";
|
|
6
6
|
import { parseComment } from "./parser.js";
|
|
7
|
-
import { assertNever, i18n } from "#utils";
|
|
7
|
+
import { assertNever, i18n, Logger, setUnion } from "#utils";
|
|
8
8
|
const jsDocCommentKinds = [
|
|
9
9
|
ts.SyntaxKind.JSDocPropertyTag,
|
|
10
10
|
ts.SyntaxKind.JSDocCallbackTag,
|
|
@@ -21,16 +21,10 @@ export function clearCommentCache() {
|
|
|
21
21
|
commentCache = new WeakMap();
|
|
22
22
|
commentDiscoveryId = 0;
|
|
23
23
|
}
|
|
24
|
-
function
|
|
24
|
+
function getCommentIgnoringCacheNoDiscoveryId(discovered, context) {
|
|
25
25
|
if (!discovered)
|
|
26
26
|
return;
|
|
27
27
|
const { file, ranges, jsDoc } = discovered;
|
|
28
|
-
const cache = commentCache.get(file) || new Map();
|
|
29
|
-
if (cache.has(ranges[0].pos)) {
|
|
30
|
-
const clone = cache.get(ranges[0].pos).clone();
|
|
31
|
-
clone.inheritedFromParentDeclaration = discovered.inheritedFromParentDeclaration;
|
|
32
|
-
return clone;
|
|
33
|
-
}
|
|
34
28
|
let comment;
|
|
35
29
|
switch (ranges[0].kind) {
|
|
36
30
|
case ts.SyntaxKind.MultiLineCommentTrivia:
|
|
@@ -42,8 +36,23 @@ function getCommentWithCache(discovered, context) {
|
|
|
42
36
|
default:
|
|
43
37
|
assertNever(ranges[0].kind);
|
|
44
38
|
}
|
|
45
|
-
comment.discoveryId = ++commentDiscoveryId;
|
|
46
39
|
comment.inheritedFromParentDeclaration = discovered.inheritedFromParentDeclaration;
|
|
40
|
+
return comment;
|
|
41
|
+
}
|
|
42
|
+
function getCommentWithCache(discovered, context) {
|
|
43
|
+
if (!discovered)
|
|
44
|
+
return;
|
|
45
|
+
const { file, ranges } = discovered;
|
|
46
|
+
const cache = commentCache.get(file) || new Map();
|
|
47
|
+
if (cache.has(ranges[0].pos)) {
|
|
48
|
+
const clone = cache.get(ranges[0].pos).clone();
|
|
49
|
+
clone.inheritedFromParentDeclaration = discovered.inheritedFromParentDeclaration;
|
|
50
|
+
return clone;
|
|
51
|
+
}
|
|
52
|
+
const comment = getCommentIgnoringCacheNoDiscoveryId(discovered, context);
|
|
53
|
+
if (!comment)
|
|
54
|
+
return;
|
|
55
|
+
comment.discoveryId = ++commentDiscoveryId;
|
|
47
56
|
cache.set(ranges[0].pos, comment);
|
|
48
57
|
commentCache.set(file, cache);
|
|
49
58
|
return comment.clone();
|
|
@@ -99,14 +108,24 @@ export function getNodeComment(node, moduleComment, context) {
|
|
|
99
108
|
return getCommentImpl(discoverNodeComment(node, context.config.commentStyle), moduleComment, context);
|
|
100
109
|
}
|
|
101
110
|
export function getFileComment(file, context) {
|
|
111
|
+
const quietContext = {
|
|
112
|
+
...context,
|
|
113
|
+
logger: new Logger(),
|
|
114
|
+
};
|
|
102
115
|
for (const commentSource of discoverFileComments(file, context.config.commentStyle)) {
|
|
103
|
-
|
|
116
|
+
// First parse the comment without adding the parse to the cache
|
|
117
|
+
// and without logging any messages. If we end up not using this as
|
|
118
|
+
// a file comment we want to avoid parsing it with warnings here as
|
|
119
|
+
// it might be associated with a JSDoc parse which has special
|
|
120
|
+
// handling to allow modifier tags to be specified as {@mod}
|
|
121
|
+
// and if it gets added to the cache here we'll get unwanted warnings
|
|
122
|
+
const comment = getCommentIgnoringCacheNoDiscoveryId(commentSource, quietContext);
|
|
104
123
|
if (comment?.getTag("@license") || comment?.getTag("@import")) {
|
|
105
124
|
continue;
|
|
106
125
|
}
|
|
107
126
|
if (comment?.getTag("@module") ||
|
|
108
127
|
comment?.hasModifier("@packageDocumentation")) {
|
|
109
|
-
return
|
|
128
|
+
return getCommentWithCache(commentSource, context);
|
|
110
129
|
}
|
|
111
130
|
return;
|
|
112
131
|
}
|
|
@@ -127,6 +146,33 @@ function getConstructorParamPropertyComment(symbol, context) {
|
|
|
127
146
|
export function getSignatureComment(declaration, context) {
|
|
128
147
|
return getCommentImpl(discoverSignatureComment(declaration, context.checker, context.config.commentStyle), false, context);
|
|
129
148
|
}
|
|
149
|
+
function buildJsDocCommentFromParts(declaration, parts, sourceComment, context) {
|
|
150
|
+
if (!parts) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const comment = new Comment(Comment.cloneDisplayParts(parts));
|
|
154
|
+
comment.sourcePath = sourceComment.sourcePath;
|
|
155
|
+
for (let i = 0; i < comment.summary.length;) {
|
|
156
|
+
const part = comment.summary[i];
|
|
157
|
+
if (part.kind === "inline-tag" &&
|
|
158
|
+
!part.text.trim() &&
|
|
159
|
+
context.config.modifierTags.has(part.tag)) {
|
|
160
|
+
comment.modifierTags.add(part.tag);
|
|
161
|
+
comment.summary.splice(i, 1);
|
|
162
|
+
}
|
|
163
|
+
else if (part.kind === "inline-tag" &&
|
|
164
|
+
part.text.trim() &&
|
|
165
|
+
context.config.modifierTags.has(part.tag) &&
|
|
166
|
+
!context.config.inlineTags.has(part.tag)) {
|
|
167
|
+
context.logger.warn(i18n.inline_tag_0_not_parsed_as_modifier_tag_1(part.tag, part.text.trim()), declaration);
|
|
168
|
+
++i;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
++i;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return comment;
|
|
175
|
+
}
|
|
130
176
|
export function getJsDocComment(declaration, context) {
|
|
131
177
|
const file = declaration.getSourceFile();
|
|
132
178
|
// First, get the whole comment. We know we'll need all of it.
|
|
@@ -134,6 +180,15 @@ export function getJsDocComment(declaration, context) {
|
|
|
134
180
|
while (!ts.isJSDoc(parent)) {
|
|
135
181
|
parent = parent.parent;
|
|
136
182
|
}
|
|
183
|
+
// Build a custom context to allow modifier tags to be written as inline
|
|
184
|
+
// tags as otherwise there's no way to specify them here #2916 #3050
|
|
185
|
+
const contextWithInline = {
|
|
186
|
+
...context,
|
|
187
|
+
config: {
|
|
188
|
+
...context.config,
|
|
189
|
+
inlineTags: setUnion(context.config.inlineTags, context.config.modifierTags),
|
|
190
|
+
},
|
|
191
|
+
};
|
|
137
192
|
// Then parse it.
|
|
138
193
|
const comment = getCommentWithCache({
|
|
139
194
|
file,
|
|
@@ -146,12 +201,10 @@ export function getJsDocComment(declaration, context) {
|
|
|
146
201
|
],
|
|
147
202
|
jsDoc: parent,
|
|
148
203
|
inheritedFromParentDeclaration: false,
|
|
149
|
-
},
|
|
204
|
+
}, contextWithInline);
|
|
150
205
|
// And pull out the tag we actually care about.
|
|
151
206
|
if (ts.isJSDocEnumTag(declaration)) {
|
|
152
|
-
|
|
153
|
-
result.sourcePath = comment.sourcePath;
|
|
154
|
-
return result;
|
|
207
|
+
return buildJsDocCommentFromParts(declaration, comment.getTag("@enum")?.content, comment, context);
|
|
155
208
|
}
|
|
156
209
|
if (ts.isJSDocTemplateTag(declaration) &&
|
|
157
210
|
declaration.comment &&
|
|
@@ -183,8 +236,6 @@ export function getJsDocComment(declaration, context) {
|
|
|
183
236
|
}
|
|
184
237
|
}
|
|
185
238
|
else {
|
|
186
|
-
|
|
187
|
-
result.sourcePath = comment.sourcePath;
|
|
188
|
-
return result;
|
|
239
|
+
return buildJsDocCommentFromParts(declaration, tag.content, comment, context);
|
|
189
240
|
}
|
|
190
241
|
}
|
|
@@ -45,12 +45,12 @@ export function parseComment(tokens, file, context) {
|
|
|
45
45
|
const tok = lexer.done() || lexer.peek();
|
|
46
46
|
const comment = new Comment();
|
|
47
47
|
comment.sourcePath = file.fileName;
|
|
48
|
-
comment.summary = blockContent(comment, lexer, context.config,
|
|
48
|
+
comment.summary = blockContent(comment, lexer, context.config, warningImpl, validationWarningImpl, context.files);
|
|
49
49
|
while (!lexer.done()) {
|
|
50
|
-
comment.blockTags.push(blockTag(comment, lexer, context.config,
|
|
50
|
+
comment.blockTags.push(blockTag(comment, lexer, context.config, warningImpl, validationWarningImpl, context.files));
|
|
51
51
|
}
|
|
52
52
|
const tok2 = tok;
|
|
53
|
-
postProcessComment(comment,
|
|
53
|
+
postProcessComment(comment, () => `${nicePath(file.fileName)}:${file.getLineAndCharacterOfPosition(tok2.pos).line + 1}`, (message) => context.logger.warn(message));
|
|
54
54
|
return comment;
|
|
55
55
|
function warningImpl(message, token) {
|
|
56
56
|
if (context.config.suppressCommentWarningsInDeclarationFiles &&
|
|
@@ -59,6 +59,13 @@ export function parseComment(tokens, file, context) {
|
|
|
59
59
|
}
|
|
60
60
|
context.logger.warn(message, token.pos, file);
|
|
61
61
|
}
|
|
62
|
+
function validationWarningImpl(message, token) {
|
|
63
|
+
if (context.config.suppressCommentWarningsInDeclarationFiles &&
|
|
64
|
+
hasDeclarationFileExtension(file.fileName)) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
context.logger.validationWarning(message, token.pos, file);
|
|
68
|
+
}
|
|
62
69
|
}
|
|
63
70
|
/**
|
|
64
71
|
* Intended for parsing markdown documents. This only parses code blocks and
|
|
@@ -95,13 +102,22 @@ export function parseCommentString(tokens, config, file, logger, files) {
|
|
|
95
102
|
case TokenSyntaxKind.Text:
|
|
96
103
|
case TokenSyntaxKind.Tag:
|
|
97
104
|
case TokenSyntaxKind.CloseBrace:
|
|
98
|
-
textContent(
|
|
105
|
+
textContent({
|
|
106
|
+
sourcePath: file.fileName,
|
|
107
|
+
token: next,
|
|
108
|
+
warning: (msg, token) => logger.warn(msg, token.pos, file),
|
|
109
|
+
validationWarning: (msg, token) => logger.validationWarning(msg, token.pos, file),
|
|
110
|
+
files,
|
|
111
|
+
atNewLine,
|
|
112
|
+
validationOptions: config.validationOptions,
|
|
113
|
+
},
|
|
114
|
+
/* out */ content, reentry);
|
|
99
115
|
break;
|
|
100
116
|
case TokenSyntaxKind.Code:
|
|
101
117
|
content.push({ kind: "code", text: next.text });
|
|
102
118
|
break;
|
|
103
119
|
case TokenSyntaxKind.OpenBrace:
|
|
104
|
-
inlineTag(lexer, content, suppressWarningsConfig,
|
|
120
|
+
inlineTag(lexer, content, suppressWarningsConfig, (message, token) => logger.warn(message, token.pos, file));
|
|
105
121
|
consume = false;
|
|
106
122
|
break;
|
|
107
123
|
default:
|
|
@@ -161,7 +177,7 @@ function makeCodeBlock(text) {
|
|
|
161
177
|
* Loop over comment, produce lint warnings, and set tag names for tags
|
|
162
178
|
* which have them.
|
|
163
179
|
*/
|
|
164
|
-
function postProcessComment(comment,
|
|
180
|
+
function postProcessComment(comment, getPosition, warning) {
|
|
165
181
|
for (const tag of comment.blockTags) {
|
|
166
182
|
if (HAS_USER_IDENTIFIER.includes(tag.tag) && tag.content.length) {
|
|
167
183
|
const first = tag.content[0];
|
|
@@ -211,7 +227,7 @@ function postProcessComment(comment, i18n, getPosition, warning) {
|
|
|
211
227
|
}
|
|
212
228
|
}
|
|
213
229
|
const aliasedTags = new Map([["@return", "@returns"]]);
|
|
214
|
-
function blockTag(comment, lexer, config,
|
|
230
|
+
function blockTag(comment, lexer, config, warning, validationWarning, files) {
|
|
215
231
|
const blockTag = lexer.take();
|
|
216
232
|
ok(blockTag.kind === TokenSyntaxKind.Tag, "blockTag called not at the start of a block tag."); // blockContent is broken if this fails.
|
|
217
233
|
if (!config.blockTags.has(blockTag.text)) {
|
|
@@ -220,7 +236,7 @@ function blockTag(comment, lexer, config, i18n, warning, files) {
|
|
|
220
236
|
const tagName = aliasedTags.get(blockTag.text) || blockTag.text;
|
|
221
237
|
let content;
|
|
222
238
|
if (tagName === "@example") {
|
|
223
|
-
return exampleBlock(comment, lexer, config,
|
|
239
|
+
return exampleBlock(comment, lexer, config, warning, validationWarning, files);
|
|
224
240
|
}
|
|
225
241
|
let typeAnnotation;
|
|
226
242
|
if (!lexer.done() &&
|
|
@@ -234,10 +250,10 @@ function blockTag(comment, lexer, config, i18n, warning, files) {
|
|
|
234
250
|
}
|
|
235
251
|
if (["@default", "@defaultValue"].includes(tagName) &&
|
|
236
252
|
config.jsDocCompatibility.defaultTag) {
|
|
237
|
-
content = defaultBlockContent(comment, lexer, config,
|
|
253
|
+
content = defaultBlockContent(comment, lexer, config, warning, validationWarning, files);
|
|
238
254
|
}
|
|
239
255
|
else {
|
|
240
|
-
content = blockContent(comment, lexer, config,
|
|
256
|
+
content = blockContent(comment, lexer, config, warning, validationWarning, files);
|
|
241
257
|
}
|
|
242
258
|
const tag = new CommentTag(tagName, content);
|
|
243
259
|
if (typeAnnotation) {
|
|
@@ -249,14 +265,14 @@ function blockTag(comment, lexer, config, i18n, warning, files) {
|
|
|
249
265
|
* The `@default` tag gets a special case because otherwise we will produce many warnings
|
|
250
266
|
* about unescaped/mismatched/missing braces in legacy JSDoc comments
|
|
251
267
|
*/
|
|
252
|
-
function defaultBlockContent(comment, lexer, config,
|
|
268
|
+
function defaultBlockContent(comment, lexer, config, warning, validationWarning, files) {
|
|
253
269
|
lexer.mark();
|
|
254
270
|
const tempRegistry = new FileRegistry();
|
|
255
|
-
const content = blockContent(comment, lexer, config,
|
|
271
|
+
const content = blockContent(comment, lexer, config, () => { }, () => { }, tempRegistry);
|
|
256
272
|
const end = lexer.done() || lexer.peek();
|
|
257
273
|
lexer.release();
|
|
258
274
|
if (content.some((part) => part.kind === "code" || part.kind === "inline-tag")) {
|
|
259
|
-
return blockContent(comment, lexer, config,
|
|
275
|
+
return blockContent(comment, lexer, config, warning, validationWarning, files);
|
|
260
276
|
}
|
|
261
277
|
const tokens = [];
|
|
262
278
|
while ((lexer.done() || lexer.peek()) !== end) {
|
|
@@ -279,10 +295,10 @@ function defaultBlockContent(comment, lexer, config, i18n, warning, files) {
|
|
|
279
295
|
*
|
|
280
296
|
* In TSDoc, we also want to treat the first line of the block as the example name.
|
|
281
297
|
*/
|
|
282
|
-
function exampleBlock(comment, lexer, config,
|
|
298
|
+
function exampleBlock(comment, lexer, config, warning, validationWarning, files) {
|
|
283
299
|
lexer.mark();
|
|
284
300
|
const tempRegistry = new FileRegistry();
|
|
285
|
-
const content = blockContent(comment, lexer, config,
|
|
301
|
+
const content = blockContent(comment, lexer, config, () => { }, () => { }, tempRegistry);
|
|
286
302
|
const end = lexer.done() || lexer.peek();
|
|
287
303
|
lexer.release();
|
|
288
304
|
if (!config.jsDocCompatibility.exampleTag ||
|
|
@@ -323,7 +339,7 @@ function exampleBlock(comment, lexer, config, i18n, warning, files) {
|
|
|
323
339
|
assertNever(next.kind);
|
|
324
340
|
}
|
|
325
341
|
}
|
|
326
|
-
const content = blockContent(comment, lexer, config,
|
|
342
|
+
const content = blockContent(comment, lexer, config, warning, validationWarning, files);
|
|
327
343
|
const tag = new CommentTag("@example", content);
|
|
328
344
|
if (exampleName.trim()) {
|
|
329
345
|
tag.name = exampleName.trim();
|
|
@@ -362,7 +378,7 @@ function exampleBlock(comment, lexer, config, i18n, warning, files) {
|
|
|
362
378
|
* If you change this, also look at parseCommentString as it
|
|
363
379
|
* likely needs similar modifications to ensure parsing is consistent.
|
|
364
380
|
*/
|
|
365
|
-
function blockContent(comment, lexer, config,
|
|
381
|
+
function blockContent(comment, lexer, config, warning, validationWarning, files) {
|
|
366
382
|
const content = [];
|
|
367
383
|
let atNewLine = true;
|
|
368
384
|
const reentry = new TextParserReentryState();
|
|
@@ -375,8 +391,16 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
|
|
|
375
391
|
content.push({ kind: "text", text: next.text });
|
|
376
392
|
break;
|
|
377
393
|
case TokenSyntaxKind.Text:
|
|
378
|
-
textContent(
|
|
379
|
-
|
|
394
|
+
textContent({
|
|
395
|
+
sourcePath: comment.sourcePath,
|
|
396
|
+
token: next,
|
|
397
|
+
files,
|
|
398
|
+
atNewLine,
|
|
399
|
+
warning,
|
|
400
|
+
validationWarning,
|
|
401
|
+
validationOptions: config.validationOptions,
|
|
402
|
+
},
|
|
403
|
+
/*out*/ content, reentry);
|
|
380
404
|
break;
|
|
381
405
|
case TokenSyntaxKind.Code:
|
|
382
406
|
content.push({ kind: "code", text: next.text });
|
|
@@ -414,7 +438,7 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
|
|
|
414
438
|
content.push({ kind: "text", text: next.text });
|
|
415
439
|
break;
|
|
416
440
|
case TokenSyntaxKind.OpenBrace:
|
|
417
|
-
inlineTag(lexer, content, config,
|
|
441
|
+
inlineTag(lexer, content, config, warning);
|
|
418
442
|
consume = false;
|
|
419
443
|
break;
|
|
420
444
|
default:
|
|
@@ -451,7 +475,7 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
|
|
|
451
475
|
}
|
|
452
476
|
return content;
|
|
453
477
|
}
|
|
454
|
-
function inlineTag(lexer, block, config,
|
|
478
|
+
function inlineTag(lexer, block, config, warning) {
|
|
455
479
|
const openBrace = lexer.take();
|
|
456
480
|
// Now skip whitespace to grab the tag name.
|
|
457
481
|
// If the first non-whitespace text after the brace isn't a tag,
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parser to handle plain text markdown.
|
|
3
|
-
*
|
|
4
|
-
* Responsible for recognizing relative paths within the text and turning
|
|
5
|
-
* them into references.
|
|
6
|
-
* @module
|
|
7
|
-
*/
|
|
8
|
-
import type { TranslationProxy } from "../../internationalization/index.js";
|
|
9
1
|
import type { CommentDisplayPart } from "../../models/index.js";
|
|
10
2
|
import type { FileRegistry } from "../../models/FileRegistry.js";
|
|
3
|
+
import { type ValidationOptions } from "#node-utils";
|
|
11
4
|
import { type Token } from "./lexer.js";
|
|
12
5
|
import type { NormalizedPath, TranslatedString } from "#utils";
|
|
6
|
+
interface TextParserData {
|
|
7
|
+
sourcePath: NormalizedPath;
|
|
8
|
+
token: Token;
|
|
9
|
+
pos: number;
|
|
10
|
+
warning: (msg: TranslatedString, token: Token) => void;
|
|
11
|
+
validationWarning: (msg: TranslatedString, token: Token) => void;
|
|
12
|
+
files: FileRegistry;
|
|
13
|
+
atNewLine: boolean;
|
|
14
|
+
validationOptions: ValidationOptions;
|
|
15
|
+
}
|
|
13
16
|
/**
|
|
14
17
|
* This is incredibly unfortunate. The comment lexer owns the responsibility
|
|
15
18
|
* for splitting up text into text/code, this is totally fine for HTML links
|
|
@@ -26,4 +29,5 @@ export declare class TextParserReentryState {
|
|
|
26
29
|
* Look for relative links within a piece of text and add them to the {@link FileRegistry}
|
|
27
30
|
* so that they can be correctly resolved during rendering.
|
|
28
31
|
*/
|
|
29
|
-
export declare function textContent(
|
|
32
|
+
export declare function textContent(parserData: Omit<TextParserData, "pos">, outContent: CommentDisplayPart[], reentry: TextParserReentryState): void;
|
|
33
|
+
export {};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser to handle plain text markdown.
|
|
3
|
+
*
|
|
4
|
+
* Responsible for recognizing relative paths within the text and turning
|
|
5
|
+
* them into references.
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { i18n } from "#utils";
|
|
1
9
|
import { HtmlAttributeParser, ParserState } from "#node-utils";
|
|
2
10
|
import { TokenSyntaxKind } from "./lexer.js";
|
|
3
11
|
import MarkdownIt from "markdown-it";
|
|
@@ -34,42 +42,38 @@ export class TextParserReentryState {
|
|
|
34
42
|
* Look for relative links within a piece of text and add them to the {@link FileRegistry}
|
|
35
43
|
* so that they can be correctly resolved during rendering.
|
|
36
44
|
*/
|
|
37
|
-
export function textContent(
|
|
45
|
+
export function textContent(parserData, outContent, reentry) {
|
|
38
46
|
let lastPartEnd = 0;
|
|
39
47
|
let canEndMarkdownLink = true;
|
|
40
48
|
const data = {
|
|
41
|
-
|
|
42
|
-
token,
|
|
49
|
+
...parserData,
|
|
43
50
|
pos: 0, // relative to the token
|
|
44
|
-
warning,
|
|
45
|
-
files: files,
|
|
46
|
-
atNewLine,
|
|
47
51
|
};
|
|
48
52
|
function addRef(ref) {
|
|
49
53
|
canEndMarkdownLink = true;
|
|
50
54
|
outContent.push({
|
|
51
55
|
kind: "text",
|
|
52
|
-
text: token.text.slice(lastPartEnd, ref.pos),
|
|
56
|
+
text: data.token.text.slice(lastPartEnd, ref.pos),
|
|
53
57
|
});
|
|
54
58
|
const link = {
|
|
55
59
|
kind: "relative-link",
|
|
56
|
-
text: token.text.slice(ref.pos, ref.end),
|
|
60
|
+
text: data.token.text.slice(ref.pos, ref.end),
|
|
57
61
|
target: ref.target,
|
|
58
62
|
targetAnchor: ref.targetAnchor,
|
|
59
63
|
};
|
|
60
64
|
outContent.push(link);
|
|
61
65
|
lastPartEnd = ref.end;
|
|
62
66
|
data.pos = ref.end;
|
|
63
|
-
if (!ref.target) {
|
|
64
|
-
|
|
67
|
+
if (!ref.target && data.validationOptions.invalidPath) {
|
|
68
|
+
data.validationWarning(i18n.relative_path_0_is_not_a_file_and_will_not_be_copied_to_output(data.token.text.slice(ref.pos, ref.end)), {
|
|
65
69
|
kind: TokenSyntaxKind.Text,
|
|
66
70
|
// ref.pos is relative to the token, but this pos is relative to the file.
|
|
67
|
-
pos: token.pos + ref.pos,
|
|
68
|
-
text: token.text.slice(ref.pos, ref.end),
|
|
71
|
+
pos: data.token.pos + ref.pos,
|
|
72
|
+
text: data.token.text.slice(ref.pos, ref.end),
|
|
69
73
|
});
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
|
-
while (data.pos < token.text.length) {
|
|
76
|
+
while (data.pos < data.token.text.length) {
|
|
73
77
|
if (canEndMarkdownLink) {
|
|
74
78
|
const link = checkMarkdownLink(data, reentry);
|
|
75
79
|
if (link) {
|
|
@@ -92,14 +96,14 @@ export function textContent(sourcePath, token, i18n, warning, outContent, files,
|
|
|
92
96
|
}
|
|
93
97
|
continue;
|
|
94
98
|
}
|
|
95
|
-
const atNewLine = token.text[data.pos] === "\n";
|
|
99
|
+
const atNewLine = data.token.text[data.pos] === "\n";
|
|
96
100
|
data.atNewLine = atNewLine;
|
|
97
101
|
if (atNewLine && !reentry.withinLinkDest)
|
|
98
102
|
canEndMarkdownLink = true;
|
|
99
103
|
++data.pos;
|
|
100
104
|
}
|
|
101
|
-
if (lastPartEnd !== token.text.length) {
|
|
102
|
-
outContent.push({ kind: "text", text: token.text.slice(lastPartEnd) });
|
|
105
|
+
if (lastPartEnd !== data.token.text.length) {
|
|
106
|
+
outContent.push({ kind: "text", text: data.token.text.slice(lastPartEnd) });
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
@@ -245,6 +249,7 @@ function checkTagLink(data) {
|
|
|
245
249
|
if (token.text.startsWith("<link ", pos)) {
|
|
246
250
|
data.pos += 4;
|
|
247
251
|
return checkAttributes(data, {
|
|
252
|
+
// cspell:words imagesrcset
|
|
248
253
|
imagesrcset: checkAttributeSrcSet,
|
|
249
254
|
});
|
|
250
255
|
}
|
|
@@ -614,6 +614,7 @@ let Converter = (() => {
|
|
|
614
614
|
suppressCommentWarningsInDeclarationFiles: this.application.options.getValue("suppressCommentWarningsInDeclarationFiles"),
|
|
615
615
|
useTsLinkResolution: this.application.options.getValue("useTsLinkResolution"),
|
|
616
616
|
commentStyle: this.application.options.getValue("commentStyle"),
|
|
617
|
+
validationOptions: this.application.options.getValue("validation"),
|
|
617
618
|
};
|
|
618
619
|
// Can't be included in options because the TSDoc parser blows up if we do.
|
|
619
620
|
// TypeDoc supports it as one, so it should always be included here.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { ParameterReflection, type Reflection, ReflectionKind, SignatureReflection, TypeParameterReflection } from "../../models/index.js";
|
|
3
3
|
import type { Context } from "../context.js";
|
|
4
|
+
export declare function convertConstructSignatures(context: Context, symbol: ts.Symbol): void;
|
|
4
5
|
export declare function createSignature(context: Context, kind: ReflectionKind.CallSignature | ReflectionKind.ConstructorSignature | ReflectionKind.GetSignature | ReflectionKind.SetSignature, signature: ts.Signature, symbol: ts.Symbol | undefined, declaration?: ts.SignatureDeclaration | ts.JSDocSignature): void;
|
|
5
6
|
/**
|
|
6
7
|
* Special cased constructor factory for functions tagged with `@class`
|
|
@@ -4,6 +4,19 @@ import { DeclarationReflection, IntrinsicType, ParameterReflection, PredicateTyp
|
|
|
4
4
|
import { ConverterEvents } from "../converter-events.js";
|
|
5
5
|
import { convertDefaultValue } from "../convert-expression.js";
|
|
6
6
|
import { removeUndefined } from "../utils/reflections.js";
|
|
7
|
+
export function convertConstructSignatures(context, symbol) {
|
|
8
|
+
const type = context.checker.getDeclaredTypeOfSymbol(symbol);
|
|
9
|
+
// These get added as a "constructor" member of this interface. This is a problem... but nobody
|
|
10
|
+
// has complained yet. We really ought to have a constructSignatures property on the reflection instead.
|
|
11
|
+
const constructSignatures = context.checker.getSignaturesOfType(type, ts.SignatureKind.Construct);
|
|
12
|
+
if (constructSignatures.length) {
|
|
13
|
+
const constructMember = new DeclarationReflection("constructor", ReflectionKind.Constructor, context.scope);
|
|
14
|
+
context.postReflectionCreation(constructMember, symbol, void 0);
|
|
15
|
+
context.finalizeDeclarationReflection(constructMember);
|
|
16
|
+
const constructContext = context.withScope(constructMember);
|
|
17
|
+
constructSignatures.forEach((sig) => createSignature(constructContext, ReflectionKind.ConstructorSignature, sig, symbol));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
7
20
|
export function createSignature(context, kind, signature, symbol, declaration) {
|
|
8
21
|
assert(context.scope instanceof DeclarationReflection);
|
|
9
22
|
declaration ||= signature.getDeclaration();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import type { Context } from "./context.js";
|
|
3
|
-
export declare function convertJsDocAlias(context: Context, symbol: ts.Symbol, declaration: ts.JSDocTypedefTag | ts.JSDocEnumTag, exportSymbol?: ts.Symbol):
|
|
3
|
+
export declare function convertJsDocAlias(context: Context, symbol: ts.Symbol, declaration: ts.JSDocTypedefTag | ts.JSDocEnumTag, exportSymbol?: ts.Symbol): undefined;
|
|
4
4
|
export declare function convertJsDocCallback(context: Context, symbol: ts.Symbol, declaration: ts.JSDocCallbackTag, exportSymbol?: ts.Symbol): void;
|
|
@@ -5,13 +5,44 @@ import { ok } from "assert";
|
|
|
5
5
|
import ts from "typescript";
|
|
6
6
|
import { DeclarationReflection, IntrinsicType, ReflectionKind, ReflectionType, SignatureReflection, } from "../models/index.js";
|
|
7
7
|
import { ConverterEvents } from "./converter-events.js";
|
|
8
|
-
import { convertParameterNodes, convertTemplateParameterNodes } from "./factories/signature.js";
|
|
8
|
+
import { convertConstructSignatures, convertParameterNodes, convertTemplateParameterNodes, createSignature, } from "./factories/signature.js";
|
|
9
|
+
import { i18n } from "#utils";
|
|
10
|
+
import { convertIndexSignatures } from "./factories/index-signature.js";
|
|
11
|
+
// This is almost convertTypeAliasAsInterface, but unfortunately needs to be separate
|
|
12
|
+
// due to type parameters being different in JSDoc comments
|
|
13
|
+
function convertJsDocAliasAsInterface(context, symbol, exportSymbol, declaration) {
|
|
14
|
+
const reflection = context.createDeclarationReflection(ReflectionKind.Interface, symbol, exportSymbol);
|
|
15
|
+
context.finalizeDeclarationReflection(reflection);
|
|
16
|
+
const rc = context.withScope(reflection);
|
|
17
|
+
const type = context.checker.getTypeAtLocation(declaration);
|
|
18
|
+
if (type.getFlags() & ts.TypeFlags.Union) {
|
|
19
|
+
context.logger.warn(i18n.converting_union_as_interface(), declaration);
|
|
20
|
+
}
|
|
21
|
+
// Interfaces have properties
|
|
22
|
+
for (const prop of type.getProperties()) {
|
|
23
|
+
context.converter.convertSymbol(rc, prop);
|
|
24
|
+
}
|
|
25
|
+
// And type parameters
|
|
26
|
+
convertTemplateParameters(rc, declaration.parent);
|
|
27
|
+
// And maybe call signatures
|
|
28
|
+
context.checker
|
|
29
|
+
.getSignaturesOfType(type, ts.SignatureKind.Call)
|
|
30
|
+
.forEach((sig) => createSignature(rc, ReflectionKind.CallSignature, sig, symbol));
|
|
31
|
+
// And maybe constructor signatures
|
|
32
|
+
convertConstructSignatures(rc, symbol);
|
|
33
|
+
// And finally, index signatures
|
|
34
|
+
convertIndexSignatures(rc, type);
|
|
35
|
+
}
|
|
9
36
|
export function convertJsDocAlias(context, symbol, declaration, exportSymbol) {
|
|
10
37
|
if (declaration.typeExpression &&
|
|
11
38
|
ts.isJSDocTypeLiteral(declaration.typeExpression)) {
|
|
12
39
|
convertJsDocInterface(context, declaration, symbol, exportSymbol);
|
|
13
40
|
return;
|
|
14
41
|
}
|
|
42
|
+
const comment = context.getJsDocComment(declaration);
|
|
43
|
+
if (comment?.hasModifier("@interface")) {
|
|
44
|
+
return convertJsDocAliasAsInterface(context, symbol, exportSymbol, declaration);
|
|
45
|
+
}
|
|
15
46
|
// If the typedef tag is just referring to another type-space symbol, with no type parameters
|
|
16
47
|
// or appropriate forwarding type parameters, then we treat it as a re-export instead of creating
|
|
17
48
|
// a type alias with an import type.
|
|
@@ -21,7 +52,7 @@ export function convertJsDocAlias(context, symbol, declaration, exportSymbol) {
|
|
|
21
52
|
return;
|
|
22
53
|
}
|
|
23
54
|
const reflection = context.createDeclarationReflection(ReflectionKind.TypeAlias, symbol, exportSymbol);
|
|
24
|
-
reflection.comment =
|
|
55
|
+
reflection.comment = comment;
|
|
25
56
|
reflection.type = context.converter.convertType(context.withScope(reflection), declaration.typeExpression?.type);
|
|
26
57
|
convertTemplateParameters(context.withScope(reflection), declaration.parent);
|
|
27
58
|
context.finalizeDeclarationReflection(reflection);
|
|
@@ -290,6 +290,8 @@ let CommentPlugin = (() => {
|
|
|
290
290
|
* @param reflection The reflection that is currently processed.
|
|
291
291
|
*/
|
|
292
292
|
onCreateTypeParameter(_context, reflection) {
|
|
293
|
+
if (reflection.comment)
|
|
294
|
+
return;
|
|
293
295
|
const comment = reflection.parent?.comment;
|
|
294
296
|
if (comment) {
|
|
295
297
|
let tag = comment.getIdentifiedTag(reflection.name, "@typeParam");
|
|
@@ -306,6 +308,17 @@ let CommentPlugin = (() => {
|
|
|
306
308
|
reflection.comment = new Comment(tag.content);
|
|
307
309
|
reflection.comment.sourcePath = comment.sourcePath;
|
|
308
310
|
removeIfPresent(comment.blockTags, tag);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// #3031 if this is a class constructor, also check for type parameters
|
|
315
|
+
// that live on the class itself and potentially copy their comment.
|
|
316
|
+
if (reflection.parent?.kindOf(ReflectionKind.ConstructorSignature) &&
|
|
317
|
+
reflection.parent.parent?.kindOf(ReflectionKind.Constructor)) {
|
|
318
|
+
const cls = reflection.parent.parent.parent;
|
|
319
|
+
const typeParam = cls.typeParameters?.find(param => param.name === reflection.name);
|
|
320
|
+
if (typeParam?.comment) {
|
|
321
|
+
reflection.comment = typeParam.comment.clone();
|
|
309
322
|
}
|
|
310
323
|
}
|
|
311
324
|
}
|