typedoc 0.25.4 → 0.25.6

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 (63) hide show
  1. package/dist/lib/converter/comments/discovery.js +1 -1
  2. package/dist/lib/converter/context.d.ts +0 -3
  3. package/dist/lib/converter/context.js +0 -3
  4. package/dist/lib/converter/converter.d.ts +0 -1
  5. package/dist/lib/converter/converter.js +0 -1
  6. package/dist/lib/converter/factories/signature.js +29 -3
  7. package/dist/lib/converter/plugins/CategoryPlugin.d.ts +0 -7
  8. package/dist/lib/converter/plugins/CategoryPlugin.js +6 -12
  9. package/dist/lib/converter/plugins/CommentPlugin.d.ts +1 -0
  10. package/dist/lib/converter/plugins/CommentPlugin.js +59 -29
  11. package/dist/lib/converter/plugins/GroupPlugin.d.ts +0 -7
  12. package/dist/lib/converter/plugins/GroupPlugin.js +7 -13
  13. package/dist/lib/converter/plugins/SourcePlugin.js +23 -0
  14. package/dist/lib/converter/symbols.js +44 -23
  15. package/dist/lib/converter/types.js +23 -23
  16. package/dist/lib/models/comments/comment.d.ts +0 -1
  17. package/dist/lib/models/comments/comment.js +0 -1
  18. package/dist/lib/models/reflections/abstract.d.ts +3 -3
  19. package/dist/lib/models/reflections/abstract.js +4 -2
  20. package/dist/lib/models/reflections/declaration.js +1 -1
  21. package/dist/lib/models/reflections/kind.d.ts +6 -0
  22. package/dist/lib/models/reflections/kind.js +17 -0
  23. package/dist/lib/models/reflections/parameter.js +1 -1
  24. package/dist/lib/models/reflections/project.d.ts +3 -0
  25. package/dist/lib/models/reflections/project.js +59 -6
  26. package/dist/lib/models/reflections/signature.js +1 -1
  27. package/dist/lib/models/sources/file.d.ts +1 -1
  28. package/dist/lib/models/types.d.ts +5 -0
  29. package/dist/lib/models/types.js +21 -10
  30. package/dist/lib/output/themes/default/DefaultTheme.d.ts +1 -1
  31. package/dist/lib/output/themes/default/DefaultTheme.js +82 -11
  32. package/dist/lib/output/themes/default/DefaultThemeRenderContext.d.ts +1 -0
  33. package/dist/lib/output/themes/default/DefaultThemeRenderContext.js +2 -0
  34. package/dist/lib/output/themes/default/partials/hierarchy.js +18 -1
  35. package/dist/lib/output/themes/default/partials/icon.js +2 -2
  36. package/dist/lib/output/themes/default/partials/member.getterSetter.js +2 -2
  37. package/dist/lib/output/themes/default/partials/member.signature.title.js +2 -2
  38. package/dist/lib/output/themes/default/partials/parameter.js +2 -2
  39. package/dist/lib/output/themes/default/partials/reflectionPreview.js +3 -3
  40. package/dist/lib/output/themes/default/partials/type.js +2 -3
  41. package/dist/lib/output/themes/default/partials/typeParameters.js +6 -3
  42. package/dist/lib/output/themes/default/templates/hierarchy.d.ts +5 -0
  43. package/dist/lib/output/themes/default/templates/hierarchy.js +32 -0
  44. package/dist/lib/output/themes/lib.js +3 -3
  45. package/dist/lib/serialization/components.d.ts +1 -1
  46. package/dist/lib/serialization/schema.d.ts +1 -0
  47. package/dist/lib/serialization/serializer.d.ts +0 -1
  48. package/dist/lib/serialization/serializer.js +0 -1
  49. package/dist/lib/utils/enum.d.ts +1 -0
  50. package/dist/lib/utils/enum.js +5 -1
  51. package/dist/lib/utils/loggers.d.ts +0 -3
  52. package/dist/lib/utils/loggers.js +0 -1
  53. package/dist/lib/utils/options/declaration.d.ts +1 -0
  54. package/dist/lib/utils/options/readers/tsconfig.js +4 -1
  55. package/dist/lib/utils/options/readers/typedoc.d.ts +0 -1
  56. package/dist/lib/utils/options/readers/typedoc.js +0 -1
  57. package/dist/lib/utils/options/sources/typedoc.js +1 -0
  58. package/dist/lib/utils/tsconfig.d.ts +1 -0
  59. package/dist/lib/utils/tsconfig.js +33 -1
  60. package/dist/lib/validation/documentation.js +23 -16
  61. package/package.json +9 -8
  62. package/static/main.js +2 -2
  63. package/static/style.css +35 -15
@@ -294,7 +294,7 @@ function declarationToCommentNode(node) {
294
294
  if (node.kind === typescript_1.default.SyntaxKind.ExportSpecifier) {
295
295
  return node.parent.parent;
296
296
  }
297
- if ([typescript_1.default.SyntaxKind.NamespaceExport, typescript_1.default.SyntaxKind.FunctionType].includes(node.kind)) {
297
+ if (typescript_1.default.SyntaxKind.NamespaceExport === node.kind) {
298
298
  return node.parent;
299
299
  }
300
300
  return node;
@@ -82,8 +82,5 @@ export declare class Context {
82
82
  getFileComment(node: ts.SourceFile): import("../models/index").Comment | undefined;
83
83
  getJsDocComment(declaration: ts.JSDocPropertyLikeTag | ts.JSDocCallbackTag | ts.JSDocTypedefTag | ts.JSDocTemplateTag | ts.JSDocEnumTag): import("../models/index").Comment | undefined;
84
84
  getSignatureComment(declaration: ts.SignatureDeclaration | ts.JSDocSignature): import("../models/index").Comment | undefined;
85
- /**
86
- * @param callback The callback function that should be executed with the changed context.
87
- */
88
85
  withScope(scope: Reflection): Context;
89
86
  }
@@ -184,9 +184,6 @@ class Context {
184
184
  getSignatureComment(declaration) {
185
185
  return (0, comments_1.getSignatureComment)(declaration, this.converter.config, this.logger, this.converter.commentStyle, this.converter.useTsLinkResolution ? this.checker : undefined);
186
186
  }
187
- /**
188
- * @param callback The callback function that should be executed with the changed context.
189
- */
190
187
  withScope(scope) {
191
188
  const context = new Context(this.converter, this.programs, this.project, scope);
192
189
  context.convertingTypeNode = this.convertingTypeNode;
@@ -117,7 +117,6 @@ export declare class Converter extends ChildableComponent<Application, Converter
117
117
  * Convert the given TypeScript type into its TypeDoc type reflection.
118
118
  *
119
119
  * @param context The context object describing the current state the converter is in.
120
- * @param referenceTarget The target to be used to attempt to resolve reference types
121
120
  * @returns The TypeDoc type reflection representing the given node and type.
122
121
  * @internal
123
122
  */
@@ -203,7 +203,6 @@ let Converter = (() => {
203
203
  * Convert the given TypeScript type into its TypeDoc type reflection.
204
204
  *
205
205
  * @param context The context object describing the current state the converter is in.
206
- * @param referenceTarget The target to be used to attempt to resolve reference types
207
206
  * @returns The TypeDoc type reflection representing the given node and type.
208
207
  * @internal
209
208
  */
@@ -47,6 +47,9 @@ function createSignature(context, kind, signature, symbol, declaration) {
47
47
  else if (kind == models_1.ReflectionKind.SetSignature) {
48
48
  sigRef.type = new models_1.IntrinsicType("void");
49
49
  }
50
+ else if (declaration?.type?.kind === typescript_1.default.SyntaxKind.ThisType) {
51
+ sigRef.type = new models_1.IntrinsicType("this");
52
+ }
50
53
  else {
51
54
  sigRef.type = context.converter.convertType(sigRefCtx, (declaration?.kind === typescript_1.default.SyntaxKind.FunctionDeclaration &&
52
55
  declaration.type) ||
@@ -89,7 +92,14 @@ function convertParameters(context, sigRef, parameters, parameterNodes) {
89
92
  else {
90
93
  type = param.type;
91
94
  }
92
- paramRefl.type = context.converter.convertType(context.withScope(paramRefl), type);
95
+ if (declaration &&
96
+ typescript_1.default.isParameter(declaration) &&
97
+ declaration.type?.kind === typescript_1.default.SyntaxKind.ThisType) {
98
+ paramRefl.type = new models_1.IntrinsicType("this");
99
+ }
100
+ else {
101
+ paramRefl.type = context.converter.convertType(context.withScope(paramRefl), type);
102
+ }
93
103
  let isOptional = false;
94
104
  if (declaration) {
95
105
  isOptional = typescript_1.default.isParameter(declaration)
@@ -114,6 +124,7 @@ function convertParameters(context, sigRef, parameters, parameterNodes) {
114
124
  typescript_1.default.isJSDocVariadicType(declaration.typeExpression.type);
115
125
  }
116
126
  paramRefl.setFlag(models_1.ReflectionFlag.Rest, isRest);
127
+ checkForDestructuredParameterDefaults(paramRefl, parameterNodes?.[i]);
117
128
  return paramRefl;
118
129
  });
119
130
  }
@@ -140,10 +151,27 @@ function convertParameterNodes(context, sigRef, parameters) {
140
151
  ? !!param.dotDotDotToken
141
152
  : !!param.typeExpression &&
142
153
  typescript_1.default.isJSDocVariadicType(param.typeExpression.type));
154
+ checkForDestructuredParameterDefaults(paramRefl, param);
143
155
  return paramRefl;
144
156
  });
145
157
  }
146
158
  exports.convertParameterNodes = convertParameterNodes;
159
+ function checkForDestructuredParameterDefaults(param, decl) {
160
+ if (!decl || !typescript_1.default.isParameter(decl))
161
+ return;
162
+ if (param.name !== "__namedParameters")
163
+ return;
164
+ if (!typescript_1.default.isObjectBindingPattern(decl.name))
165
+ return;
166
+ if (param.type?.type !== "reflection")
167
+ return;
168
+ for (const child of param.type.declaration.children || []) {
169
+ const tsChild = decl.name.elements.find((el) => (el.propertyName || el.name).getText() === child.name);
170
+ if (tsChild) {
171
+ child.defaultValue = (0, convert_expression_1.convertDefaultValue)(tsChild);
172
+ }
173
+ }
174
+ }
147
175
  function convertTypeParameters(context, parent, parameters) {
148
176
  return parameters?.map((param) => {
149
177
  const constraintT = param.getConstraint();
@@ -218,8 +246,6 @@ function convertTemplateParameterNodes(context, nodes) {
218
246
  return paramRefl;
219
247
  });
220
248
  });
221
- const params = (nodes ?? []).flatMap((tag) => tag.typeParameters);
222
- return convertTypeParameterNodes(context, params);
223
249
  }
224
250
  exports.convertTemplateParameterNodes = convertTemplateParameterNodes;
225
251
  function getVariance(modifiers) {
@@ -22,13 +22,6 @@ export declare class CategoryPlugin extends ConverterComponent {
22
22
  * Triggered when the converter begins converting a project.
23
23
  */
24
24
  private onBegin;
25
- /**
26
- * Triggered when the converter resolves a reflection.
27
- *
28
- * @param context The context object describing the current state the converter is in.
29
- * @param reflection The reflection that is currently resolved.
30
- */
31
- private onResolve;
32
25
  /**
33
26
  * Triggered when the converter has finished resolving a project.
34
27
  *
@@ -100,7 +100,6 @@ let CategoryPlugin = (() => {
100
100
  initialize() {
101
101
  this.listenTo(this.owner, {
102
102
  [converter_1.Converter.EVENT_BEGIN]: this.onBegin,
103
- [converter_1.Converter.EVENT_RESOLVE]: this.onResolve,
104
103
  [converter_1.Converter.EVENT_RESOLVE_END]: this.onEndResolve,
105
104
  }, undefined, -200);
106
105
  }
@@ -117,17 +116,6 @@ let CategoryPlugin = (() => {
117
116
  CategoryPlugin.WEIGHTS = this.categoryOrder;
118
117
  }
119
118
  }
120
- /**
121
- * Triggered when the converter resolves a reflection.
122
- *
123
- * @param context The context object describing the current state the converter is in.
124
- * @param reflection The reflection that is currently resolved.
125
- */
126
- onResolve(_context, reflection) {
127
- if (reflection instanceof models_1.ContainerReflection) {
128
- this.categorize(reflection);
129
- }
130
- }
131
119
  /**
132
120
  * Triggered when the converter has finished resolving a project.
133
121
  *
@@ -136,6 +124,12 @@ let CategoryPlugin = (() => {
136
124
  onEndResolve(context) {
137
125
  const project = context.project;
138
126
  this.categorize(project);
127
+ for (const id in project.reflections) {
128
+ const reflection = project.reflections[id];
129
+ if (reflection instanceof models_1.ContainerReflection) {
130
+ this.categorize(reflection);
131
+ }
132
+ }
139
133
  const unusedBoosts = new Set(Object.keys(this.boosts));
140
134
  for (const boost of this.usedBoosts) {
141
135
  unusedBoosts.delete(boost);
@@ -121,4 +121,5 @@ export declare class CommentPlugin extends ConverterComponent {
121
121
  */
122
122
  private isHidden;
123
123
  private excludedByCategory;
124
+ private validateParamTags;
124
125
  }
@@ -382,13 +382,8 @@ let CommentPlugin = (() => {
382
382
  const comment = reflection.kindOf(models_1.ReflectionKind.ClassOrInterface)
383
383
  ? undefined
384
384
  : reflection.comment;
385
- // Since this reflection has signatures, remove the comment from the parent
386
- // reflection. This is important so that in type aliases we don't end up with
387
- // a comment rendered twice.
388
- if (!reflection.kindOf(models_1.ReflectionKind.ClassOrInterface)) {
389
- delete reflection.comment;
390
- }
391
385
  for (const signature of signatures) {
386
+ const signatureHadOwnComment = !!signature.comment;
392
387
  const childComment = (signature.comment ||= comment?.clone());
393
388
  if (!childComment)
394
389
  continue;
@@ -400,7 +395,6 @@ let CommentPlugin = (() => {
400
395
  parameter.name = commentParams[index].name;
401
396
  }
402
397
  }
403
- moveNestedParamTags(childComment, parameter);
404
398
  const tag = childComment.getIdentifiedTag(parameter.name, "@param");
405
399
  if (tag) {
406
400
  parameter.comment = new models_1.Comment(models_1.Comment.cloneDisplayParts(tag.content));
@@ -414,10 +408,26 @@ let CommentPlugin = (() => {
414
408
  parameter.comment = new models_1.Comment(models_1.Comment.cloneDisplayParts(tag.content));
415
409
  }
416
410
  }
411
+ this.validateParamTags(signature, childComment, signature.parameters || [], signatureHadOwnComment);
417
412
  childComment?.removeTags("@param");
418
413
  childComment?.removeTags("@typeParam");
419
414
  childComment?.removeTags("@template");
420
415
  }
416
+ // Since this reflection has signatures, we need to remove the comment from the non-primary
417
+ // declaration location. For functions, this means removing it from the Function reflection.
418
+ // For type aliases, this means removing it from reflection.type.declaration.
419
+ // This is important so that in type aliases we don't end up with a comment rendered twice.
420
+ if (reflection.kindOf(models_1.ReflectionKind.FunctionOrMethod | models_1.ReflectionKind.Constructor)) {
421
+ delete reflection.comment;
422
+ }
423
+ if (reflection.kindOf(models_1.ReflectionKind.TypeAlias)) {
424
+ reflection.comment?.removeTags("@param");
425
+ reflection.comment?.removeTags("@typeParam");
426
+ reflection.comment?.removeTags("@template");
427
+ for (const sig of signatures) {
428
+ delete sig.comment;
429
+ }
430
+ }
421
431
  }
422
432
  removeExcludedTags(comment) {
423
433
  for (const tag of NEVER_RENDERED) {
@@ -512,6 +522,16 @@ let CommentPlugin = (() => {
512
522
  }
513
523
  return excludeCategories.some((cat) => categories.has(cat));
514
524
  }
525
+ validateParamTags(signature, comment, params, signatureHadOwnComment) {
526
+ const paramTags = comment.blockTags.filter((tag) => tag.tag === "@param");
527
+ (0, utils_1.removeIf)(paramTags, (tag) => params.some((param) => param.name === tag.name));
528
+ moveNestedParamTags(/* in-out */ paramTags, params);
529
+ if (signatureHadOwnComment && paramTags.length) {
530
+ for (const tag of paramTags) {
531
+ this.application.logger.warn(`The signature ${signature.getFriendlyFullName()} has an @param with name "${tag.name}", which was not used.`);
532
+ }
533
+ }
534
+ }
515
535
  };
516
536
  _CommentPlugin_excludeTags_accessor_storage = new WeakMap();
517
537
  _CommentPlugin_excludeInternal_accessor_storage = new WeakMap();
@@ -555,29 +575,39 @@ function inTypeLiteral(refl) {
555
575
  return false;
556
576
  }
557
577
  // Moves tags like `@param foo.bar docs for bar` into the `bar` property of the `foo` parameter.
558
- function moveNestedParamTags(comment, parameter) {
559
- const visitor = {
560
- reflection(target) {
561
- const tags = comment.blockTags.filter((t) => t.tag === "@param" &&
562
- t.name?.startsWith(`${parameter.name}.`));
563
- for (const tag of tags) {
564
- const path = tag.name.split(".");
565
- path.shift();
566
- const child = target.declaration.getChildByName(path);
567
- if (child && !child.comment) {
568
- child.comment = new models_1.Comment(models_1.Comment.cloneDisplayParts(tag.content));
578
+ function moveNestedParamTags(
579
+ /* in-out */ paramTags, parameters) {
580
+ const used = new Set();
581
+ for (const param of parameters) {
582
+ const visitor = {
583
+ reflection(target) {
584
+ const tags = paramTags.filter((t) => t.name?.startsWith(`${param.name}.`));
585
+ for (const tag of tags) {
586
+ const path = tag.name.split(".");
587
+ path.shift();
588
+ const child = target.declaration.getChildByName(path);
589
+ if (child && !child.comment) {
590
+ child.comment = new models_1.Comment(models_1.Comment.cloneDisplayParts(tag.content));
591
+ used.add(paramTags.indexOf(tag));
592
+ }
569
593
  }
570
- }
571
- },
572
- // #1876, also do this for unions/intersections.
573
- union(u) {
574
- u.types.forEach((t) => t.visit(visitor));
575
- },
576
- intersection(i) {
577
- i.types.forEach((t) => t.visit(visitor));
578
- },
579
- };
580
- parameter.type?.visit(visitor);
594
+ },
595
+ // #1876, also do this for unions/intersections.
596
+ union(u) {
597
+ u.types.forEach((t) => t.visit(visitor));
598
+ },
599
+ intersection(i) {
600
+ i.types.forEach((t) => t.visit(visitor));
601
+ },
602
+ };
603
+ param.type?.visit(visitor);
604
+ }
605
+ const toRemove = Array.from(used)
606
+ .sort((a, b) => a - b)
607
+ .reverse();
608
+ for (const index of toRemove) {
609
+ paramTags.splice(index, 1);
610
+ }
581
611
  }
582
612
  function movePropertyTags(comment, container) {
583
613
  const propTags = comment.blockTags.filter((tag) => tag.tag === "@prop" || tag.tag === "@property");
@@ -17,13 +17,6 @@ export declare class GroupPlugin extends ConverterComponent {
17
17
  * Create a new GroupPlugin instance.
18
18
  */
19
19
  initialize(): void;
20
- /**
21
- * Triggered when the converter resolves a reflection.
22
- *
23
- * @param context The context object describing the current state the converter is in.
24
- * @param reflection The reflection that is currently resolved.
25
- */
26
- private onResolve;
27
20
  /**
28
21
  * Triggered when the converter has finished resolving a project.
29
22
  *
@@ -100,20 +100,8 @@ let GroupPlugin = (() => {
100
100
  this.sortFunction = (0, sort_1.getSortFunction)(this.application.options);
101
101
  GroupPlugin.WEIGHTS = this.groupOrder;
102
102
  },
103
- [converter_1.Converter.EVENT_RESOLVE]: this.onResolve,
104
103
  [converter_1.Converter.EVENT_RESOLVE_END]: this.onEndResolve,
105
- });
106
- }
107
- /**
108
- * Triggered when the converter resolves a reflection.
109
- *
110
- * @param context The context object describing the current state the converter is in.
111
- * @param reflection The reflection that is currently resolved.
112
- */
113
- onResolve(_context, reflection) {
114
- if (reflection instanceof index_1.ContainerReflection) {
115
- this.group(reflection);
116
- }
104
+ }, undefined, -100);
117
105
  }
118
106
  /**
119
107
  * Triggered when the converter has finished resolving a project.
@@ -122,6 +110,12 @@ let GroupPlugin = (() => {
122
110
  */
123
111
  onEndResolve(context) {
124
112
  this.group(context.project);
113
+ for (const id in context.project.reflections) {
114
+ const reflection = context.project.reflections[id];
115
+ if (reflection instanceof index_1.ContainerReflection) {
116
+ this.group(reflection);
117
+ }
118
+ }
125
119
  const unusedBoosts = new Set(Object.keys(this.boosts));
126
120
  for (const boost of this.usedBoosts) {
127
121
  unusedBoosts.delete(boost);
@@ -196,6 +196,9 @@ let SourcePlugin = (() => {
196
196
  refl instanceof index_1.SignatureReflection)) {
197
197
  continue;
198
198
  }
199
+ if (replaceSourcesWithParentSources(refl)) {
200
+ refl.sources = refl.parent.sources;
201
+ }
199
202
  for (const source of refl.sources || []) {
200
203
  if (this.disableGit || (0, repository_1.gitIsInstalled)()) {
201
204
  const repo = this.getRepository(basePath, source.fullFileName);
@@ -273,3 +276,23 @@ function getLocationNode(node) {
273
276
  return node.name;
274
277
  return node;
275
278
  }
279
+ function replaceSourcesWithParentSources(refl) {
280
+ if (refl instanceof index_1.DeclarationReflection || !refl.sources) {
281
+ return false;
282
+ }
283
+ const symbol = refl.project.getSymbolFromReflection(refl.parent);
284
+ if (!symbol?.declarations) {
285
+ return false;
286
+ }
287
+ for (const decl of symbol.declarations) {
288
+ const file = decl.getSourceFile();
289
+ const pos = file.getLineAndCharacterOfPosition(decl.pos);
290
+ const end = file.getLineAndCharacterOfPosition(decl.end);
291
+ if (refl.sources.some((src) => src.fullFileName === file.fileName &&
292
+ pos.line <= src.line - 1 &&
293
+ src.line - 1 <= end.line)) {
294
+ return false;
295
+ }
296
+ }
297
+ return true;
298
+ }
@@ -48,7 +48,7 @@ const conversionOrder = [
48
48
  typescript_1.default.SymbolFlags.FunctionScopedVariable,
49
49
  typescript_1.default.SymbolFlags.ExportValue,
50
50
  typescript_1.default.SymbolFlags.TypeAlias,
51
- typescript_1.default.SymbolFlags.Function,
51
+ typescript_1.default.SymbolFlags.Function, // Before NamespaceModule
52
52
  typescript_1.default.SymbolFlags.Method,
53
53
  typescript_1.default.SymbolFlags.Interface,
54
54
  typescript_1.default.SymbolFlags.Property,
@@ -100,6 +100,10 @@ function convertSymbol(context, symbol, exportSymbol) {
100
100
  }
101
101
  if ((0, enum_1.hasAllFlags)(symbol.flags, typescript_1.default.SymbolFlags.NamespaceModule)) {
102
102
  // This might be here if a namespace is declared several times.
103
+ // Or if it's a namespace-like thing defined on a function
104
+ // In the function case, it's important to remove ValueModule so that
105
+ // if we convert the children as properties of the function rather than as
106
+ // a separate namespace, we skip creating the namespace.
103
107
  flags = (0, enum_1.removeFlag)(flags, typescript_1.default.SymbolFlags.ValueModule);
104
108
  }
105
109
  if ((0, enum_1.hasAnyFlag)(symbol.flags, typescript_1.default.SymbolFlags.Method |
@@ -110,10 +114,8 @@ function convertSymbol(context, symbol, exportSymbol) {
110
114
  // { methodProperty() {} }
111
115
  flags = (0, enum_1.removeFlag)(flags, typescript_1.default.SymbolFlags.Property);
112
116
  }
113
- for (const flag of (0, enum_1.getEnumFlags)(flags ^ allConverterFlags)) {
114
- if (!(flag & allConverterFlags)) {
115
- context.logger.verbose(`Missing converter for symbol: ${symbol.name} with flag ${typescript_1.default.SymbolFlags[flag]}`);
116
- }
117
+ for (const flag of (0, enum_1.getEnumFlags)(flags & ~allConverterFlags)) {
118
+ context.logger.verbose(`Missing converter for symbol: ${symbol.name} with flag ${typescript_1.default.SymbolFlags[flag]}`);
117
119
  }
118
120
  // Note: This method does not allow skipping earlier converters.
119
121
  // For now, this is fine... might not be flexible enough in the future.
@@ -260,9 +262,7 @@ function convertFunctionOrMethod(context, symbol, exportSymbol) {
260
262
  // Need to get the non nullable type because interface methods might be declared
261
263
  // with a question token. See GH1490.
262
264
  const signatures = type.getNonNullableType().getCallSignatures();
263
- const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.ClassOrInterface |
264
- models_1.ReflectionKind.VariableOrProperty |
265
- models_1.ReflectionKind.TypeLiteral)
265
+ const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.MethodContainer)
266
266
  ? models_1.ReflectionKind.Method
267
267
  : models_1.ReflectionKind.Function, symbol, exportSymbol, void 0);
268
268
  if (symbol.declarations?.length && isMethod) {
@@ -276,6 +276,8 @@ function convertFunctionOrMethod(context, symbol, exportSymbol) {
276
276
  for (const sig of signatures) {
277
277
  (0, signature_1.createSignature)(scope, models_1.ReflectionKind.CallSignature, sig, symbol);
278
278
  }
279
+ convertFunctionProperties(scope, symbol, type);
280
+ return typescript_1.default.SymbolFlags.NamespaceModule;
279
281
  }
280
282
  // getDeclaredTypeOfSymbol gets the INSTANCE type
281
283
  // getTypeOfSymbolAtLocation gets the STATIC type
@@ -350,13 +352,13 @@ function convertClassOrInterface(context, symbol, exportSymbol) {
350
352
  convertConstructSignatures(reflectionContext, symbol);
351
353
  // And finally, index signatures
352
354
  (0, index_signature_1.convertIndexSignature)(reflectionContext, symbol);
353
- // Normally this shouldn't matter, unless someone did something with skipLibCheck off.
355
+ // Normally this shouldn't matter, unless someone did something with skipLibCheck on.
354
356
  return typescript_1.default.SymbolFlags.Alias;
355
357
  }
356
358
  function convertProperty(context, symbol, exportSymbol) {
357
359
  // This might happen if we're converting a function-module created with Object.assign
358
360
  // or `export default () => {}`
359
- if (context.scope.kindOf(models_1.ReflectionKind.SomeModule | models_1.ReflectionKind.Project)) {
361
+ if (context.scope.kindOf(models_1.ReflectionKind.VariableContainer)) {
360
362
  return convertVariable(context, symbol, exportSymbol);
361
363
  }
362
364
  const declarations = symbol.getDeclarations() ?? [];
@@ -382,7 +384,7 @@ function convertProperty(context, symbol, exportSymbol) {
382
384
  return convertArrowAsMethod(context, symbol, declaration.initializer, exportSymbol);
383
385
  }
384
386
  }
385
- const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.Namespace)
387
+ const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.VariableContainer)
386
388
  ? models_1.ReflectionKind.Variable
387
389
  : models_1.ReflectionKind.Property, symbol, exportSymbol);
388
390
  reflection.conversionFlags |= models_1.ConversionFlags.VariableOrPropertySource;
@@ -413,9 +415,16 @@ function convertArrowAsMethod(context, symbol, arrow, exportSymbol) {
413
415
  setModifiers(symbol, arrow.parent, reflection);
414
416
  context.finalizeDeclarationReflection(reflection);
415
417
  const rc = context.withScope(reflection);
416
- const signature = context.checker.getSignatureFromDeclaration(arrow);
417
- (0, assert_1.default)(signature);
418
- (0, signature_1.createSignature)(rc, models_1.ReflectionKind.CallSignature, signature, symbol, arrow);
418
+ const locationDeclaration = symbol.parent
419
+ ?.getDeclarations()
420
+ ?.find((d) => typescript_1.default.isClassDeclaration(d) || typescript_1.default.isInterfaceDeclaration(d)) ??
421
+ symbol.parent?.getDeclarations()?.[0]?.getSourceFile() ??
422
+ symbol.getDeclarations()?.[0]?.getSourceFile();
423
+ (0, assert_1.default)(locationDeclaration, "Missing declaration context");
424
+ const type = context.checker.getTypeOfSymbolAtLocation(symbol, locationDeclaration);
425
+ const signatures = type.getNonNullableType().getCallSignatures();
426
+ (0, assert_1.default)(signatures.length, "Missing signatures");
427
+ (0, signature_1.createSignature)(rc, models_1.ReflectionKind.CallSignature, signatures[0], symbol, arrow);
419
428
  }
420
429
  function convertConstructor(context, symbol) {
421
430
  const reflection = context.createDeclarationReflection(models_1.ReflectionKind.Constructor, symbol, void 0, "constructor");
@@ -478,7 +487,9 @@ function convertVariable(context, symbol, exportSymbol) {
478
487
  if (type.getCallSignatures().length) {
479
488
  return convertVariableAsFunction(context, symbol, exportSymbol);
480
489
  }
481
- const reflection = context.createDeclarationReflection(models_1.ReflectionKind.Variable, symbol, exportSymbol);
490
+ const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.VariableContainer)
491
+ ? models_1.ReflectionKind.Variable
492
+ : models_1.ReflectionKind.Property, symbol, exportSymbol);
482
493
  let typeNode;
483
494
  if (declaration && typescript_1.default.isVariableDeclaration(declaration)) {
484
495
  // Otherwise we might have destructuring
@@ -535,7 +546,9 @@ function convertVariableAsFunction(context, symbol, exportSymbol) {
535
546
  const type = accessDeclaration
536
547
  ? context.checker.getTypeOfSymbolAtLocation(symbol, accessDeclaration)
537
548
  : context.checker.getDeclaredTypeOfSymbol(symbol);
538
- const reflection = context.createDeclarationReflection(models_1.ReflectionKind.Function, symbol, exportSymbol);
549
+ const reflection = context.createDeclarationReflection(context.scope.kindOf(models_1.ReflectionKind.MethodContainer)
550
+ ? models_1.ReflectionKind.Method
551
+ : models_1.ReflectionKind.Function, symbol, exportSymbol);
539
552
  setModifiers(symbol, accessDeclaration, reflection);
540
553
  reflection.conversionFlags |= models_1.ConversionFlags.VariableOrPropertySource;
541
554
  context.finalizeDeclarationReflection(reflection);
@@ -544,15 +557,23 @@ function convertVariableAsFunction(context, symbol, exportSymbol) {
544
557
  for (const signature of type.getCallSignatures()) {
545
558
  (0, signature_1.createSignature)(reflectionContext, models_1.ReflectionKind.CallSignature, signature, symbol);
546
559
  }
547
- // #2436: Functions created with Object.assign on a function won't have a namespace flag
548
- // but likely have properties that we should put into a namespace.
560
+ convertFunctionProperties(context.withScope(reflection), symbol, type);
561
+ return typescript_1.default.SymbolFlags.Property | typescript_1.default.SymbolFlags.NamespaceModule;
562
+ }
563
+ function convertFunctionProperties(context, symbol, type) {
564
+ // #2436/#2461: Functions created with Object.assign on a function likely have properties
565
+ // that we should document. We also add properties to the function if they are defined like:
566
+ // function f() {}
567
+ // f.x = 123;
568
+ // rather than creating a separate namespace.
569
+ // In the expando case, we'll have both namespace flags.
570
+ // In the Object.assign case, we'll have no namespace flags.
571
+ const nsFlags = typescript_1.default.SymbolFlags.ValueModule | typescript_1.default.SymbolFlags.NamespaceModule;
549
572
  if (type.getProperties().length &&
550
- !(0, enum_1.hasAnyFlag)(symbol.flags, typescript_1.default.SymbolFlags.NamespaceModule | typescript_1.default.SymbolFlags.ValueModule)) {
551
- const ns = context.createDeclarationReflection(models_1.ReflectionKind.Namespace, symbol, exportSymbol);
552
- context.finalizeDeclarationReflection(ns);
553
- convertSymbols(context.withScope(ns), type.getProperties());
573
+ ((0, enum_1.hasAllFlags)(symbol.flags, nsFlags) ||
574
+ !(0, enum_1.hasAnyFlag)(symbol.flags, nsFlags))) {
575
+ convertSymbols(context, type.getProperties());
554
576
  }
555
- return typescript_1.default.SymbolFlags.Property;
556
577
  }
557
578
  function convertAccessor(context, symbol, exportSymbol) {
558
579
  const reflection = context.createDeclarationReflection(models_1.ReflectionKind.Accessor, symbol, exportSymbol);
@@ -64,7 +64,7 @@ function loadConverters() {
64
64
  exports.loadConverters = loadConverters;
65
65
  // This ought not be necessary, but we need some way to discover recursively
66
66
  // typed symbols which do not have type nodes. See the `recursive` symbol in the variables test.
67
- const seenTypeSymbols = new Set();
67
+ const seenTypes = new Set();
68
68
  function maybeConvertType(context, typeOrNode) {
69
69
  if (!typeOrNode) {
70
70
  return;
@@ -83,19 +83,23 @@ function convertType(context, typeOrNode) {
83
83
  }
84
84
  return requestBugReport(context, typeOrNode);
85
85
  }
86
+ // TS 4.2 added this to enable better tracking of type aliases.
87
+ // We need to check it here, not just in the union checker, because typeToTypeNode
88
+ // will use the origin when serializing
89
+ // aliasSymbol check is important - #2468
90
+ if (typeOrNode.isUnion() &&
91
+ typeOrNode.origin &&
92
+ !typeOrNode.origin.isUnion() &&
93
+ !typeOrNode.aliasSymbol) {
94
+ return convertType(context, typeOrNode.origin);
95
+ }
86
96
  // IgnoreErrors is important, without it, we can't assert that we will get a node.
87
97
  const node = context.checker.typeToTypeNode(typeOrNode, void 0, typescript_1.default.NodeBuilderFlags.IgnoreErrors);
88
98
  (0, assert_1.default)(node); // According to the TS source of typeToString, this is a bug if it does not hold.
89
- const symbol = typeOrNode.getSymbol();
90
- if (symbol) {
91
- if (node.kind !== typescript_1.default.SyntaxKind.TypeReference &&
92
- node.kind !== typescript_1.default.SyntaxKind.ArrayType &&
93
- seenTypeSymbols.has(symbol)) {
94
- const typeString = context.checker.typeToString(typeOrNode);
95
- context.logger.verbose(`Refusing to recurse when converting type: ${typeString}`);
96
- return new models_1.UnknownType(typeString);
97
- }
98
- seenTypeSymbols.add(symbol);
99
+ if (seenTypes.has(typeOrNode.id)) {
100
+ const typeString = context.checker.typeToString(typeOrNode);
101
+ context.logger.verbose(`Refusing to recurse when converting type: ${typeString}`);
102
+ return new models_1.UnknownType(typeString);
99
103
  }
100
104
  let converter = converters.get(node.kind);
101
105
  if (converter) {
@@ -104,9 +108,9 @@ function convertType(context, typeOrNode) {
104
108
  !typeOrNode.isIntersection()) {
105
109
  converter = typeLiteralConverter;
106
110
  }
111
+ seenTypes.add(typeOrNode.id);
107
112
  const result = converter.convertType(context, typeOrNode, node);
108
- if (symbol)
109
- seenTypeSymbols.delete(symbol);
113
+ seenTypes.delete(typeOrNode.id);
110
114
  return result;
111
115
  }
112
116
  return requestBugReport(context, typeOrNode);
@@ -402,12 +406,16 @@ const queryConverter = {
402
406
  // on a variable typed as `any` with a name that doesn't exist.
403
407
  return new models_1.QueryType(models_1.ReferenceType.createBrokenReference(node.exprName.getText(), context.project));
404
408
  }
405
- return new models_1.QueryType(models_1.ReferenceType.createSymbolReference(context.resolveAliasedSymbol(querySymbol), context, node.exprName.getText()));
409
+ const ref = models_1.ReferenceType.createSymbolReference(context.resolveAliasedSymbol(querySymbol), context, node.exprName.getText());
410
+ ref.preferValues = true;
411
+ return new models_1.QueryType(ref);
406
412
  },
407
413
  convertType(context, type, node) {
408
414
  const symbol = type.getSymbol() || context.getSymbolAtLocation(node.exprName);
409
415
  (0, assert_1.default)(symbol, `Query type failed to get a symbol for: ${context.checker.typeToString(type)}. This is a bug.`);
410
- return new models_1.QueryType(models_1.ReferenceType.createSymbolReference(context.resolveAliasedSymbol(symbol), context));
416
+ const ref = models_1.ReferenceType.createSymbolReference(context.resolveAliasedSymbol(symbol), context);
417
+ ref.preferValues = true;
418
+ return new models_1.QueryType(ref);
411
419
  },
412
420
  };
413
421
  const referenceConverter = {
@@ -623,10 +631,6 @@ const typeOperatorConverter = {
623
631
  // keyof will only show up with generic functions, otherwise it gets eagerly
624
632
  // resolved to a union of strings.
625
633
  if (node.operator === typescript_1.default.SyntaxKind.KeyOfKeyword) {
626
- // TS 4.2 added this to enable better tracking of type aliases.
627
- if (type.isUnion() && type.origin) {
628
- return convertType(context, type.origin);
629
- }
630
634
  // There's probably an interface for this somewhere... I couldn't find it.
631
635
  const targetType = type.type;
632
636
  return new models_1.TypeOperatorType(convertType(context, targetType), "keyof");
@@ -642,10 +646,6 @@ const unionConverter = {
642
646
  return new models_1.UnionType(node.types.map((type) => convertType(context, type)));
643
647
  },
644
648
  convertType(context, type) {
645
- // TS 4.2 added this to enable better tracking of type aliases.
646
- if (type.origin) {
647
- return convertType(context, type.origin);
648
- }
649
649
  return new models_1.UnionType(type.types.map((type) => convertType(context, type)));
650
650
  },
651
651
  };
@@ -140,7 +140,6 @@ export declare class Comment {
140
140
  * Return the first tag with the given name.
141
141
  *
142
142
  * @param tagName The name of the tag to look for.
143
- * @param paramName An optional parameter name to look for.
144
143
  * @returns The found tag or undefined.
145
144
  */
146
145
  getTag(tagName: `@${string}`): CommentTag | undefined;