typedoc 0.28.13 → 0.28.15

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.
Files changed (52) hide show
  1. package/dist/lib/cli.js +2 -1
  2. package/dist/lib/converter/comments/index.d.ts +3 -1
  3. package/dist/lib/converter/comments/parser.js +61 -23
  4. package/dist/lib/converter/comments/textParser.d.ts +13 -9
  5. package/dist/lib/converter/comments/textParser.js +21 -16
  6. package/dist/lib/converter/converter.js +2 -0
  7. package/dist/lib/converter/factories/signature.js +5 -4
  8. package/dist/lib/converter/plugins/CommentPlugin.d.ts +1 -0
  9. package/dist/lib/converter/plugins/CommentPlugin.js +48 -11
  10. package/dist/lib/converter/symbols.js +15 -8
  11. package/dist/lib/converter/types.js +18 -6
  12. package/dist/lib/converter/utils/repository.js +3 -0
  13. package/dist/lib/internationalization/locales/de.cjs +0 -1
  14. package/dist/lib/internationalization/locales/de.d.cts +0 -1
  15. package/dist/lib/internationalization/locales/en.cjs +3 -1
  16. package/dist/lib/internationalization/locales/en.d.cts +3 -1
  17. package/dist/lib/internationalization/locales/ja.cjs +0 -1
  18. package/dist/lib/internationalization/locales/ja.d.cts +0 -1
  19. package/dist/lib/internationalization/locales/ko.cjs +0 -1
  20. package/dist/lib/internationalization/locales/ko.d.cts +0 -1
  21. package/dist/lib/internationalization/locales/zh.cjs +0 -1
  22. package/dist/lib/internationalization/locales/zh.d.cts +0 -1
  23. package/dist/lib/models/Comment.d.ts +5 -0
  24. package/dist/lib/models/Comment.js +10 -0
  25. package/dist/lib/models/DeclarationReflection.d.ts +7 -0
  26. package/dist/lib/models/DeclarationReflection.js +9 -0
  27. package/dist/lib/output/events.d.ts +2 -0
  28. package/dist/lib/output/events.js +1 -0
  29. package/dist/lib/output/plugins/JavascriptIndexPlugin.js +1 -1
  30. package/dist/lib/output/themes/MarkedPlugin.js +8 -1
  31. package/dist/lib/output/themes/default/Slugger.d.ts +1 -1
  32. package/dist/lib/output/themes/default/Slugger.js +13 -5
  33. package/dist/lib/output/themes/default/partials/comment.js +1 -0
  34. package/dist/lib/output/themes/default/partials/member.js +1 -0
  35. package/dist/lib/output/themes/default/partials/moduleReflection.js +1 -0
  36. package/dist/lib/output/themes/default/partials/navigation.js +1 -1
  37. package/dist/lib/serialization/schema.d.ts +2 -2
  38. package/dist/lib/utils/options/declaration.d.ts +6 -0
  39. package/dist/lib/utils/options/defaults.d.ts +1 -0
  40. package/dist/lib/utils/options/defaults.js +1 -0
  41. package/dist/lib/utils/options/sources/typedoc.js +14 -0
  42. package/dist/lib/utils/options/tsdoc-defaults.d.ts +2 -2
  43. package/dist/lib/utils/options/tsdoc-defaults.js +2 -1
  44. package/dist/lib/utils-common/general.js +2 -0
  45. package/dist/lib/utils-common/logger.d.ts +12 -1
  46. package/dist/lib/utils-common/logger.js +9 -0
  47. package/dist/lib/validation/documentation.js +2 -2
  48. package/dist/lib/validation/exports.js +2 -2
  49. package/dist/lib/validation/links.js +7 -7
  50. package/package.json +14 -14
  51. package/static/style.css +3 -3
  52. package/tsdoc.json +5 -4
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,6 +1,6 @@
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
5
  import { type Logger } from "#utils";
6
6
  import type { Context } from "../context.js";
@@ -8,10 +8,12 @@ export interface CommentParserConfig {
8
8
  blockTags: Set<string>;
9
9
  inlineTags: Set<string>;
10
10
  modifierTags: Set<string>;
11
+ preservedTypeAnnotationTags: Set<string>;
11
12
  jsDocCompatibility: JsDocCompatibility;
12
13
  suppressCommentWarningsInDeclarationFiles: boolean;
13
14
  useTsLinkResolution: boolean;
14
15
  commentStyle: CommentStyle;
16
+ validationOptions: ValidationOptions;
15
17
  }
16
18
  export interface CommentContext {
17
19
  config: CommentParserConfig;
@@ -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, i18n, warningImpl, context.files);
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, i18n, warningImpl, context.files));
50
+ comment.blockTags.push(blockTag(comment, lexer, context.config, warningImpl, validationWarningImpl, context.files));
51
51
  }
52
52
  const tok2 = tok;
53
- postProcessComment(comment, i18n, () => `${nicePath(file.fileName)}:${file.getLineAndCharacterOfPosition(tok2.pos).line + 1}`, (message) => context.logger.warn(message));
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(file.fileName, next, i18n, (msg, token) => logger.warn(msg, token.pos, file), content, files, atNewLine, reentry);
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, i18n, (message, token) => logger.warn(message, token.pos, file));
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, i18n, getPosition, warning) {
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, i18n, warning, files) {
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,29 +236,43 @@ 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, i18n, warning, files);
239
+ return exampleBlock(comment, lexer, config, warning, validationWarning, files);
224
240
  }
225
- else if (["@default", "@defaultValue"].includes(tagName) &&
241
+ let typeAnnotation;
242
+ if (!lexer.done() &&
243
+ config.preservedTypeAnnotationTags.has(tagName)) {
244
+ if (lexer.peek().kind === TokenSyntaxKind.Text && /^\s+$/.test(lexer.peek().text)) {
245
+ lexer.take();
246
+ }
247
+ if (lexer.peek().kind === TokenSyntaxKind.TypeAnnotation) {
248
+ typeAnnotation = lexer.take().text;
249
+ }
250
+ }
251
+ if (["@default", "@defaultValue"].includes(tagName) &&
226
252
  config.jsDocCompatibility.defaultTag) {
227
- content = defaultBlockContent(comment, lexer, config, i18n, warning, files);
253
+ content = defaultBlockContent(comment, lexer, config, warning, validationWarning, files);
228
254
  }
229
255
  else {
230
- content = blockContent(comment, lexer, config, i18n, warning, files);
256
+ content = blockContent(comment, lexer, config, warning, validationWarning, files);
257
+ }
258
+ const tag = new CommentTag(tagName, content);
259
+ if (typeAnnotation) {
260
+ tag.typeAnnotation = typeAnnotation;
231
261
  }
232
- return new CommentTag(tagName, content);
262
+ return tag;
233
263
  }
234
264
  /**
235
265
  * The `@default` tag gets a special case because otherwise we will produce many warnings
236
266
  * about unescaped/mismatched/missing braces in legacy JSDoc comments
237
267
  */
238
- function defaultBlockContent(comment, lexer, config, i18n, warning, files) {
268
+ function defaultBlockContent(comment, lexer, config, warning, validationWarning, files) {
239
269
  lexer.mark();
240
270
  const tempRegistry = new FileRegistry();
241
- const content = blockContent(comment, lexer, config, i18n, () => { }, tempRegistry);
271
+ const content = blockContent(comment, lexer, config, () => { }, () => { }, tempRegistry);
242
272
  const end = lexer.done() || lexer.peek();
243
273
  lexer.release();
244
274
  if (content.some((part) => part.kind === "code" || part.kind === "inline-tag")) {
245
- return blockContent(comment, lexer, config, i18n, warning, files);
275
+ return blockContent(comment, lexer, config, warning, validationWarning, files);
246
276
  }
247
277
  const tokens = [];
248
278
  while ((lexer.done() || lexer.peek()) !== end) {
@@ -265,10 +295,10 @@ function defaultBlockContent(comment, lexer, config, i18n, warning, files) {
265
295
  *
266
296
  * In TSDoc, we also want to treat the first line of the block as the example name.
267
297
  */
268
- function exampleBlock(comment, lexer, config, i18n, warning, files) {
298
+ function exampleBlock(comment, lexer, config, warning, validationWarning, files) {
269
299
  lexer.mark();
270
300
  const tempRegistry = new FileRegistry();
271
- const content = blockContent(comment, lexer, config, i18n, () => { }, tempRegistry);
301
+ const content = blockContent(comment, lexer, config, () => { }, () => { }, tempRegistry);
272
302
  const end = lexer.done() || lexer.peek();
273
303
  lexer.release();
274
304
  if (!config.jsDocCompatibility.exampleTag ||
@@ -309,7 +339,7 @@ function exampleBlock(comment, lexer, config, i18n, warning, files) {
309
339
  assertNever(next.kind);
310
340
  }
311
341
  }
312
- const content = blockContent(comment, lexer, config, i18n, warning, files);
342
+ const content = blockContent(comment, lexer, config, warning, validationWarning, files);
313
343
  const tag = new CommentTag("@example", content);
314
344
  if (exampleName.trim()) {
315
345
  tag.name = exampleName.trim();
@@ -348,7 +378,7 @@ function exampleBlock(comment, lexer, config, i18n, warning, files) {
348
378
  * If you change this, also look at parseCommentString as it
349
379
  * likely needs similar modifications to ensure parsing is consistent.
350
380
  */
351
- function blockContent(comment, lexer, config, i18n, warning, files) {
381
+ function blockContent(comment, lexer, config, warning, validationWarning, files) {
352
382
  const content = [];
353
383
  let atNewLine = true;
354
384
  const reentry = new TextParserReentryState();
@@ -361,8 +391,16 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
361
391
  content.push({ kind: "text", text: next.text });
362
392
  break;
363
393
  case TokenSyntaxKind.Text:
364
- textContent(comment.sourcePath, next, i18n, warning,
365
- /*out*/ content, files, atNewLine, reentry);
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);
366
404
  break;
367
405
  case TokenSyntaxKind.Code:
368
406
  content.push({ kind: "code", text: next.text });
@@ -400,7 +438,7 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
400
438
  content.push({ kind: "text", text: next.text });
401
439
  break;
402
440
  case TokenSyntaxKind.OpenBrace:
403
- inlineTag(lexer, content, config, i18n, warning);
441
+ inlineTag(lexer, content, config, warning);
404
442
  consume = false;
405
443
  break;
406
444
  default:
@@ -437,7 +475,7 @@ function blockContent(comment, lexer, config, i18n, warning, files) {
437
475
  }
438
476
  return content;
439
477
  }
440
- function inlineTag(lexer, block, config, i18n, warning) {
478
+ function inlineTag(lexer, block, config, warning) {
441
479
  const openBrace = lexer.take();
442
480
  // Now skip whitespace to grab the tag name.
443
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(sourcePath: NormalizedPath, token: Token, i18n: TranslationProxy, warning: (msg: TranslatedString, token: Token) => void, outContent: CommentDisplayPart[], files: FileRegistry, atNewLine: boolean, reentry: TextParserReentryState): void;
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(sourcePath, token, i18n, warning, outContent, files, atNewLine, reentry) {
45
+ export function textContent(parserData, outContent, reentry) {
38
46
  let lastPartEnd = 0;
39
47
  let canEndMarkdownLink = true;
40
48
  const data = {
41
- sourcePath,
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
- warning(i18n.relative_path_0_is_not_a_file_and_will_not_be_copied_to_output(token.text.slice(ref.pos, ref.end)), {
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
  }
@@ -609,10 +609,12 @@ let Converter = (() => {
609
609
  blockTags: new Set(this.application.options.getValue("blockTags")),
610
610
  inlineTags: new Set(this.application.options.getValue("inlineTags")),
611
611
  modifierTags: new Set(this.application.options.getValue("modifierTags")),
612
+ preservedTypeAnnotationTags: new Set(this.application.options.getValue("preservedTypeAnnotationTags")),
612
613
  jsDocCompatibility: this.application.options.getValue("jsDocCompatibility"),
613
614
  suppressCommentWarningsInDeclarationFiles: this.application.options.getValue("suppressCommentWarningsInDeclarationFiles"),
614
615
  useTsLinkResolution: this.application.options.getValue("useTsLinkResolution"),
615
616
  commentStyle: this.application.options.getValue("commentStyle"),
617
+ validationOptions: this.application.options.getValue("validation"),
616
618
  };
617
619
  // Can't be included in options because the TSDoc parser blows up if we do.
618
620
  // TypeDoc supports it as one, so it should always be included here.
@@ -113,7 +113,7 @@ function convertParameters(context, sigRef, parameters, parameterNodes) {
113
113
  assert(!declaration ||
114
114
  ts.isParameter(declaration) ||
115
115
  ts.isJSDocParameterTag(declaration));
116
- const paramRefl = new ParameterReflection(/__\d+/.test(param.name) ? "__namedParameters" : param.name, ReflectionKind.Parameter, sigRef);
116
+ const paramRefl = new ParameterReflection(/^__\d+$/.test(param.name) ? "__namedParameters" : param.name, ReflectionKind.Parameter, sigRef);
117
117
  if (declaration && ts.isJSDocParameterTag(declaration)) {
118
118
  paramRefl.comment = context.getJsDocComment(declaration);
119
119
  }
@@ -132,7 +132,7 @@ function convertParameters(context, sigRef, parameters, parameterNodes) {
132
132
  }
133
133
  }
134
134
  else {
135
- type = param.type;
135
+ type = context.checker.getTypeOfSymbol(param);
136
136
  }
137
137
  if (declaration &&
138
138
  ts.isParameter(declaration) &&
@@ -160,8 +160,9 @@ function convertParameters(context, sigRef, parameters, parameterNodes) {
160
160
  paramRefl.defaultValue = convertDefaultValue(parameterNodes?.[i + parameterNodeOffset]);
161
161
  paramRefl.setFlag(ReflectionFlag.Optional, isOptional);
162
162
  // If we have no declaration, then this is an implicitly defined parameter in JS land
163
- // because the method body uses `arguments`... which is always a rest argument
164
- let isRest = true;
163
+ // because the method body uses `arguments`... which is always a rest argument,
164
+ // unless it is a this parameter defined with @this in JSDoc.
165
+ let isRest = param.name !== "this";
165
166
  if (declaration) {
166
167
  isRest = ts.isParameter(declaration)
167
168
  ? !!declaration.dotDotDotToken
@@ -61,6 +61,7 @@ export declare class CommentPlugin extends ConverterComponent {
61
61
  accessor cascadedModifierTags: TagString[];
62
62
  accessor excludeInternal: boolean;
63
63
  accessor excludePrivate: boolean;
64
+ accessor excludePrivateClassFields: boolean;
64
65
  accessor excludeProtected: boolean;
65
66
  accessor excludeNotDocumented: boolean;
66
67
  accessor excludeCategories: string[];
@@ -44,9 +44,9 @@ import { CategoryPlugin } from "./CategoryPlugin.js";
44
44
  * (for JS users) will be consumed by TypeScript and need not be preserved
45
45
  * in the comment.
46
46
  *
47
- * Note that param/arg/argument/return/returns are not present.
47
+ * Note that param/arg/argument/return/returns/this are not present.
48
48
  * These tags will have their type information stripped when parsing, but still
49
- * provide useful information for documentation.
49
+ * may provide useful information for documentation.
50
50
  */
51
51
  const NEVER_RENDERED = [
52
52
  "@augments",
@@ -55,7 +55,6 @@ const NEVER_RENDERED = [
55
55
  "@constructor",
56
56
  "@enum",
57
57
  "@extends",
58
- "@this",
59
58
  "@type",
60
59
  "@typedef",
61
60
  "@jsx",
@@ -140,6 +139,9 @@ let CommentPlugin = (() => {
140
139
  let _excludePrivate_decorators;
141
140
  let _excludePrivate_initializers = [];
142
141
  let _excludePrivate_extraInitializers = [];
142
+ let _excludePrivateClassFields_decorators;
143
+ let _excludePrivateClassFields_initializers = [];
144
+ let _excludePrivateClassFields_extraInitializers = [];
143
145
  let _excludeProtected_decorators;
144
146
  let _excludeProtected_initializers = [];
145
147
  let _excludeProtected_extraInitializers = [];
@@ -159,6 +161,7 @@ let CommentPlugin = (() => {
159
161
  _cascadedModifierTags_decorators = [Option("cascadedModifierTags")];
160
162
  _excludeInternal_decorators = [Option("excludeInternal")];
161
163
  _excludePrivate_decorators = [Option("excludePrivate")];
164
+ _excludePrivateClassFields_decorators = [Option("excludePrivateClassFields")];
162
165
  _excludeProtected_decorators = [Option("excludeProtected")];
163
166
  _excludeNotDocumented_decorators = [Option("excludeNotDocumented")];
164
167
  _excludeCategories_decorators = [Option("excludeCategories")];
@@ -167,6 +170,7 @@ let CommentPlugin = (() => {
167
170
  __esDecorate(this, null, _cascadedModifierTags_decorators, { kind: "accessor", name: "cascadedModifierTags", static: false, private: false, access: { has: obj => "cascadedModifierTags" in obj, get: obj => obj.cascadedModifierTags, set: (obj, value) => { obj.cascadedModifierTags = value; } }, metadata: _metadata }, _cascadedModifierTags_initializers, _cascadedModifierTags_extraInitializers);
168
171
  __esDecorate(this, null, _excludeInternal_decorators, { kind: "accessor", name: "excludeInternal", static: false, private: false, access: { has: obj => "excludeInternal" in obj, get: obj => obj.excludeInternal, set: (obj, value) => { obj.excludeInternal = value; } }, metadata: _metadata }, _excludeInternal_initializers, _excludeInternal_extraInitializers);
169
172
  __esDecorate(this, null, _excludePrivate_decorators, { kind: "accessor", name: "excludePrivate", static: false, private: false, access: { has: obj => "excludePrivate" in obj, get: obj => obj.excludePrivate, set: (obj, value) => { obj.excludePrivate = value; } }, metadata: _metadata }, _excludePrivate_initializers, _excludePrivate_extraInitializers);
173
+ __esDecorate(this, null, _excludePrivateClassFields_decorators, { kind: "accessor", name: "excludePrivateClassFields", static: false, private: false, access: { has: obj => "excludePrivateClassFields" in obj, get: obj => obj.excludePrivateClassFields, set: (obj, value) => { obj.excludePrivateClassFields = value; } }, metadata: _metadata }, _excludePrivateClassFields_initializers, _excludePrivateClassFields_extraInitializers);
170
174
  __esDecorate(this, null, _excludeProtected_decorators, { kind: "accessor", name: "excludeProtected", static: false, private: false, access: { has: obj => "excludeProtected" in obj, get: obj => obj.excludeProtected, set: (obj, value) => { obj.excludeProtected = value; } }, metadata: _metadata }, _excludeProtected_initializers, _excludeProtected_extraInitializers);
171
175
  __esDecorate(this, null, _excludeNotDocumented_decorators, { kind: "accessor", name: "excludeNotDocumented", static: false, private: false, access: { has: obj => "excludeNotDocumented" in obj, get: obj => obj.excludeNotDocumented, set: (obj, value) => { obj.excludeNotDocumented = value; } }, metadata: _metadata }, _excludeNotDocumented_initializers, _excludeNotDocumented_extraInitializers);
172
176
  __esDecorate(this, null, _excludeCategories_decorators, { kind: "accessor", name: "excludeCategories", static: false, private: false, access: { has: obj => "excludeCategories" in obj, get: obj => obj.excludeCategories, set: (obj, value) => { obj.excludeCategories = value; } }, metadata: _metadata }, _excludeCategories_initializers, _excludeCategories_extraInitializers);
@@ -185,7 +189,10 @@ let CommentPlugin = (() => {
185
189
  #excludePrivate_accessor_storage = (__runInitializers(this, _excludeInternal_extraInitializers), __runInitializers(this, _excludePrivate_initializers, void 0));
186
190
  get excludePrivate() { return this.#excludePrivate_accessor_storage; }
187
191
  set excludePrivate(value) { this.#excludePrivate_accessor_storage = value; }
188
- #excludeProtected_accessor_storage = (__runInitializers(this, _excludePrivate_extraInitializers), __runInitializers(this, _excludeProtected_initializers, void 0));
192
+ #excludePrivateClassFields_accessor_storage = (__runInitializers(this, _excludePrivate_extraInitializers), __runInitializers(this, _excludePrivateClassFields_initializers, void 0));
193
+ get excludePrivateClassFields() { return this.#excludePrivateClassFields_accessor_storage; }
194
+ set excludePrivateClassFields(value) { this.#excludePrivateClassFields_accessor_storage = value; }
195
+ #excludeProtected_accessor_storage = (__runInitializers(this, _excludePrivateClassFields_extraInitializers), __runInitializers(this, _excludeProtected_initializers, void 0));
189
196
  get excludeProtected() { return this.#excludeProtected_accessor_storage; }
190
197
  set excludeProtected(value) { this.#excludeProtected_accessor_storage = value; }
191
198
  #excludeNotDocumented_accessor_storage = (__runInitializers(this, _excludeProtected_extraInitializers), __runInitializers(this, _excludeNotDocumented_initializers, void 0));
@@ -283,6 +290,8 @@ let CommentPlugin = (() => {
283
290
  * @param reflection The reflection that is currently processed.
284
291
  */
285
292
  onCreateTypeParameter(_context, reflection) {
293
+ if (reflection.comment)
294
+ return;
286
295
  const comment = reflection.parent?.comment;
287
296
  if (comment) {
288
297
  let tag = comment.getIdentifiedTag(reflection.name, "@typeParam");
@@ -299,6 +308,17 @@ let CommentPlugin = (() => {
299
308
  reflection.comment = new Comment(tag.content);
300
309
  reflection.comment.sourcePath = comment.sourcePath;
301
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();
302
322
  }
303
323
  }
304
324
  }
@@ -447,19 +467,25 @@ let CommentPlugin = (() => {
447
467
  moveSignatureParamComments(signature, comment = signature.comment) {
448
468
  if (!comment)
449
469
  return;
450
- signature.parameters?.forEach((parameter, index) => {
451
- if (parameter.name === "__namedParameters") {
452
- const commentParams = comment.blockTags.filter((tag) => tag.tag === "@param" && !tag.name?.includes("."));
453
- if (signature.parameters?.length === commentParams.length &&
454
- commentParams[index].name) {
455
- parameter.name = commentParams[index].name;
456
- }
470
+ const unusedCommentParams = comment.blockTags.filter((tag) => tag.tag === "@param" && tag.name && !tag.name.includes(".") &&
471
+ !signature.parameters?.some(p => p.name === tag.name));
472
+ signature.parameters?.forEach((parameter) => {
473
+ if (parameter.name === "__namedParameters" && unusedCommentParams.length) {
474
+ parameter.name = unusedCommentParams[0].name;
475
+ unusedCommentParams.splice(0, 1);
457
476
  }
458
477
  const tag = comment.getIdentifiedTag(parameter.name, "@param");
459
478
  if (tag) {
460
479
  parameter.comment = new Comment(Comment.cloneDisplayParts(tag.content));
461
480
  parameter.comment.sourcePath = comment.sourcePath;
462
481
  }
482
+ else if (parameter.name === "this") {
483
+ const thisTag = comment.getTag("@this");
484
+ if (thisTag) {
485
+ parameter.comment = new Comment(Comment.cloneDisplayParts(thisTag.content));
486
+ parameter.comment.sourcePath = comment.sourcePath;
487
+ }
488
+ }
463
489
  });
464
490
  for (const parameter of signature.typeParameters || []) {
465
491
  const tag = comment.getIdentifiedTag(parameter.name, "@typeParam") ||
@@ -471,6 +497,7 @@ let CommentPlugin = (() => {
471
497
  }
472
498
  }
473
499
  this.validateParamTags(signature, comment, signature.parameters || []);
500
+ comment.removeTags("@this");
474
501
  comment.removeTags("@param");
475
502
  comment.removeTags("@typeParam");
476
503
  comment.removeTags("@template");
@@ -513,6 +540,16 @@ let CommentPlugin = (() => {
513
540
  this.excludePrivate) {
514
541
  return true;
515
542
  }
543
+ // #3017 this isn't quite right as it may incorrectly detect
544
+ // private members named with a hash which aren't actually private
545
+ // class fields (e.g. class Foo { "#hash" = 1 })
546
+ // We can't fix this without storing more information about the name,
547
+ // which I'm going to put off until #3015 is done.
548
+ if (reflection.flags.hasFlag(ReflectionFlag.Private) &&
549
+ reflection.name.startsWith("#") &&
550
+ this.excludePrivateClassFields) {
551
+ return true;
552
+ }
516
553
  if (reflection.flags.hasFlag(ReflectionFlag.Protected) &&
517
554
  this.excludeProtected) {
518
555
  return true;
@@ -377,6 +377,14 @@ function convertClassOrInterface(context, symbol, exportSymbol) {
377
377
  reflection.implementedTypes = implementedTypes;
378
378
  }
379
379
  context.finalizeDeclarationReflection(reflection);
380
+ // Convert type parameters early so that we get access them when converting the constructors if any
381
+ if (instanceType.typeParameters) {
382
+ reflection.typeParameters = instanceType.typeParameters.map((param) => {
383
+ const declaration = param.symbol.declarations?.[0];
384
+ assert(declaration && ts.isTypeParameterDeclaration(declaration));
385
+ return createTypeParamReflection(declaration, reflectionContext);
386
+ });
387
+ }
380
388
  if (classDeclaration && reflection.kind === ReflectionKind.Class) {
381
389
  // Classes can have static props
382
390
  const staticType = context.checker.getTypeOfSymbolAtLocation(symbol, classDeclaration);
@@ -404,14 +412,6 @@ function convertClassOrInterface(context, symbol, exportSymbol) {
404
412
  }
405
413
  // Classes/interfaces usually just have properties...
406
414
  convertSymbols(reflectionContext, context.checker.getPropertiesOfType(instanceType));
407
- // And type arguments
408
- if (instanceType.typeParameters) {
409
- reflection.typeParameters = instanceType.typeParameters.map((param) => {
410
- const declaration = param.symbol.declarations?.[0];
411
- assert(declaration && ts.isTypeParameterDeclaration(declaration));
412
- return createTypeParamReflection(declaration, reflectionContext);
413
- });
414
- }
415
415
  // Interfaces might also have call signatures
416
416
  // Classes might too, because of declaration merging
417
417
  context.checker
@@ -754,6 +754,13 @@ function convertAccessor(context, symbol, exportSymbol) {
754
754
  const declaration = symbol.getDeclarations()?.[0];
755
755
  if (declaration) {
756
756
  setModifiers(symbol, declaration, reflection);
757
+ // #3019, auto accessors `accessor x: string` get the symbol flag for
758
+ // an accessor, but they don't have get/set accessors, so the need a type
759
+ // set on the accessor reflection structure.
760
+ if (ts.isPropertyDeclaration(declaration) &&
761
+ declaration.modifiers?.some(n => n.kind === ts.SyntaxKind.AccessorKeyword)) {
762
+ reflection.type = context.converter.convertType(context.withScope(reflection), context.checker.getTypeOfSymbol(symbol), declaration.type);
763
+ }
757
764
  }
758
765
  context.finalizeDeclarationReflection(reflection);
759
766
  const getDeclaration = symbol.getDeclarations()?.find(ts.isGetAccessor);
@@ -696,7 +696,7 @@ const unionConverter = {
696
696
  convertType(context, type) {
697
697
  const types = type.types.map((type) => convertType(context, type));
698
698
  normalizeUnion(types);
699
- sortLiteralUnion(types);
699
+ sortUnion(types);
700
700
  return new UnionType(types);
701
701
  },
702
702
  };
@@ -764,14 +764,26 @@ function kindToModifier(kind) {
764
764
  return undefined;
765
765
  }
766
766
  }
767
- function sortLiteralUnion(types) {
768
- if (types.some((t) => t.type !== "literal" || typeof t.value !== "number")) {
767
+ function sortUnion(types) {
768
+ // If every member of the union is a literal numeric type, sort in ascending order
769
+ if (types.every(t => t.type === "literal" && typeof t.value === "number")) {
770
+ types.sort((a, b) => {
771
+ const aLit = a;
772
+ const bLit = b;
773
+ return aLit.value - bLit.value;
774
+ });
769
775
  return;
770
776
  }
777
+ // #3024 Otherwise, leave the union in the converted order with the exception of null
778
+ // and undefined, which should be sorted last, with null before undefined.
771
779
  types.sort((a, b) => {
772
- const aLit = a;
773
- const bLit = b;
774
- return aLit.value - bLit.value;
780
+ const aIsNull = a.type === "literal" && a.value === null;
781
+ const aIsUndef = a.type === "intrinsic" && a.name === "undefined";
782
+ const bIsNull = b.type === "literal" && b.value === null;
783
+ const bIsUndef = b.type === "intrinsic" && b.name === "undefined";
784
+ const aWeight = aIsNull ? 1 : aIsUndef ? 2 : 0;
785
+ const bWeight = bIsNull ? 1 : bIsUndef ? 2 : 0;
786
+ return aWeight - bWeight;
775
787
  });
776
788
  }
777
789
  function normalizeUnion(types) {
@@ -139,6 +139,9 @@ let GitRepository = (() => {
139
139
  * @returns A new instance of {@link GitRepository} or undefined.
140
140
  */
141
141
  static tryCreateRepository(path, sourceLinkTemplate, gitRevision, gitRemote, logger) {
142
+ if (gitRevision === "{branch}") {
143
+ gitRevision = git("-C", path, "branch", "--show-current").stdout.trim();
144
+ }
142
145
  gitRevision ||= git("-C", path, "rev-parse", "HEAD").stdout.trim();
143
146
  if (gitRevision == "HEAD")
144
147
  return; // Will only happen in a repo with no commits.
@@ -165,7 +165,6 @@ module.exports = localeUtils.buildIncompleteTranslation({
165
165
  help_excludeNotDocumentedKinds: "Arten von Reflections, die von excludeNotDocumented entfernt werden können",
166
166
  help_excludeInternal: "Verhindert, dass Symbole in der Dokumentation erscheinen, die mit @internal markiert sind",
167
167
  help_excludeCategories: "Schließt Symbole aus dieser Kategorie von der Dokumentation aus",
168
- help_excludePrivate: "Ignoriert private Variablen und Methoden, Standardwert ist true.",
169
168
  help_excludeProtected: "Ignoriert geschützte Variablen und Methoden",
170
169
  help_excludeReferences: "Wird ein Symbol mehrfach exportiert, ignoriere alle außer dem ersten Export",
171
170
  help_externalSymbolLinkMappings: "Definiert eigene Links für Symbole, die nicht in der Dokumentation enthalten sind",