typedoc 0.27.4 → 0.27.5

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 (35) hide show
  1. package/README.md +0 -3
  2. package/dist/index.d.ts +5 -0
  3. package/dist/index.js +5 -0
  4. package/dist/lib/converter/comments/blockLexer.js +28 -10
  5. package/dist/lib/converter/comments/declarationReferenceResolver.js +12 -6
  6. package/dist/lib/converter/comments/lineLexer.js +23 -7
  7. package/dist/lib/converter/comments/linkResolver.js +9 -4
  8. package/dist/lib/converter/comments/rawLexer.js +28 -16
  9. package/dist/lib/converter/comments/textParser.js +1 -0
  10. package/dist/lib/debug/debugReflectionLifetimes.d.ts +2 -0
  11. package/dist/lib/debug/debugReflectionLifetimes.js +19 -0
  12. package/dist/lib/debug/debugRendererUrls.d.ts +5 -0
  13. package/dist/lib/debug/debugRendererUrls.js +59 -0
  14. package/dist/lib/debug/index.d.ts +2 -0
  15. package/dist/lib/debug/index.js +2 -0
  16. package/dist/lib/internationalization/internationalization.d.ts +1 -2
  17. package/dist/lib/internationalization/locales/en.cjs +1 -0
  18. package/dist/lib/internationalization/locales/en.d.cts +1 -0
  19. package/dist/lib/models/ReflectionCategory.js +1 -1
  20. package/dist/lib/models/ReflectionGroup.js +1 -1
  21. package/dist/lib/models/reflections/project.js +1 -0
  22. package/dist/lib/models/types.js +9 -2
  23. package/dist/lib/output/components.d.ts +1 -1
  24. package/dist/lib/output/themes/MarkedPlugin.d.ts +2 -0
  25. package/dist/lib/output/themes/MarkedPlugin.js +33 -7
  26. package/dist/lib/output/themes/default/DefaultTheme.js +14 -1
  27. package/dist/lib/output/themes/default/partials/member.signatures.js +1 -1
  28. package/dist/lib/output/themes/default/partials/typeDetails.js +14 -4
  29. package/dist/lib/serialization/serializer.d.ts +1 -0
  30. package/dist/lib/serialization/serializer.js +4 -1
  31. package/dist/lib/utils/jsx.d.ts +2 -2
  32. package/dist/lib/utils/jsx.elements.d.ts +11 -0
  33. package/dist/lib/utils/options/declaration.d.ts +4 -0
  34. package/dist/lib/utils/options/sources/typedoc.js +1 -0
  35. package/package.json +3 -2
package/README.md CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  Documentation generator for TypeScript projects.
4
4
 
5
- [![CI](https://github.com/TypeStrong/typedoc/workflows/CI/badge.svg)](https://github.com/TypeStrong/typedoc/actions)
6
- [![NPM Version](https://img.shields.io/npm/v/typedoc?color=33cd56&logo=npm)](https://www.npmjs.com/package/typedoc)
7
-
8
5
  ## Documentation
9
6
 
10
7
  For more detailed documentation, the changelog, and TypeDoc documentation rendered with TypeDoc, see https://typedoc.org.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * @module TypeDoc API
3
+ *
4
+ * In addition to the members documented here, TypeDoc exports a `typedoc/debug`
5
+ * entry point which exports some functions which may be useful during plugin
6
+ * development or debugging. Exports from that entry point are **not stable**
7
+ * and may change or be removed at any time.
3
8
  */
4
9
  export { Application, type ApplicationEvents } from "./lib/application.js";
5
10
  export { EventDispatcher } from "./lib/utils/events.js";
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * @module TypeDoc API
3
+ *
4
+ * In addition to the members documented here, TypeDoc exports a `typedoc/debug`
5
+ * entry point which exports some functions which may be useful during plugin
6
+ * development or debugging. Exports from that entry point are **not stable**
7
+ * and may change or be removed at any time.
3
8
  */
4
9
  export { Application } from "./lib/application.js";
5
10
  export { EventDispatcher } from "./lib/utils/events.js";
@@ -107,17 +107,29 @@ function* lexBlockComment2(file, pos, end, linkTags, checker) {
107
107
  break;
108
108
  case "`": {
109
109
  // Markdown's code rules are a royal pain. This could be one of several things.
110
- // 1. Inline code: <1-n ticks><text><same number of ticks>
111
- // 2. Code block: <3 ticks><language, no ticks>\n<text>\n<3 ticks>\n
110
+ // 1. Inline code: <1-n ticks><text without multiple consecutive newlines or ticks at start of line><same number of ticks>
111
+ // 2. Code block: <newline><3+ ticks><language, no ticks>\n<text>\n<3 ticks>\n
112
112
  // 3. Unmatched tick(s), not code, but part of some text.
113
113
  // We don't quite handle #2 correctly yet. PR welcome!
114
114
  braceStartsType = false;
115
115
  let tickCount = 1;
116
- let lookahead = pos;
116
+ let lookahead = pos - 1;
117
+ let atNewline = true;
118
+ while (lookahead > 0 && file[lookahead] !== "\n") {
119
+ if (/\S/.test(file[lookahead])) {
120
+ if (!commentHasStars || file[lookahead] !== "*") {
121
+ atNewline = false;
122
+ break;
123
+ }
124
+ }
125
+ --lookahead;
126
+ }
127
+ lookahead = pos;
117
128
  while (lookahead + 1 < end && file[lookahead + 1] === "`") {
118
129
  tickCount++;
119
130
  lookahead++;
120
131
  }
132
+ const isCodeBlock = atNewline && tickCount >= 3;
121
133
  let lookaheadStart = pos;
122
134
  const codeText = [];
123
135
  lookahead++;
@@ -125,12 +137,18 @@ function* lexBlockComment2(file, pos, end, linkTags, checker) {
125
137
  if (lookaheadExactlyNTicks(lookahead, tickCount)) {
126
138
  lookahead += tickCount;
127
139
  codeText.push(file.substring(lookaheadStart, lookahead));
128
- yield {
129
- kind: TokenSyntaxKind.Code,
130
- text: codeText.join(""),
131
- pos,
132
- };
133
- pos = lookahead;
140
+ const codeTextStr = codeText.join("");
141
+ if (isCodeBlock || !/\n\s*\n/.test(codeTextStr)) {
142
+ yield {
143
+ kind: TokenSyntaxKind.Code,
144
+ text: codeTextStr,
145
+ pos,
146
+ };
147
+ pos = lookahead;
148
+ }
149
+ else {
150
+ yield makeToken(TokenSyntaxKind.Text, tickCount);
151
+ }
134
152
  break;
135
153
  }
136
154
  else if (file[lookahead] === "`") {
@@ -167,7 +185,7 @@ function* lexBlockComment2(file, pos, end, linkTags, checker) {
167
185
  }
168
186
  }
169
187
  if (lookahead >= end && pos !== lookahead) {
170
- if (tickCount === 3 &&
188
+ if (isCodeBlock &&
171
189
  file.substring(pos, end).includes("\n")) {
172
190
  codeText.push(file.substring(lookaheadStart, end));
173
191
  yield {
@@ -174,8 +174,14 @@ function resolveKeyword(refl, kw) {
174
174
  function resolveSymbolReferencePart(refl, path) {
175
175
  let high = [];
176
176
  let low = [];
177
- if (!(refl instanceof ContainerReflection) ||
178
- !refl.childrenIncludingDocuments) {
177
+ let children;
178
+ if (refl instanceof ContainerReflection) {
179
+ children = refl.childrenIncludingDocuments;
180
+ }
181
+ if (!children && refl.isDeclaration() && refl.type?.type === "reflection") {
182
+ children = refl.type.declaration.childrenIncludingDocuments;
183
+ }
184
+ if (!children) {
179
185
  return { high, low };
180
186
  }
181
187
  switch (path.navigation) {
@@ -184,16 +190,16 @@ function resolveSymbolReferencePart(refl, path) {
184
190
  // so that resolution doesn't behave very poorly with projects using JSDoc style resolution.
185
191
  // Also is more consistent with how TypeScript resolves link tags.
186
192
  case ".":
187
- high = refl.childrenIncludingDocuments.filter((r) => r.name === path.path &&
193
+ high = children.filter((r) => r.name === path.path &&
188
194
  (r.kindOf(ReflectionKind.SomeExport) || r.flags.isStatic));
189
- low = refl.childrenIncludingDocuments.filter((r) => r.name === path.path &&
195
+ low = children.filter((r) => r.name === path.path &&
190
196
  (!r.kindOf(ReflectionKind.SomeExport) || !r.flags.isStatic));
191
197
  break;
192
198
  // Resolve via "members", interface children, class instance properties/accessors/methods,
193
199
  // enum members, type literal properties
194
200
  case "#":
195
201
  high =
196
- refl.children?.filter((r) => {
202
+ children?.filter((r) => {
197
203
  return (r.name === path.path &&
198
204
  r.kindOf(ReflectionKind.SomeMember) &&
199
205
  !r.flags.isStatic);
@@ -203,7 +209,7 @@ function resolveSymbolReferencePart(refl, path) {
203
209
  // module/namespace exports since TypeDoc doesn't support documenting locals.
204
210
  case "~":
205
211
  if (refl.kindOf(ReflectionKind.SomeModule | ReflectionKind.Project)) {
206
- high = refl.children?.filter((r) => r.name === path.path) || [];
212
+ high = children?.filter((r) => r.name === path.path) || [];
207
213
  }
208
214
  break;
209
215
  }
@@ -65,11 +65,21 @@ function* lexLineComments2(file, pos, end) {
65
65
  // We don't quite handle #2 correctly yet. PR welcome!
66
66
  braceStartsType = false;
67
67
  let tickCount = 1;
68
- let lookahead = pos;
68
+ let lookahead = pos - 1;
69
+ let atNewline = true;
70
+ while (lookahead > 0 && file[lookahead] !== "\n") {
71
+ if (/\S/.test(file[lookahead])) {
72
+ atNewline = false;
73
+ break;
74
+ }
75
+ --lookahead;
76
+ }
77
+ lookahead = pos;
69
78
  while (lookahead + 1 < end && file[lookahead + 1] === "`") {
70
79
  tickCount++;
71
80
  lookahead++;
72
81
  }
82
+ const isCodeBlock = atNewline && tickCount >= 3;
73
83
  let lookaheadStart = pos;
74
84
  const codeText = [];
75
85
  lookahead++;
@@ -77,12 +87,18 @@ function* lexLineComments2(file, pos, end) {
77
87
  if (lookaheadExactlyNTicks(lookahead, tickCount)) {
78
88
  lookahead += tickCount;
79
89
  codeText.push(file.substring(lookaheadStart, lookahead));
80
- yield {
81
- kind: TokenSyntaxKind.Code,
82
- text: codeText.join(""),
83
- pos,
84
- };
85
- pos = lookahead;
90
+ const codeTextStr = codeText.join("");
91
+ if (isCodeBlock || !/\n\s*\n/.test(codeTextStr)) {
92
+ yield {
93
+ kind: TokenSyntaxKind.Code,
94
+ text: codeTextStr,
95
+ pos,
96
+ };
97
+ pos = lookahead;
98
+ }
99
+ else {
100
+ yield makeToken(TokenSyntaxKind.Text, tickCount);
101
+ }
86
102
  break;
87
103
  }
88
104
  else if (file[lookahead] === "`") {
@@ -1,5 +1,5 @@
1
1
  import ts from "typescript";
2
- import { DeclarationReflection, Reflection, ReflectionSymbolId, } from "../../models/index.js";
2
+ import { DeclarationReflection, Reflection, ReflectionKind, ReflectionSymbolId, } from "../../models/index.js";
3
3
  import { parseDeclarationReference, } from "./declarationReference.js";
4
4
  import { resolveDeclarationReference } from "./declarationReferenceResolver.js";
5
5
  const urlPrefix = /^(http|ftp)s?:\/\//;
@@ -45,9 +45,14 @@ function resolveLinkTag(reflection, part, externalResolver, options) {
45
45
  const declRef = parseDeclarationReference(part.text, pos, end);
46
46
  // Might already know where it should go if useTsLinkResolution is turned on
47
47
  if (part.target instanceof ReflectionSymbolId) {
48
- const tsTarget = reflection.project.getReflectionFromSymbolId(part.target);
49
- if (tsTarget) {
50
- target = tsTarget;
48
+ const tsTargets = reflection.project.getReflectionsFromSymbolId(part.target);
49
+ if (tsTargets.length) {
50
+ // Find the target most likely to have a real url in the generated documentation
51
+ target =
52
+ tsTargets.find((r) => r.kindOf(ReflectionKind.SomeExport)) ||
53
+ tsTargets.find((r) => r.kindOf(ReflectionKind.SomeMember) &&
54
+ r.parent?.kindOf(ReflectionKind.SomeExport)) ||
55
+ tsTargets[0];
51
56
  pos = end;
52
57
  defaultDisplayText =
53
58
  part.tsLinkText ||
@@ -43,19 +43,14 @@ function* lexCommentString2(file) {
43
43
  while (pos < end && /\s/.test(file[end - 1])) {
44
44
  end--;
45
45
  }
46
- let lineStart = true;
47
46
  let expectingTag = false;
48
47
  for (;;) {
49
48
  if (pos >= end) {
50
49
  return;
51
50
  }
52
- if (lineStart) {
53
- lineStart = false;
54
- }
55
51
  switch (file[pos]) {
56
52
  case "\n":
57
53
  yield makeToken(TokenSyntaxKind.NewLine, 1);
58
- lineStart = true;
59
54
  expectingTag = false;
60
55
  break;
61
56
  case "{":
@@ -68,16 +63,26 @@ function* lexCommentString2(file) {
68
63
  break;
69
64
  case "`": {
70
65
  // Markdown's code rules are a royal pain. This could be one of several things.
71
- // 1. Inline code: <1-n ticks><text><same number of ticks>
72
- // 2. Code block: <3 ticks><language, no ticks>\n<text>\n<3 ticks>\n
66
+ // 1. Inline code: <1-n ticks><text without multiple consecutive newlines or ticks at start of line><same number of ticks>
67
+ // 2. Code block: <newline><3+ ticks><language, no ticks>\n<text>\n<3 ticks>\n
73
68
  // 3. Unmatched tick(s), not code, but part of some text.
74
69
  // We don't quite handle #2 correctly yet. PR welcome!
75
70
  let tickCount = 1;
76
- let lookahead = pos;
71
+ let lookahead = pos - 1;
72
+ let atNewline = true;
73
+ while (lookahead > 0 && file[lookahead] !== "\n") {
74
+ if (/\S/.test(file[lookahead])) {
75
+ atNewline = false;
76
+ break;
77
+ }
78
+ --lookahead;
79
+ }
80
+ lookahead = pos;
77
81
  while (lookahead + 1 < end && file[lookahead + 1] === "`") {
78
82
  tickCount++;
79
83
  lookahead++;
80
84
  }
85
+ const isCodeBlock = atNewline && tickCount >= 3;
81
86
  let lookaheadStart = pos;
82
87
  const codeText = [];
83
88
  lookahead++;
@@ -85,13 +90,20 @@ function* lexCommentString2(file) {
85
90
  if (lookaheadExactlyNTicks(lookahead, tickCount)) {
86
91
  lookahead += tickCount;
87
92
  codeText.push(file.substring(lookaheadStart, lookahead));
88
- yield {
89
- kind: TokenSyntaxKind.Code,
90
- text: codeText.join(""),
91
- pos,
92
- };
93
- expectingTag = false;
94
- pos = lookahead;
93
+ const codeTextStr = codeText.join("");
94
+ if (isCodeBlock || !/\n\s*\n/.test(codeTextStr)) {
95
+ yield {
96
+ kind: TokenSyntaxKind.Code,
97
+ text: codeTextStr,
98
+ pos,
99
+ };
100
+ expectingTag = false;
101
+ pos = lookahead;
102
+ }
103
+ else {
104
+ yield makeToken(TokenSyntaxKind.Text, tickCount);
105
+ expectingTag = false;
106
+ }
95
107
  break;
96
108
  }
97
109
  else if (file[lookahead] === "`") {
@@ -114,7 +126,7 @@ function* lexCommentString2(file) {
114
126
  }
115
127
  }
116
128
  if (lookahead >= end && pos !== lookahead) {
117
- if (tickCount === 3 &&
129
+ if (isCodeBlock &&
118
130
  file.substring(pos, end).includes("\n")) {
119
131
  codeText.push(file.substring(lookaheadStart, end));
120
132
  yield {
@@ -81,6 +81,7 @@ export function textContent(sourcePath, token, i18n, warning, outContent, files,
81
81
  addRef(tagLink);
82
82
  continue;
83
83
  }
84
+ data.atNewLine = token.text[data.pos] === "\n";
84
85
  ++data.pos;
85
86
  }
86
87
  if (lastPartEnd !== token.text.length) {
@@ -0,0 +1,2 @@
1
+ import type { Application } from "../application.js";
2
+ export declare function debugReflectionLifetimes(app: Application): void;
@@ -0,0 +1,19 @@
1
+ import { ConverterEvents } from "../converter/converter-events.js";
2
+ export function debugReflectionLifetimes(app) {
3
+ app.converter.on(ConverterEvents.CREATE_PROJECT, logCreate);
4
+ app.converter.on(ConverterEvents.CREATE_SIGNATURE, logCreate);
5
+ app.converter.on(ConverterEvents.CREATE_TYPE_PARAMETER, logCreate);
6
+ app.converter.on(ConverterEvents.CREATE_DECLARATION, logCreate);
7
+ app.converter.on(ConverterEvents.CREATE_DOCUMENT, logCreate);
8
+ app.converter.on(ConverterEvents.CREATE_PARAMETER, logCreate);
9
+ app.converter.on(ConverterEvents.CREATE_PROJECT, (_context, project) => {
10
+ const oldRemove = project["_removeReflection"];
11
+ project["_removeReflection"] = function (reflection) {
12
+ console.log("Remove", reflection.id, reflection.getFullName());
13
+ return oldRemove.call(this, reflection);
14
+ };
15
+ });
16
+ }
17
+ function logCreate(_context, refl) {
18
+ console.log("Create", refl.variant, refl.id, refl.getFullName());
19
+ }
@@ -0,0 +1,5 @@
1
+ import type { Application } from "../application.js";
2
+ export declare function debugRendererUrls(app: Application, { json, logs }?: {
3
+ logs?: true;
4
+ json?: boolean | undefined;
5
+ }): void;
@@ -0,0 +1,59 @@
1
+ /* eslint-disable no-console */
2
+ import { join } from "node:path";
3
+ import { Reflection, ReflectionKind, } from "../models/index.js";
4
+ const serializer = {
5
+ priority: 0,
6
+ supports(x) {
7
+ return x instanceof Reflection;
8
+ },
9
+ toObject(item, obj) {
10
+ obj.url = item.url;
11
+ obj.hasOwnDocument = item.hasOwnDocument;
12
+ // obj.anchor = item.anchor;
13
+ delete obj.sources;
14
+ delete obj.groups;
15
+ delete obj.categories;
16
+ delete obj.readme;
17
+ delete obj.content;
18
+ obj.kind = ReflectionKind[obj.kind];
19
+ delete obj.flags;
20
+ delete obj.defaultValue;
21
+ delete obj.symbolIdMap;
22
+ delete obj.files;
23
+ delete obj.packageName;
24
+ delete obj.variant;
25
+ delete obj.extendedTypes;
26
+ delete obj.inheritedFrom;
27
+ if (!["reflection", "reference"].includes(obj.type?.type)) {
28
+ delete obj.type;
29
+ }
30
+ if (obj.comment) {
31
+ obj.comment.summary = obj.comment.summary.filter((part) => part.kind === "inline-tag");
32
+ obj.comment.blockTags = obj.comment.blockTags?.filter((tag) => {
33
+ tag.content = tag.content.filter((part) => part.kind === "inline-tag");
34
+ return tag.content.length;
35
+ });
36
+ if (!obj.comment.summary.length &&
37
+ !obj.comment.blockTags?.length &&
38
+ !obj.comment.modifierTags) {
39
+ delete obj.comment;
40
+ }
41
+ }
42
+ return obj;
43
+ },
44
+ };
45
+ export function debugRendererUrls(app, { json = false, logs = false } = { logs: true }) {
46
+ app.renderer.postRenderAsyncJobs.push(async (evt) => {
47
+ if (json) {
48
+ app.serializer.addSerializer(serializer);
49
+ await app.generateJson(evt.project, join(evt.outputDirectory, "url_debug.json"));
50
+ app.serializer.removeSerializer(serializer);
51
+ }
52
+ if (logs) {
53
+ for (const id in evt.project.reflections) {
54
+ const refl = evt.project.reflections[id];
55
+ console.log(refl.id, refl.getFullName(), refl.url, refl.hasOwnDocument);
56
+ }
57
+ }
58
+ });
59
+ }
@@ -0,0 +1,2 @@
1
+ export { debugRendererUrls } from "./debugRendererUrls.js";
2
+ export { debugReflectionLifetimes } from "./debugReflectionLifetimes.js";
@@ -0,0 +1,2 @@
1
+ export { debugRendererUrls } from "./debugRendererUrls.js";
2
+ export { debugReflectionLifetimes } from "./debugReflectionLifetimes.js";
@@ -2,7 +2,6 @@ import type { Application } from "../application.js";
2
2
  import { ReflectionKind } from "../models/reflections/kind.js";
3
3
  import { ReflectionFlag } from "../models/index.js";
4
4
  import { type BuiltinTranslatableStringArgs } from "./translatable.js";
5
- import translatable from "./locales/en.cjs";
6
5
  /**
7
6
  * ### What is translatable?
8
7
  * TypeDoc includes a lot of literal strings. By convention, messages which are displayed
@@ -75,7 +74,7 @@ export declare class Internationalization {
75
74
  * Get the translation of the specified key, replacing placeholders
76
75
  * with the arguments specified.
77
76
  */
78
- translate<T extends keyof typeof translatable>(key: T, ...args: TranslatableStrings[T]): TranslatedString;
77
+ translate<T extends keyof TranslatableStrings>(key: T, ...args: TranslatableStrings[T]): TranslatedString;
79
78
  kindSingularString(kind: ReflectionKind): TranslatedString;
80
79
  kindPluralString(kind: ReflectionKind): TranslatedString;
81
80
  flagString(flag: ReflectionFlag): TranslatedString;
@@ -61,6 +61,7 @@ module.exports = {
61
61
  reflection_0_kind_1_defined_in_2_does_not_have_any_documentation: `{0} ({1}), defined in {2}, does not have any documentation`,
62
62
  invalid_intentionally_not_exported_symbols_0: "The following symbols were marked as intentionally not exported, but were either not referenced in the documentation, or were exported:\n\t{0}",
63
63
  reflection_0_has_unused_mergeModuleWith_tag: "{0} has a @mergeModuleWith tag which could not be resolved",
64
+ reflection_0_links_to_1_with_text_2_but_resolved_to_3: `"{0}" links to "{1}" with text "{2}" which exists but does not have a link in the documentation, will link to "{3}" instead.`,
64
65
  // conversion plugins
65
66
  not_all_search_category_boosts_used_0: `Not all categories specified in searchCategoryBoosts were used in the documentation. The unused categories were:\n\t{0}`,
66
67
  not_all_search_group_boosts_used_0: `Not all groups specified in searchGroupBoosts were used in the documentation. The unused groups were:\n\t{0}`,
@@ -56,6 +56,7 @@ declare const _default: {
56
56
  readonly reflection_0_kind_1_defined_in_2_does_not_have_any_documentation: "{0} ({1}), defined in {2}, does not have any documentation";
57
57
  readonly invalid_intentionally_not_exported_symbols_0: "The following symbols were marked as intentionally not exported, but were either not referenced in the documentation, or were exported:\n\t{0}";
58
58
  readonly reflection_0_has_unused_mergeModuleWith_tag: "{0} has a @mergeModuleWith tag which could not be resolved";
59
+ readonly reflection_0_links_to_1_with_text_2_but_resolved_to_3: "\"{0}\" links to \"{1}\" with text \"{2}\" which exists but does not have a link in the documentation, will link to \"{3}\" instead.";
59
60
  readonly not_all_search_category_boosts_used_0: "Not all categories specified in searchCategoryBoosts were used in the documentation. The unused categories were:\n\t{0}";
60
61
  readonly not_all_search_group_boosts_used_0: "Not all groups specified in searchGroupBoosts were used in the documentation. The unused groups were:\n\t{0}";
61
62
  readonly comment_for_0_includes_categoryDescription_for_1_but_no_child_in_group: "Comment for {0} includes @categoryDescription for \"{1}\", but no child is placed in that category";
@@ -52,7 +52,7 @@ export class ReflectionCategory {
52
52
  de.defer((project) => {
53
53
  for (const childId of obj.children || []) {
54
54
  const child = project.getReflectionById(de.oldIdToNewId[childId] ?? -1);
55
- if (child?.isDeclaration()) {
55
+ if (child?.isDeclaration() || child?.isDocument()) {
56
56
  this.children.push(child);
57
57
  }
58
58
  }
@@ -68,7 +68,7 @@ export class ReflectionGroup {
68
68
  de.defer((project) => {
69
69
  for (const childId of obj.children || []) {
70
70
  const child = project.getReflectionById(de.oldIdToNewId[childId] ?? -1);
71
- if (child?.isDeclaration()) {
71
+ if (child?.isDeclaration() || child?.isDocument()) {
72
72
  this.children.push(child);
73
73
  }
74
74
  }
@@ -294,6 +294,7 @@ export class ProjectReflection extends ContainerReflection {
294
294
  }
295
295
  /** @internal */
296
296
  registerSymbolId(reflection, id) {
297
+ this.removedSymbolIds.delete(id);
297
298
  this.reflectionIdToSymbolIdMap.set(reflection.id, id);
298
299
  const previous = this.symbolToReflectionIdMap.get(id);
299
300
  if (previous) {
@@ -690,7 +690,11 @@ export class ReferenceType extends Type {
690
690
  : ReflectionKind.TypeReferenceTarget;
691
691
  const resolved = resolvePotential.find((refl) => refl.kindOf(kind)) ||
692
692
  resolvePotential.find((refl) => refl.kindOf(~kind));
693
- this._target = resolved.id;
693
+ // Do not mark the type as resolved at this point so that if it
694
+ // points to a member which is removed (e.g. by typedoc-plugin-zod)
695
+ // and then replaced it still ends up pointing at the right reflection.
696
+ // We will lock type reference resolution when serializing to JSON.
697
+ // this._target = resolved.id;
694
698
  return resolved;
695
699
  }
696
700
  /**
@@ -820,6 +824,9 @@ export class ReferenceType extends Type {
820
824
  else if (this._project?.symbolIdHasBeenRemoved(this._target)) {
821
825
  target = -1;
822
826
  }
827
+ else if (this.reflection) {
828
+ target = this.reflection.id;
829
+ }
823
830
  else {
824
831
  target = this._target.toObject(serializer);
825
832
  }
@@ -837,7 +844,7 @@ export class ReferenceType extends Type {
837
844
  if (this.refersToTypeParameter) {
838
845
  result.refersToTypeParameter = true;
839
846
  }
840
- if (typeof this._target !== "number" && this.preferValues) {
847
+ if (typeof target !== "number" && this.preferValues) {
841
848
  result.preferValues = true;
842
849
  }
843
850
  if (this.highlightedProperties) {
@@ -27,7 +27,7 @@ export declare abstract class ContextAwareRendererComponent extends RendererComp
27
27
  * Regular expression to test if a string looks like an external url.
28
28
  */
29
29
  protected urlPrefix: RegExp;
30
- private get hostedBaseUrl();
30
+ protected get hostedBaseUrl(): string;
31
31
  private accessor useHostedBaseUrlForAbsoluteLinks;
32
32
  constructor(owner: Renderer);
33
33
  private absoluteToRelativePathMap;
@@ -1,5 +1,6 @@
1
1
  import { ContextAwareRendererComponent } from "../components.js";
2
2
  import { MarkdownEvent, RendererEvent, type PageEvent } from "../events.js";
3
+ import { type ValidationOptions } from "../../utils/index.js";
3
4
  import type { BundledTheme } from "@gerrit0/mini-shiki";
4
5
  import type { DefaultThemeRenderContext, Renderer } from "../index.js";
5
6
  import { type CommentDisplayPart } from "../../models/index.js";
@@ -12,6 +13,7 @@ export declare class MarkedPlugin extends ContextAwareRendererComponent {
12
13
  accessor darkTheme: BundledTheme;
13
14
  accessor markdownItOptions: Record<string, unknown>;
14
15
  accessor markdownLinkExternal: boolean;
16
+ accessor validation: ValidationOptions;
15
17
  private parser?;
16
18
  private renderedRelativeLinks;
17
19
  /**
@@ -58,6 +58,9 @@ let MarkedPlugin = (() => {
58
58
  let _markdownLinkExternal_decorators;
59
59
  let _markdownLinkExternal_initializers = [];
60
60
  let _markdownLinkExternal_extraInitializers = [];
61
+ let _validation_decorators;
62
+ let _validation_initializers = [];
63
+ let _validation_extraInitializers = [];
61
64
  return class MarkedPlugin extends _classSuper {
62
65
  static {
63
66
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
@@ -65,10 +68,12 @@ let MarkedPlugin = (() => {
65
68
  _darkTheme_decorators = [Option("darkHighlightTheme")];
66
69
  _markdownItOptions_decorators = [Option("markdownItOptions")];
67
70
  _markdownLinkExternal_decorators = [Option("markdownLinkExternal")];
71
+ _validation_decorators = [Option("validation")];
68
72
  __esDecorate(this, null, _lightTheme_decorators, { kind: "accessor", name: "lightTheme", static: false, private: false, access: { has: obj => "lightTheme" in obj, get: obj => obj.lightTheme, set: (obj, value) => { obj.lightTheme = value; } }, metadata: _metadata }, _lightTheme_initializers, _lightTheme_extraInitializers);
69
73
  __esDecorate(this, null, _darkTheme_decorators, { kind: "accessor", name: "darkTheme", static: false, private: false, access: { has: obj => "darkTheme" in obj, get: obj => obj.darkTheme, set: (obj, value) => { obj.darkTheme = value; } }, metadata: _metadata }, _darkTheme_initializers, _darkTheme_extraInitializers);
70
74
  __esDecorate(this, null, _markdownItOptions_decorators, { kind: "accessor", name: "markdownItOptions", static: false, private: false, access: { has: obj => "markdownItOptions" in obj, get: obj => obj.markdownItOptions, set: (obj, value) => { obj.markdownItOptions = value; } }, metadata: _metadata }, _markdownItOptions_initializers, _markdownItOptions_extraInitializers);
71
75
  __esDecorate(this, null, _markdownLinkExternal_decorators, { kind: "accessor", name: "markdownLinkExternal", static: false, private: false, access: { has: obj => "markdownLinkExternal" in obj, get: obj => obj.markdownLinkExternal, set: (obj, value) => { obj.markdownLinkExternal = value; } }, metadata: _metadata }, _markdownLinkExternal_initializers, _markdownLinkExternal_extraInitializers);
76
+ __esDecorate(this, null, _validation_decorators, { kind: "accessor", name: "validation", static: false, private: false, access: { has: obj => "validation" in obj, get: obj => obj.validation, set: (obj, value) => { obj.validation = value; } }, metadata: _metadata }, _validation_initializers, _validation_extraInitializers);
72
77
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
73
78
  }
74
79
  #lightTheme_accessor_storage = __runInitializers(this, _lightTheme_initializers, void 0);
@@ -83,7 +88,10 @@ let MarkedPlugin = (() => {
83
88
  #markdownLinkExternal_accessor_storage = (__runInitializers(this, _markdownItOptions_extraInitializers), __runInitializers(this, _markdownLinkExternal_initializers, void 0));
84
89
  get markdownLinkExternal() { return this.#markdownLinkExternal_accessor_storage; }
85
90
  set markdownLinkExternal(value) { this.#markdownLinkExternal_accessor_storage = value; }
86
- parser = __runInitializers(this, _markdownLinkExternal_extraInitializers);
91
+ #validation_accessor_storage = (__runInitializers(this, _markdownLinkExternal_extraInitializers), __runInitializers(this, _validation_initializers, void 0));
92
+ get validation() { return this.#validation_accessor_storage; }
93
+ set validation(value) { this.#validation_accessor_storage = value; }
94
+ parser = __runInitializers(this, _validation_extraInitializers);
87
95
  renderedRelativeLinks = [];
88
96
  /**
89
97
  * This needing to be here really feels hacky... probably some nicer way to do this.
@@ -158,19 +166,35 @@ let MarkedPlugin = (() => {
158
166
  }
159
167
  else if ("id" in part.target) {
160
168
  // No point in trying to resolve a ReflectionSymbolId at this point, we've already
161
- // tried and failed during the resolution step.
169
+ // tried and failed during the resolution step. Warnings related to those broken links
170
+ // have already been emitted.
162
171
  url = context.urlTo(part.target);
163
172
  kindClass = ReflectionKind.classString(part.target.kind);
173
+ // If we don't have a URL the user probably linked to some deeply nested property
174
+ // which doesn't get an assigned URL. We'll walk upwards until we find a reflection
175
+ // which has a URL and link to that instead.
176
+ if (!url) {
177
+ // Walk upwards to find something we can link to.
178
+ let target = part.target.parent;
179
+ url = context.urlTo(target);
180
+ while (!url && target.parent) {
181
+ target = target.parent;
182
+ // We know we'll always end up with a URL here eventually as the
183
+ // project always has a URL.
184
+ url = context.urlTo(target);
185
+ }
186
+ if (this.validation.rewrittenLink) {
187
+ this.application.logger.warn(this.application.i18n.reflection_0_links_to_1_with_text_2_but_resolved_to_3(page.model.getFriendlyFullName(), part.target.getFriendlyFullName(), part.text, target.getFriendlyFullName()));
188
+ }
189
+ }
164
190
  }
165
191
  if (useHtml) {
166
192
  const text = part.tag === "@linkcode" ? `<code>${part.text}</code>` : part.text;
167
- result.push(url
168
- ? `<a href="${url}"${kindClass ? ` class="${kindClass}"` : ""}>${text}</a>`
169
- : part.text);
193
+ result.push(`<a href="${url}"${kindClass ? ` class="${kindClass}"` : ""}>${text}</a>`);
170
194
  }
171
195
  else {
172
196
  const text = part.tag === "@linkcode" ? "`" + part.text + "`" : part.text;
173
- result.push(url ? `[${text}](${url})` : text);
197
+ result.push(`[${text}](${url})`);
174
198
  }
175
199
  }
176
200
  else {
@@ -298,7 +322,9 @@ let MarkedPlugin = (() => {
298
322
  // will be relative links. This will likely have to change with
299
323
  // the introduction of support for customized routers whenever
300
324
  // that becomes a real thing.
301
- if (this.markdownLinkExternal && /https?:\/\//i.test(href)) {
325
+ if (this.markdownLinkExternal &&
326
+ /https?:\/\//i.test(href) &&
327
+ !(href + "/").startsWith(this.hostedBaseUrl)) {
302
328
  token.attrSet("target", "_blank");
303
329
  const classes = token.attrGet("class")?.split(" ") || [];
304
330
  classes.push("external");
@@ -394,12 +394,25 @@ let DefaultTheme = (() => {
394
394
  !(reflection instanceof TypeParameterReflection)) {
395
395
  return;
396
396
  }
397
- if (!reflection.url || !DefaultTheme.URL_PREFIX.test(reflection.url)) {
397
+ // We support linking to reflections for types directly contained within an export
398
+ // but not any deeper. This is because TypeDoc may or may not render the type details
399
+ // for a property depending on whether or not it is deemed useful, and defining a link
400
+ // which might not be used may result in a link being generated which isn't valid. #2808.
401
+ // This should be kept in sync with the renderingChildIsUseful function.
402
+ if (reflection.kindOf(ReflectionKind.TypeLiteral) &&
403
+ (!reflection.parent?.kindOf(ReflectionKind.SomeExport) ||
404
+ reflection.parent.type?.type !== "reflection")) {
405
+ return;
406
+ }
407
+ if ((!reflection.url || !DefaultTheme.URL_PREFIX.test(reflection.url)) &&
408
+ !reflection.kindOf(ReflectionKind.TypeLiteral)) {
398
409
  let refl = reflection;
399
410
  const parts = [refl.name];
400
411
  while (refl.parent && refl.parent !== container && !(reflection.parent instanceof ProjectReflection)) {
401
412
  refl = refl.parent;
402
413
  // Avoid duplicate names for signatures
414
+ // BREAKING: In 0.28, also add !refl.kindOf(ReflectionKind.TypeLiteral) to this check to improve anchor
415
+ // generation by omitting useless __type prefixes.
403
416
  if (parts[0] !== refl.name) {
404
417
  parts.unshift(refl.name);
405
418
  }
@@ -4,7 +4,7 @@ import { classNames } from "../../lib.js";
4
4
  export const memberSignatures = (context, props) => (JSX.createElement(JSX.Fragment, null,
5
5
  JSX.createElement("ul", { class: classNames({ "tsd-signatures": true }, context.getReflectionClasses(props)) }, props.signatures?.map((item) => (JSX.createElement(JSX.Fragment, null,
6
6
  JSX.createElement("li", { class: "tsd-signature tsd-anchor-link" },
7
- JSX.createElement("a", { id: item.anchor, class: "tsd-anchor" }),
7
+ item.anchor && JSX.createElement("a", { id: item.anchor, class: "tsd-anchor" }),
8
8
  context.memberSignatureTitle(item),
9
9
  anchorIcon(context, item.anchor)),
10
10
  JSX.createElement("li", { class: "tsd-description" }, context.memberSignatureBody(item))))))));
@@ -133,7 +133,7 @@ function renderChild(context, child, renderAnchors, highlight) {
133
133
  JSX.createElement("h5", null,
134
134
  !!child.flags.isRest && JSX.createElement("span", { class: "tsd-signature-symbol" }, "..."),
135
135
  JSX.createElement("span", { class: getKindClass(child) }, child.name),
136
- JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
136
+ child.anchor && JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
137
137
  JSX.createElement("span", { class: "tsd-signature-symbol" },
138
138
  !!child.flags.isOptional && "?",
139
139
  ":"),
@@ -155,7 +155,7 @@ function renderChild(context, child, renderAnchors, highlight) {
155
155
  context.reflectionFlags(child),
156
156
  !!child.flags.isRest && JSX.createElement("span", { class: "tsd-signature-symbol" }, "..."),
157
157
  JSX.createElement("span", { class: getKindClass(child) }, child.name),
158
- JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
158
+ child.anchor && JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
159
159
  JSX.createElement("span", { class: "tsd-signature-symbol" },
160
160
  !!child.flags.isOptional && "?",
161
161
  ": "),
@@ -170,7 +170,7 @@ function renderChild(context, child, renderAnchors, highlight) {
170
170
  context.reflectionFlags(child.getSignature),
171
171
  JSX.createElement("span", { class: "tsd-signature-keyword" }, "get "),
172
172
  JSX.createElement("span", { class: getKindClass(child) }, child.name),
173
- JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
173
+ child.anchor && JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
174
174
  JSX.createElement("span", { class: "tsd-signature-symbol" }, "(): "),
175
175
  context.type(child.getSignature.type)),
176
176
  highlightOrComment(child.getSignature))),
@@ -179,7 +179,7 @@ function renderChild(context, child, renderAnchors, highlight) {
179
179
  context.reflectionFlags(child.setSignature),
180
180
  JSX.createElement("span", { class: "tsd-signature-keyword" }, "set "),
181
181
  JSX.createElement("span", { class: getKindClass(child) }, child.name),
182
- !child.getSignature && JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
182
+ !child.getSignature && child.anchor && JSX.createElement("a", { id: child.anchor, class: "tsd-anchor" }),
183
183
  JSX.createElement("span", { class: "tsd-signature-symbol" }, "("),
184
184
  child.setSignature.parameters?.map((item) => (JSX.createElement(JSX.Fragment, null,
185
185
  item.name,
@@ -205,6 +205,16 @@ function renderIndexSignature(context, index) {
205
205
  context.typeDeclaration(index.type)));
206
206
  }
207
207
  function renderingChildIsUseful(refl) {
208
+ // Object types directly under a variable/type alias will always be considered useful.
209
+ // This probably isn't ideal, but it is an easy thing to check when assigning URLs
210
+ // in the default theme, so we'll make the assumption that those properties ought to always
211
+ // be rendered.
212
+ // This should be kept in sync with the DefaultTheme.applyAnchorUrl function.
213
+ if (refl.kindOf(ReflectionKind.TypeLiteral) &&
214
+ refl.parent?.kindOf(ReflectionKind.SomeExport) &&
215
+ refl.parent.type?.type === "reflection") {
216
+ return true;
217
+ }
208
218
  if (renderingThisChildIsUseful(refl)) {
209
219
  return true;
210
220
  }
@@ -34,6 +34,7 @@ export declare class Serializer extends EventDispatcher<SerializerEvents> {
34
34
  */
35
35
  project: ProjectReflection;
36
36
  addSerializer<T extends object>(serializer: SerializerComponent<T>): void;
37
+ removeSerializer(serializer: SerializerComponent<any>): void;
37
38
  toObject<T extends {
38
39
  toObject(serializer: Serializer): ModelToObject<T>;
39
40
  }>(value: T): ModelToObject<T>;
@@ -1,6 +1,6 @@
1
1
  import { EventDispatcher } from "../utils/index.js";
2
2
  import { SerializeEvent } from "./events.js";
3
- import { insertPrioritySorted } from "../utils/array.js";
3
+ import { insertPrioritySorted, removeIfPresent } from "../utils/array.js";
4
4
  /**
5
5
  * Serializes TypeDoc's models to JSON
6
6
  *
@@ -30,6 +30,9 @@ export class Serializer extends EventDispatcher {
30
30
  addSerializer(serializer) {
31
31
  insertPrioritySorted(this.serializers, serializer);
32
32
  }
33
+ removeSerializer(serializer) {
34
+ removeIfPresent(this.serializers, serializer);
35
+ }
33
36
  toObject(value) {
34
37
  if (value === undefined) {
35
38
  return undefined;
@@ -13,7 +13,7 @@
13
13
  * @summary Custom JSX module designed specifically for TypeDoc's needs.
14
14
  * @module
15
15
  */
16
- import type { IntrinsicElements, JsxElement, JsxChildren, JsxComponent } from "./jsx.elements.js";
16
+ import type { IntrinsicElements, JsxElement, JsxChildren, JsxComponent, JsxHtmlGlobalProps } from "./jsx.elements.js";
17
17
  export type { JsxElement as Element, JsxChildren as Children, JsxComponent, } from "./jsx.elements.js";
18
18
  export { JsxFragment as Fragment } from "./jsx.elements.js";
19
19
  /**
@@ -32,7 +32,7 @@ export declare function Raw(_props: {
32
32
  * @hidden
33
33
  */
34
34
  export declare namespace JSX {
35
- export { IntrinsicElements, JsxElement as Element };
35
+ export { IntrinsicElements, JsxElement as Element, JsxHtmlGlobalProps as IntrinsicAttributes, };
36
36
  }
37
37
  /**
38
38
  * JSX factory function to create an "element" that can later be rendered with {@link renderElement}
@@ -165,6 +165,17 @@ export interface JsxHtmlGlobalProps {
165
165
  tabIndex?: number;
166
166
  title?: string;
167
167
  translate?: boolean;
168
+ /**
169
+ * Default: 'auto'. true and 'auto' are equivalent
170
+ *
171
+ * See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) for more details
172
+ */
173
+ popover?: boolean | "auto" | "manual";
174
+ /**
175
+ * It must be the popover element id, see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API)
176
+ */
177
+ popovertarget?: string;
178
+ popovertargetaction?: "hide" | "show" | "toggle";
168
179
  }
169
180
  /**
170
181
  * Properties permitted on the `<a>` element.
@@ -222,6 +222,10 @@ export type ValidationOptions = {
222
222
  * If set, TypeDoc will produce warnings about \{\@link\} tags which will produce broken links.
223
223
  */
224
224
  invalidLink: boolean;
225
+ /**
226
+ * If set, TypeDoc will produce warnings about \{\@link\} tags which do not link directly to their target.
227
+ */
228
+ rewrittenLink: boolean;
225
229
  /**
226
230
  * If set, TypeDoc will produce warnings about declarations that do not have doc comments
227
231
  */
@@ -840,6 +840,7 @@ export function addTypeDocOptions(options) {
840
840
  defaults: {
841
841
  notExported: true,
842
842
  invalidLink: true,
843
+ rewrittenLink: true,
843
844
  notDocumented: false,
844
845
  unusedMergeModuleWith: true,
845
846
  },
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "typedoc",
3
3
  "description": "Create api documentation for TypeScript projects.",
4
- "version": "0.27.4",
4
+ "version": "0.27.5",
5
5
  "homepage": "https://typedoc.org",
6
6
  "type": "module",
7
7
  "exports": {
8
8
  ".": "./dist/index.js",
9
9
  "./tsdoc.json": "./tsdoc.json",
10
- "./package.json": "./package.json"
10
+ "./package.json": "./package.json",
11
+ "./debug": "./dist/lib/debug/index.js"
11
12
  },
12
13
  "types": "./dist/index.d.ts",
13
14
  "bin": {