diff --git a/CHANGELOG.md b/CHANGELOG.md index 8558f80cf..49bb86f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,19 @@ # Unreleased +### Bug Fixes + +- Module readmes will now be included in JSON output, #2500. +- Fixed crash when `--excludeNotDocumented` was used and the project contained a reference to a removed signature, #2496. +- Fixed crash when converting an infinitely recursive type via a new `--maxTypeConversionDepth` option, #2507. +- Type links in "Parameters" and "Type Parameters" sections of the page will now be correctly colored. + +### Thanks! + +- @JMBeresford + ## v0.25.8 (2024-02-09) -## Features +### Features - Added a new `--sitemapBaseUrl` option. When specified, TypeDoc will generate a `sitemap.xml` in your output folder that describes the site, #2480. - Added support for the `@class` tag. When added to a comment on a variable or function, TypeDoc will convert the member as a class, #2479. @@ -10,9 +21,8 @@ - Added support for `@groupDescription` and `@categoryDescription` to provide a description of groups and categories, #2494. - API: Exposed `Context.getNodeComment` for plugin use, #2498. -## Bug Fixes +### Bug Fixes -- Fixed crash when `--excludeNotDocumented` was used and the project contained a reference to a removed signature, #2496. - Fixed an issue where a namespace would not be created for merged function-namespaces which are declared as variables, #2478. - A class which implements itself will no longer cause a crash when rendering HTML, #2495. - Variable functions which have construct signatures will no longer be converted as functions, ignoring the construct signatures. diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 08efaaeb9..39641f073 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -97,6 +97,10 @@ export class Converter extends ChildableComponent< @Option("preserveLinkText") accessor preserveLinkText!: boolean; + /** @internal */ + @Option("maxTypeConversionDepth") + accessor maxTypeConversionDepth!: number; + private _config?: CommentParserConfig; private _externalSymbolResolvers: Array = []; diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index 2c8f589a8..991d26143 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -115,6 +115,7 @@ function maybeConvertType( return convertType(context, typeOrNode); } +let typeConversionDepth = 0; export function convertType( context: Context, typeOrNode: ts.Type | ts.TypeNode | undefined, @@ -123,11 +124,18 @@ export function convertType( return new IntrinsicType("any"); } + if (typeConversionDepth > context.converter.maxTypeConversionDepth) { + return new UnknownType("..."); + } + loadConverters(); if ("kind" in typeOrNode) { const converter = converters.get(typeOrNode.kind); if (converter) { - return converter.convert(context, typeOrNode); + ++typeConversionDepth; + const result = converter.convert(context, typeOrNode); + --typeConversionDepth; + return result; } return requestBugReport(context, typeOrNode); } @@ -137,6 +145,7 @@ export function convertType( // will use the origin when serializing // aliasSymbol check is important - #2468 if (typeOrNode.isUnion() && typeOrNode.origin && !typeOrNode.aliasSymbol) { + // Don't increment typeConversionDepth as this is a transparent step to the user. return convertType(context, typeOrNode.origin); } @@ -167,7 +176,9 @@ export function convertType( } seenTypes.add(typeOrNode.id); + ++typeConversionDepth; const result = converter.convertType(context, typeOrNode, node); + --typeConversionDepth; seenTypes.delete(typeOrNode.id); return result; } diff --git a/src/lib/models/reflections/abstract.ts b/src/lib/models/reflections/abstract.ts index 00a9f6357..5f027b0ea 100644 --- a/src/lib/models/reflections/abstract.ts +++ b/src/lib/models/reflections/abstract.ts @@ -1,4 +1,3 @@ -import { ok } from "assert"; import { Comment } from "../comments/comment"; import { splitUnquotedString } from "./utils"; import type { ProjectReflection } from "./project"; @@ -278,14 +277,8 @@ export abstract class Reflection { @NonEnumerable // So that it doesn't show up in console.log parent?: Reflection; - get project(): ProjectReflection { - if (this.isProject()) return this; - ok( - this.parent, - "Tried to get the project on a reflection not in a project", - ); - return this.parent.project; - } + @NonEnumerable + project: ProjectReflection; /** * The parsed documentation comment attached to this reflection. @@ -322,6 +315,7 @@ export abstract class Reflection { constructor(name: string, kind: ReflectionKind, parent?: Reflection) { this.id = REFLECTION_ID++; this.parent = parent; + this.project = parent?.project || (this as any as ProjectReflection); this.name = name; this.kind = kind; diff --git a/src/lib/output/themes/default/partials/member.signature.body.tsx b/src/lib/output/themes/default/partials/member.signature.body.tsx index 5d8b22331..e62efeb72 100644 --- a/src/lib/output/themes/default/partials/member.signature.body.tsx +++ b/src/lib/output/themes/default/partials/member.signature.body.tsx @@ -23,7 +23,7 @@ export function memberSignatureBody(