From f625f15bc20defc4a128722c41dd7c479bd3f045 Mon Sep 17 00:00:00 2001 From: ProjectXero Date: Tue, 29 Jul 2025 13:03:27 +0800 Subject: [PATCH 01/46] Update Chinese translations --- src/lib/internationalization/locales/zh.cts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/lib/internationalization/locales/zh.cts b/src/lib/internationalization/locales/zh.cts index 9250ad7e9..5a0293423 100644 --- a/src/lib/internationalization/locales/zh.cts +++ b/src/lib/internationalization/locales/zh.cts @@ -79,6 +79,8 @@ export = localeUtils.buildIncompleteTranslation({ inline_tag_not_closed: "内联标签未关闭", // validation + comment_for_0_links_to_1_not_included_in_docs_use_external_link_2: + `{0} 注释中指向 “{1}” 的已解析的链接不会被包含在文档中。请将 {2} 导出或添加至 externalSymbolLinkMappings 选项以修复该警告`, failed_to_resolve_link_to_0_in_comment_for_1: "无法解析 {1} 注释中指向 “{0}” 的链接", failed_to_resolve_link_to_0_in_comment_for_1_may_have_meant_2: "无法解析 {1} 的注释中指向 “{0}” 的链接。您可能想要 “{2}”", @@ -103,9 +105,11 @@ export = localeUtils.buildIncompleteTranslation({ "文档中并未使用 searchCategoryBoosts 中指定的所有类别。未使用的类别包括:\n{0}", not_all_search_group_boosts_used_0: "文档中并未使用 searchGroupBoosts 中指定的所有组。未使用的组为:\n{0}", comment_for_0_includes_categoryDescription_for_1_but_no_child_in_group: - "{0} 的评论包含“{1}”的 @categoryDescription,但该类别中没有子项", + "{0} 的注释中包含了 “{1}” 的 @categoryDescription,但该类别中没有子项", comment_for_0_includes_groupDescription_for_1_but_no_child_in_group: - "{0} 的注释包含“{1}”的 @groupDescription,但该组中没有子项", + "{0} 的注释中包含了 “{1}” 的 @groupDescription,但该分组中没有子项", + comment_for_0_specifies_1_as_sort_strategy_but_only_2_is_valid: + `{0} 的注释中指定的 “{1}” 的 @sortStrategy 无效,以下是有效的选项:\n\t{2}`, label_0_for_1_cannot_be_referenced: "无法使用声明引用来引用 {1} 的标签“{0}”。标签只能包含 A-Z、0-9 和 _,并且不能以数字开头", modifier_tag_0_is_mutually_exclusive_with_1_in_comment_for_2: "修饰符标签 {0} 与 {2} 注释中的 {1} 互斥", @@ -187,6 +191,8 @@ export = localeUtils.buildIncompleteTranslation({ circular_reference_extends_0: "{0} 的“extends”字段出现循环引用", failed_resolve_0_to_file_in_1: "无法将 {0} 解析为 {1} 中的文件", + glob_0_should_use_posix_slash: + `该 glob “{0}” 中转义了不是特殊字符的字符。输入 TypeDoc 的 glob 可能不会使用 Windows 路径分隔符(\\),请尝试将其替换为 POSIX 路径分隔符(/)`, option_0_can_only_be_specified_by_config_file: "“{0}”选项只能通过配置文件指定", option_0_expected_a_value_but_none_provided: "--{0} 需要一个值,但没有给出任何参数", unknown_option_0_may_have_meant_1: "未知选项:{0},你可能指的是:\n\t{1}", @@ -348,6 +354,8 @@ export = localeUtils.buildIncompleteTranslation({ "useHostedBaseUrlForAbsoluteLinks 选项要求设置 hostingBaseUrl", favicon_must_have_one_of_the_following_extensions_0: "favicon 的后缀名必须是下列之一:{0}", option_0_must_be_an_object: "“{0}”选项必须是非数组对象", + option_0_must_be_an_array_of_string: "“{0}”选项必须是字符串数组", + option_0_must_be_an_array_of_string_or_functions: "“{0}”选项必须是由字符串或函数构成的数组", option_0_must_be_a_function: "‘{0}’ 选项必须是一个函数", option_0_must_be_object_with_urls: "{0} 必须是具有字符串标签作为键和 URL 值的对象", visibility_filters_only_include_0: "visibilityFilters 只能包含以下非@键:{0}", @@ -514,6 +522,7 @@ export = localeUtils.buildIncompleteTranslation({ tag_return: "返回", tag_satisfies: "满足", tag_since: "添加于", + tag_sortStrategy: "排序策略", tag_template: "类型参数", tag_type: "类型", tag_typedef: "类型定义", @@ -545,6 +554,7 @@ export = localeUtils.buildIncompleteTranslation({ tag_virtual: "虚函数", tag_abstract: "抽象类", tag_class: "类", + tag_disableGroups: "禁用分组", tag_enum: "枚举", tag_event: "事件", tag_expand: "展开", From 73f3dc25f81fd7d548f108d2ae2fd5fd06a52e02 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 1 Aug 2025 08:38:47 -0600 Subject: [PATCH 02/46] Support TypeScript 5.9 Resolves #2989 --- dprint.json | 4 +- package.json | 16 +- pnpm-lock.yaml | 582 +++++++++++++++++++++++++------------------------ 3 files changed, 303 insertions(+), 299 deletions(-) diff --git a/dprint.json b/dprint.json index 2237a8ba6..4faadb249 100644 --- a/dprint.json +++ b/dprint.json @@ -19,9 +19,9 @@ "src/test/converter2/issues/gh2631/crlf.md" ], "plugins": [ - "https://plugins.dprint.dev/typescript-0.95.8.wasm", + "https://plugins.dprint.dev/typescript-0.95.9.wasm", "https://plugins.dprint.dev/json-0.20.0.wasm", "https://plugins.dprint.dev/markdown-0.19.0.wasm", - "https://plugins.dprint.dev/g-plane/malva-v0.12.1.wasm" + "https://plugins.dprint.dev/g-plane/malva-v0.14.1.wasm" ] } diff --git a/package.json b/package.json index c345b7ab3..7a49c7b42 100644 --- a/package.json +++ b/package.json @@ -31,32 +31,32 @@ "pnpm": ">= 10" }, "dependencies": { - "@gerrit0/mini-shiki": "^3.7.0", + "@gerrit0/mini-shiki": "^3.9.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", "yaml": "^2.8.0" }, "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" }, "devDependencies": { - "@eslint/js": "^9.30.0", + "@eslint/js": "^9.32.0", "@types/lunr": "^2.3.7", "@types/markdown-it": "^14.1.2", "@types/mocha": "^10.0.10", "@types/node": "18", "@typestrong/fs-fixture-builder": "github:TypeStrong/fs-fixture-builder#34113409e3a171e68ce5e2b55461ef5c35591cfe", "c8": "^10.1.3", - "dprint": "^0.50.0", - "esbuild": "^0.25.5", - "eslint": "^9.30.0", + "dprint": "^0.50.1", + "esbuild": "^0.25.8", + "eslint": "^9.32.0", "mocha": "^11.7.1", "puppeteer": "^24.11.1", "semver": "^7.7.2", "tsx": "^4.20.3", - "typescript": "5.8.3", - "typescript-eslint": "^8.35.0" + "typescript": "5.9.2", + "typescript-eslint": "^8.38.0" }, "files": [ "/bin", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a59df8b90..7809dfed2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@gerrit0/mini-shiki': - specifier: ^3.7.0 - version: 3.7.0 + specifier: ^3.9.0 + version: 3.9.0 lunr: specifier: ^2.3.9 version: 2.3.9 @@ -25,8 +25,8 @@ importers: version: 2.8.0 devDependencies: '@eslint/js': - specifier: ^9.30.0 - version: 9.30.0 + specifier: ^9.32.0 + version: 9.32.0 '@types/lunr': specifier: ^2.3.7 version: 2.3.7 @@ -46,20 +46,20 @@ importers: specifier: ^10.1.3 version: 10.1.3 dprint: - specifier: ^0.50.0 - version: 0.50.0 + specifier: ^0.50.1 + version: 0.50.1 esbuild: - specifier: ^0.25.5 - version: 0.25.5 + specifier: ^0.25.8 + version: 0.25.8 eslint: - specifier: ^9.30.0 - version: 9.30.0 + specifier: ^9.32.0 + version: 9.32.0 mocha: specifier: ^11.7.1 version: 11.7.1 puppeteer: specifier: ^24.11.1 - version: 24.11.1(typescript@5.8.3) + version: 24.11.1(typescript@5.9.2) semver: specifier: ^7.7.2 version: 7.7.2 @@ -67,11 +67,11 @@ importers: specifier: ^4.20.3 version: 4.20.3 typescript: - specifier: 5.8.3 - version: 5.8.3 + specifier: 5.9.2 + version: 5.9.2 typescript-eslint: - specifier: ^8.35.0 - version: 8.35.0(eslint@9.30.0)(typescript@5.8.3) + specifier: ^8.38.0 + version: 8.38.0(eslint@9.32.0)(typescript@5.9.2) packages: @@ -87,197 +87,203 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@dprint/darwin-arm64@0.50.0': - resolution: {integrity: sha512-KqWpsvm4JveYdKDLSLlQINGNW4pEAGHcTFPEHR5qXMYV4pPomLgHHPyBrxe3XdGtlUp4I8HfvBMBw3b/LKd06A==} + '@dprint/darwin-arm64@0.50.1': + resolution: {integrity: sha512-NNKf3dxXn567pd/hpCVLHLbC0dI7s3YvQnUEwjRTOAQVMp6O7/ME+Tg1RPGsDP1IB+Y2fIYSM4qmG02zQrqjAQ==} cpu: [arm64] os: [darwin] - '@dprint/darwin-x64@0.50.0': - resolution: {integrity: sha512-kFeeLYhCIVAe1SMtFYk1q0qWxrkmW8FhOBTUh2oblr4AnAjpjb03m8BVUrHHKFeBTsppwck+1b8hzU6LRZO7fA==} + '@dprint/darwin-x64@0.50.1': + resolution: {integrity: sha512-PcY75U3UC/0CLOxWzE0zZJZ2PxzUM5AX2baYL1ovgDGCfqO1H0hINiyxfx/8ncGgPojWBkLs+zrcFiGnXx7BQg==} cpu: [x64] os: [darwin] - '@dprint/linux-arm64-glibc@0.50.0': - resolution: {integrity: sha512-EL0+uMSdj/n+cZOP9ZO8ndvjmtOSWXNsMHKdAAaTG0+EjH9M9YKXD6kopP6PKOR5pJuiyHCRpVKJ4xoD4adfpQ==} + '@dprint/linux-arm64-glibc@0.50.1': + resolution: {integrity: sha512-q0TOGy9FsoSKsEQ4sIMKyFweF5M8rW1S5OfwJDNRR2TU2riWByU9TKYIZUzg53iuwYKRypr/kJ5kdbl516afRQ==} cpu: [arm64] os: [linux] - '@dprint/linux-arm64-musl@0.50.0': - resolution: {integrity: sha512-bzyYxKtFw/hYAA+7lWQGQGo2YFPnH7Ql9uWxxWqiGaWVPU66K9WQt0RUEqu1hQBrCk9mMz3jx5l4oKWQ/Dc0fw==} + '@dprint/linux-arm64-musl@0.50.1': + resolution: {integrity: sha512-XRtxN2cA9rc06WFzzVPDIZYGGLmUXqpVf3F0XhhHV77ikQLJZ5reF4xBOQ+0HjJ/zy8W/HzuGDAHedWyCrRf9g==} cpu: [arm64] os: [linux] - '@dprint/linux-riscv64-glibc@0.50.0': - resolution: {integrity: sha512-ElFqmKs96NyVXWqd2SJGJGtyVmUWNiLUyaImEzL7XZRmpoJG+Ky7SryhccMQU0ENtQmY0CVgZipLZ1SqhIoluA==} + '@dprint/linux-riscv64-glibc@0.50.1': + resolution: {integrity: sha512-vAk/eYhSjA3LJ/yuYgxkHamiK8+m6YdqVBO/Ka+i16VxyjQyOdcMKBkrLCIqSxgyXd6b8raf9wM59HJbaIpoOg==} cpu: [riscv64] os: [linux] - '@dprint/linux-x64-glibc@0.50.0': - resolution: {integrity: sha512-Kim8TtCdpCQUNqF2D96vunuonYy6tPfp/AQblSVA4ADChVyFLGfPaQIECpGAAKxXnIG2SX5JRQP7nB/4JgPNbA==} + '@dprint/linux-x64-glibc@0.50.1': + resolution: {integrity: sha512-EpW5KLekaq4hXmKBWWtfBgZ244S4C+vFmMOd1YaGi8+f0hmPTJzVWLdIgpO2ZwfPQ5iycaVI/JS514PQmXPOvg==} cpu: [x64] os: [linux] - '@dprint/linux-x64-musl@0.50.0': - resolution: {integrity: sha512-ChZf0BnS3S6BIfqAPgQKqEh/7vgD1xc0MpcFcTrvkVQHuSdCQu1XiqUN12agzxB+Y5Ml9exgzP8lYgNza7iXvw==} + '@dprint/linux-x64-musl@0.50.1': + resolution: {integrity: sha512-assISBbaKKL8LkjrIy/5tpE157MVW6HbyIKAjTtg3tPNM3lDn1oH3twuGtK9WBsN/VoEP3QMZVauolcUJT/VOg==} cpu: [x64] os: [linux] - '@dprint/win32-arm64@0.50.0': - resolution: {integrity: sha512-xSY607bRyIPG7UO3uRa5c5wTGHKJqLUkQst85Hcz89EL/It6wswwUSNcywDydssN99HmSHop4fIf6FJTEpEp2g==} + '@dprint/win32-arm64@0.50.1': + resolution: {integrity: sha512-ZeaRMQYoFjrsO3lvI1SqzDWDGH1GGXWmNSeXvcFuAf2OgYQJWMBlLotCKiHNJ3uyYneoyhTg2tv9QkApNkZV4Q==} cpu: [arm64] os: [win32] - '@dprint/win32-x64@0.50.0': - resolution: {integrity: sha512-uGDjrK88LOet9a8pPRM9nKins93mK2NLozqL/hCNV88Nu5Nk0bBeVwRMAnPapjV3Jo+hsJOeq3Z1ibrq2c3v8w==} + '@dprint/win32-x64@0.50.1': + resolution: {integrity: sha512-pMm8l/hRZ9zYylKw/yCaYkSV3btYB9UyMDbWqyxNthkQ1gckWrk17VTI6WjwwQuHD4Iaz5JgAYLS36hlUzWkxA==} cpu: [x64] os: [win32] - '@esbuild/aix-ppc64@0.25.5': - resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + '@esbuild/aix-ppc64@0.25.8': + resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.5': - resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + '@esbuild/android-arm64@0.25.8': + resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.5': - resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + '@esbuild/android-arm@0.25.8': + resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.5': - resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + '@esbuild/android-x64@0.25.8': + resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.5': - resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + '@esbuild/darwin-arm64@0.25.8': + resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.5': - resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + '@esbuild/darwin-x64@0.25.8': + resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.5': - resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + '@esbuild/freebsd-arm64@0.25.8': + resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.5': - resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + '@esbuild/freebsd-x64@0.25.8': + resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.5': - resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + '@esbuild/linux-arm64@0.25.8': + resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.5': - resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + '@esbuild/linux-arm@0.25.8': + resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.5': - resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + '@esbuild/linux-ia32@0.25.8': + resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.5': - resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + '@esbuild/linux-loong64@0.25.8': + resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.5': - resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + '@esbuild/linux-mips64el@0.25.8': + resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.5': - resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + '@esbuild/linux-ppc64@0.25.8': + resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.5': - resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + '@esbuild/linux-riscv64@0.25.8': + resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.5': - resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + '@esbuild/linux-s390x@0.25.8': + resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.5': - resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + '@esbuild/linux-x64@0.25.8': + resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.5': - resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + '@esbuild/netbsd-arm64@0.25.8': + resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.5': - resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + '@esbuild/netbsd-x64@0.25.8': + resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.5': - resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + '@esbuild/openbsd-arm64@0.25.8': + resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.5': - resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + '@esbuild/openbsd-x64@0.25.8': + resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.5': - resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + '@esbuild/openharmony-arm64@0.25.8': + resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.8': + resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.5': - resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + '@esbuild/win32-arm64@0.25.8': + resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.5': - resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + '@esbuild/win32-ia32@0.25.8': + resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.5': - resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + '@esbuild/win32-x64@0.25.8': + resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -300,10 +306,6 @@ packages: resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.14.0': - resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.15.1': resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -312,20 +314,20 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.30.0': - resolution: {integrity: sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==} + '@eslint/js@9.32.0': + resolution: {integrity: sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.3.3': - resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==} + '@eslint/plugin-kit@0.3.4': + resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@gerrit0/mini-shiki@3.7.0': - resolution: {integrity: sha512-7iY9wg4FWXmeoFJpUL2u+tsmh0d0jcEJHAIzVxl3TG4KL493JNnisdLAILZ77zcD+z3J0keEXZ+lFzUgzQzPDg==} + '@gerrit0/mini-shiki@3.9.0': + resolution: {integrity: sha512-p58r5PE/hIKtE7aYzeDYZr4DPrOidwoUFPX3p6rPEZWtb7zWX3b7Bu9LZ17XODFiRO4x/VzTE15KYNEaZ3khuw==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -386,17 +388,17 @@ packages: engines: {node: '>=18'} hasBin: true - '@shikijs/engine-oniguruma@3.7.0': - resolution: {integrity: sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==} + '@shikijs/engine-oniguruma@3.9.1': + resolution: {integrity: sha512-WPlL/xqviwS3te4unSGGGfflKsuHLMI6tPdNYvgz/IygcBT6UiwDFSzjBKyebwi5GGSlXsjjdoJLIBnAplmEZw==} - '@shikijs/langs@3.7.0': - resolution: {integrity: sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==} + '@shikijs/langs@3.9.1': + resolution: {integrity: sha512-Vyy2Yv9PP3Veh3VSsIvNncOR+O93wFsNYgN2B6cCCJlS7H9SKFYc55edsqernsg8WT/zam1cfB6llJsQWLnVhA==} - '@shikijs/themes@3.7.0': - resolution: {integrity: sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==} + '@shikijs/themes@3.9.1': + resolution: {integrity: sha512-zAykkGECNICCMXpKeVvq04yqwaSuAIvrf8MjsU5bzskfg4XreU+O0B5wdNCYRixoB9snd3YlZ373WV5E/g5T9A==} - '@shikijs/types@3.7.0': - resolution: {integrity: sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==} + '@shikijs/types@3.9.1': + resolution: {integrity: sha512-rqM3T7a0iM1oPKz9iaH/cVgNX9Vz1HERcUcXJ94/fulgVdwqfnhXzGxO4bLrAnh/o5CPLy3IcYedogfV+Ns0Qg==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -440,63 +442,63 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.35.0': - resolution: {integrity: sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==} + '@typescript-eslint/eslint-plugin@8.38.0': + resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.35.0 + '@typescript-eslint/parser': ^8.38.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/parser@8.35.0': - resolution: {integrity: sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==} + '@typescript-eslint/parser@8.38.0': + resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/project-service@8.35.0': - resolution: {integrity: sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==} + '@typescript-eslint/project-service@8.38.0': + resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/scope-manager@8.35.0': - resolution: {integrity: sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==} + '@typescript-eslint/scope-manager@8.38.0': + resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.35.0': - resolution: {integrity: sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==} + '@typescript-eslint/tsconfig-utils@8.38.0': + resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.35.0': - resolution: {integrity: sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==} + '@typescript-eslint/type-utils@8.38.0': + resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/types@8.35.0': - resolution: {integrity: sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==} + '@typescript-eslint/types@8.38.0': + resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.35.0': - resolution: {integrity: sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==} + '@typescript-eslint/typescript-estree@8.38.0': + resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.35.0': - resolution: {integrity: sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==} + '@typescript-eslint/utils@8.38.0': + resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/visitor-keys@8.35.0': - resolution: {integrity: sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==} + '@typescript-eslint/visitor-keys@8.38.0': + resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typestrong/fs-fixture-builder@https://codeload.github.com/TypeStrong/fs-fixture-builder/tar.gz/34113409e3a171e68ce5e2b55461ef5c35591cfe': @@ -692,8 +694,8 @@ packages: resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} engines: {node: '>=0.3.1'} - dprint@0.50.0: - resolution: {integrity: sha512-aNJhOQsUS5D9k/YkMUaLLniIpxEBUR0ZwT0RXGQV5YpaGwE2nx6FcKuVkC6wRaZXTr8X0NpV/2HFbcvNuI2jtA==} + dprint@0.50.1: + resolution: {integrity: sha512-s+kUyQp2rGpwsM3vVmXySOY3v1NjYyRpKfQZdP4rfNTz6zQuICSO6nqIXNm3YdK1MwNFR/EXSFMuE1YPuulhow==} hasBin: true eastasianwidth@0.2.0: @@ -719,8 +721,8 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - esbuild@0.25.5: - resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + esbuild@0.25.8: + resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} engines: {node: '>=18'} hasBin: true @@ -749,8 +751,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.30.0: - resolution: {integrity: sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==} + eslint@9.32.0: + resolution: {integrity: sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1295,15 +1297,15 @@ packages: typed-query-selector@2.12.0: resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} - typescript-eslint@8.35.0: - resolution: {integrity: sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A==} + typescript-eslint@8.38.0: + resolution: {integrity: sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true @@ -1398,111 +1400,114 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@dprint/darwin-arm64@0.50.0': + '@dprint/darwin-arm64@0.50.1': optional: true - '@dprint/darwin-x64@0.50.0': + '@dprint/darwin-x64@0.50.1': optional: true - '@dprint/linux-arm64-glibc@0.50.0': + '@dprint/linux-arm64-glibc@0.50.1': optional: true - '@dprint/linux-arm64-musl@0.50.0': + '@dprint/linux-arm64-musl@0.50.1': optional: true - '@dprint/linux-riscv64-glibc@0.50.0': + '@dprint/linux-riscv64-glibc@0.50.1': optional: true - '@dprint/linux-x64-glibc@0.50.0': + '@dprint/linux-x64-glibc@0.50.1': optional: true - '@dprint/linux-x64-musl@0.50.0': + '@dprint/linux-x64-musl@0.50.1': optional: true - '@dprint/win32-arm64@0.50.0': + '@dprint/win32-arm64@0.50.1': optional: true - '@dprint/win32-x64@0.50.0': + '@dprint/win32-x64@0.50.1': optional: true - '@esbuild/aix-ppc64@0.25.5': + '@esbuild/aix-ppc64@0.25.8': optional: true - '@esbuild/android-arm64@0.25.5': + '@esbuild/android-arm64@0.25.8': optional: true - '@esbuild/android-arm@0.25.5': + '@esbuild/android-arm@0.25.8': optional: true - '@esbuild/android-x64@0.25.5': + '@esbuild/android-x64@0.25.8': optional: true - '@esbuild/darwin-arm64@0.25.5': + '@esbuild/darwin-arm64@0.25.8': optional: true - '@esbuild/darwin-x64@0.25.5': + '@esbuild/darwin-x64@0.25.8': optional: true - '@esbuild/freebsd-arm64@0.25.5': + '@esbuild/freebsd-arm64@0.25.8': optional: true - '@esbuild/freebsd-x64@0.25.5': + '@esbuild/freebsd-x64@0.25.8': optional: true - '@esbuild/linux-arm64@0.25.5': + '@esbuild/linux-arm64@0.25.8': optional: true - '@esbuild/linux-arm@0.25.5': + '@esbuild/linux-arm@0.25.8': optional: true - '@esbuild/linux-ia32@0.25.5': + '@esbuild/linux-ia32@0.25.8': optional: true - '@esbuild/linux-loong64@0.25.5': + '@esbuild/linux-loong64@0.25.8': optional: true - '@esbuild/linux-mips64el@0.25.5': + '@esbuild/linux-mips64el@0.25.8': optional: true - '@esbuild/linux-ppc64@0.25.5': + '@esbuild/linux-ppc64@0.25.8': optional: true - '@esbuild/linux-riscv64@0.25.5': + '@esbuild/linux-riscv64@0.25.8': optional: true - '@esbuild/linux-s390x@0.25.5': + '@esbuild/linux-s390x@0.25.8': optional: true - '@esbuild/linux-x64@0.25.5': + '@esbuild/linux-x64@0.25.8': optional: true - '@esbuild/netbsd-arm64@0.25.5': + '@esbuild/netbsd-arm64@0.25.8': optional: true - '@esbuild/netbsd-x64@0.25.5': + '@esbuild/netbsd-x64@0.25.8': optional: true - '@esbuild/openbsd-arm64@0.25.5': + '@esbuild/openbsd-arm64@0.25.8': optional: true - '@esbuild/openbsd-x64@0.25.5': + '@esbuild/openbsd-x64@0.25.8': optional: true - '@esbuild/sunos-x64@0.25.5': + '@esbuild/openharmony-arm64@0.25.8': optional: true - '@esbuild/win32-arm64@0.25.5': + '@esbuild/sunos-x64@0.25.8': optional: true - '@esbuild/win32-ia32@0.25.5': + '@esbuild/win32-arm64@0.25.8': optional: true - '@esbuild/win32-x64@0.25.5': + '@esbuild/win32-ia32@0.25.8': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.30.0)': + '@esbuild/win32-x64@0.25.8': + optional: true + + '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0)': dependencies: - eslint: 9.30.0 + eslint: 9.32.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -1517,10 +1522,6 @@ snapshots: '@eslint/config-helpers@0.3.0': {} - '@eslint/core@0.14.0': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/core@0.15.1': dependencies: '@types/json-schema': 7.0.15 @@ -1539,21 +1540,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.30.0': {} + '@eslint/js@9.32.0': {} '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.3.3': + '@eslint/plugin-kit@0.3.4': dependencies: '@eslint/core': 0.15.1 levn: 0.4.1 - '@gerrit0/mini-shiki@3.7.0': + '@gerrit0/mini-shiki@3.9.0': dependencies: - '@shikijs/engine-oniguruma': 3.7.0 - '@shikijs/langs': 3.7.0 - '@shikijs/themes': 3.7.0 - '@shikijs/types': 3.7.0 + '@shikijs/engine-oniguruma': 3.9.1 + '@shikijs/langs': 3.9.1 + '@shikijs/themes': 3.9.1 + '@shikijs/types': 3.9.1 '@shikijs/vscode-textmate': 10.0.2 '@humanfs/core@0.19.1': {} @@ -1617,20 +1618,20 @@ snapshots: - bare-buffer - supports-color - '@shikijs/engine-oniguruma@3.7.0': + '@shikijs/engine-oniguruma@3.9.1': dependencies: - '@shikijs/types': 3.7.0 + '@shikijs/types': 3.9.1 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.7.0': + '@shikijs/langs@3.9.1': dependencies: - '@shikijs/types': 3.7.0 + '@shikijs/types': 3.9.1 - '@shikijs/themes@3.7.0': + '@shikijs/themes@3.9.1': dependencies: - '@shikijs/types': 3.7.0 + '@shikijs/types': 3.9.1 - '@shikijs/types@3.7.0': + '@shikijs/types@3.9.1': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -1673,96 +1674,97 @@ snapshots: '@types/node': 18.19.113 optional: true - '@typescript-eslint/eslint-plugin@8.35.0(@typescript-eslint/parser@8.35.0(eslint@9.30.0)(typescript@5.8.3))(eslint@9.30.0)(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.35.0(eslint@9.30.0)(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.35.0 - '@typescript-eslint/type-utils': 8.35.0(eslint@9.30.0)(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.0(eslint@9.30.0)(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.35.0 - eslint: 9.30.0 + '@typescript-eslint/parser': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.38.0 + '@typescript-eslint/type-utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.38.0 + eslint: 9.32.0 graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.35.0(eslint@9.30.0)(typescript@5.8.3)': + '@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.35.0 - '@typescript-eslint/types': 8.35.0 - '@typescript-eslint/typescript-estree': 8.35.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.35.0 + '@typescript-eslint/scope-manager': 8.38.0 + '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.38.0 debug: 4.4.1(supports-color@8.1.1) - eslint: 9.30.0 - typescript: 5.8.3 + eslint: 9.32.0 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.35.0(typescript@5.8.3)': + '@typescript-eslint/project-service@8.38.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.35.0(typescript@5.8.3) - '@typescript-eslint/types': 8.35.0 + '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) + '@typescript-eslint/types': 8.38.0 debug: 4.4.1(supports-color@8.1.1) - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.35.0': + '@typescript-eslint/scope-manager@8.38.0': dependencies: - '@typescript-eslint/types': 8.35.0 - '@typescript-eslint/visitor-keys': 8.35.0 + '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/visitor-keys': 8.38.0 - '@typescript-eslint/tsconfig-utils@8.35.0(typescript@5.8.3)': + '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.9.2)': dependencies: - typescript: 5.8.3 + typescript: 5.9.2 - '@typescript-eslint/type-utils@8.35.0(eslint@9.30.0)(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.38.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.35.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.0(eslint@9.30.0)(typescript@5.8.3) + '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) debug: 4.4.1(supports-color@8.1.1) - eslint: 9.30.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + eslint: 9.32.0 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.35.0': {} + '@typescript-eslint/types@8.38.0': {} - '@typescript-eslint/typescript-estree@8.35.0(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.38.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.35.0(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.35.0(typescript@5.8.3) - '@typescript-eslint/types': 8.35.0 - '@typescript-eslint/visitor-keys': 8.35.0 + '@typescript-eslint/project-service': 8.38.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) + '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/visitor-keys': 8.38.0 debug: 4.4.1(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.35.0(eslint@9.30.0)(typescript@5.8.3)': + '@typescript-eslint/utils@8.38.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.0) - '@typescript-eslint/scope-manager': 8.35.0 - '@typescript-eslint/types': 8.35.0 - '@typescript-eslint/typescript-estree': 8.35.0(typescript@5.8.3) - eslint: 9.30.0 - typescript: 5.8.3 + '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) + '@typescript-eslint/scope-manager': 8.38.0 + '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + eslint: 9.32.0 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.35.0': + '@typescript-eslint/visitor-keys@8.38.0': dependencies: - '@typescript-eslint/types': 8.35.0 + '@typescript-eslint/types': 8.38.0 eslint-visitor-keys: 4.2.1 '@typestrong/fs-fixture-builder@https://codeload.github.com/TypeStrong/fs-fixture-builder/tar.gz/34113409e3a171e68ce5e2b55461ef5c35591cfe': {} @@ -1895,14 +1897,14 @@ snapshots: convert-source-map@2.0.0: {} - cosmiconfig@9.0.0(typescript@5.8.3): + cosmiconfig@9.0.0(typescript@5.9.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 cross-spawn@7.0.6: dependencies: @@ -1932,17 +1934,17 @@ snapshots: diff@7.0.0: {} - dprint@0.50.0: + dprint@0.50.1: optionalDependencies: - '@dprint/darwin-arm64': 0.50.0 - '@dprint/darwin-x64': 0.50.0 - '@dprint/linux-arm64-glibc': 0.50.0 - '@dprint/linux-arm64-musl': 0.50.0 - '@dprint/linux-riscv64-glibc': 0.50.0 - '@dprint/linux-x64-glibc': 0.50.0 - '@dprint/linux-x64-musl': 0.50.0 - '@dprint/win32-arm64': 0.50.0 - '@dprint/win32-x64': 0.50.0 + '@dprint/darwin-arm64': 0.50.1 + '@dprint/darwin-x64': 0.50.1 + '@dprint/linux-arm64-glibc': 0.50.1 + '@dprint/linux-arm64-musl': 0.50.1 + '@dprint/linux-riscv64-glibc': 0.50.1 + '@dprint/linux-x64-glibc': 0.50.1 + '@dprint/linux-x64-musl': 0.50.1 + '@dprint/win32-arm64': 0.50.1 + '@dprint/win32-x64': 0.50.1 eastasianwidth@0.2.0: {} @@ -1962,33 +1964,34 @@ snapshots: dependencies: is-arrayish: 0.2.1 - esbuild@0.25.5: + esbuild@0.25.8: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.5 - '@esbuild/android-arm': 0.25.5 - '@esbuild/android-arm64': 0.25.5 - '@esbuild/android-x64': 0.25.5 - '@esbuild/darwin-arm64': 0.25.5 - '@esbuild/darwin-x64': 0.25.5 - '@esbuild/freebsd-arm64': 0.25.5 - '@esbuild/freebsd-x64': 0.25.5 - '@esbuild/linux-arm': 0.25.5 - '@esbuild/linux-arm64': 0.25.5 - '@esbuild/linux-ia32': 0.25.5 - '@esbuild/linux-loong64': 0.25.5 - '@esbuild/linux-mips64el': 0.25.5 - '@esbuild/linux-ppc64': 0.25.5 - '@esbuild/linux-riscv64': 0.25.5 - '@esbuild/linux-s390x': 0.25.5 - '@esbuild/linux-x64': 0.25.5 - '@esbuild/netbsd-arm64': 0.25.5 - '@esbuild/netbsd-x64': 0.25.5 - '@esbuild/openbsd-arm64': 0.25.5 - '@esbuild/openbsd-x64': 0.25.5 - '@esbuild/sunos-x64': 0.25.5 - '@esbuild/win32-arm64': 0.25.5 - '@esbuild/win32-ia32': 0.25.5 - '@esbuild/win32-x64': 0.25.5 + '@esbuild/aix-ppc64': 0.25.8 + '@esbuild/android-arm': 0.25.8 + '@esbuild/android-arm64': 0.25.8 + '@esbuild/android-x64': 0.25.8 + '@esbuild/darwin-arm64': 0.25.8 + '@esbuild/darwin-x64': 0.25.8 + '@esbuild/freebsd-arm64': 0.25.8 + '@esbuild/freebsd-x64': 0.25.8 + '@esbuild/linux-arm': 0.25.8 + '@esbuild/linux-arm64': 0.25.8 + '@esbuild/linux-ia32': 0.25.8 + '@esbuild/linux-loong64': 0.25.8 + '@esbuild/linux-mips64el': 0.25.8 + '@esbuild/linux-ppc64': 0.25.8 + '@esbuild/linux-riscv64': 0.25.8 + '@esbuild/linux-s390x': 0.25.8 + '@esbuild/linux-x64': 0.25.8 + '@esbuild/netbsd-arm64': 0.25.8 + '@esbuild/netbsd-x64': 0.25.8 + '@esbuild/openbsd-arm64': 0.25.8 + '@esbuild/openbsd-x64': 0.25.8 + '@esbuild/openharmony-arm64': 0.25.8 + '@esbuild/sunos-x64': 0.25.8 + '@esbuild/win32-arm64': 0.25.8 + '@esbuild/win32-ia32': 0.25.8 + '@esbuild/win32-x64': 0.25.8 escalade@3.2.0: {} @@ -2011,16 +2014,16 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.30.0: + eslint@9.32.0: dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.0) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.0 - '@eslint/core': 0.14.0 + '@eslint/core': 0.15.1 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.30.0 - '@eslint/plugin-kit': 0.3.3 + '@eslint/js': 9.32.0 + '@eslint/plugin-kit': 0.3.4 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -2467,11 +2470,11 @@ snapshots: - supports-color - utf-8-validate - puppeteer@24.11.1(typescript@5.8.3): + puppeteer@24.11.1(typescript@5.9.2): dependencies: '@puppeteer/browsers': 2.10.5 chromium-bidi: 5.1.0(devtools-protocol@0.0.1464554) - cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig: 9.0.0(typescript@5.9.2) devtools-protocol: 0.0.1464554 puppeteer-core: 24.11.1 typed-query-selector: 2.12.0 @@ -2605,15 +2608,15 @@ snapshots: dependencies: is-number: 7.0.0 - ts-api-utils@2.1.0(typescript@5.8.3): + ts-api-utils@2.1.0(typescript@5.9.2): dependencies: - typescript: 5.8.3 + typescript: 5.9.2 tslib@2.8.1: {} tsx@4.20.3: dependencies: - esbuild: 0.25.5 + esbuild: 0.25.8 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 @@ -2624,17 +2627,18 @@ snapshots: typed-query-selector@2.12.0: {} - typescript-eslint@8.35.0(eslint@9.30.0)(typescript@5.8.3): + typescript-eslint@8.38.0(eslint@9.32.0)(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.35.0(@typescript-eslint/parser@8.35.0(eslint@9.30.0)(typescript@5.8.3))(eslint@9.30.0)(typescript@5.8.3) - '@typescript-eslint/parser': 8.35.0(eslint@9.30.0)(typescript@5.8.3) - '@typescript-eslint/utils': 8.35.0(eslint@9.30.0)(typescript@5.8.3) - eslint: 9.30.0 - typescript: 5.8.3 + '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + eslint: 9.32.0 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - typescript@5.8.3: {} + typescript@5.9.2: {} uc.micro@2.1.0: {} From 47b5e98d04b80f177050013db321aaa1c281fbb4 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 1 Aug 2025 08:52:41 -0600 Subject: [PATCH 03/46] Fix auto discovery of entry points Resolves #2988 --- CHANGELOG.md | 8 +++ src/lib/application.ts | 6 -- src/lib/converter/factories/symbol-id.ts | 72 +----------------------- src/lib/utils/declaration-maps.ts | 71 +++++++++++++++++++++++ src/lib/utils/entry-point.ts | 19 ++++++- src/lib/utils/index.ts | 1 + 6 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 src/lib/utils/declaration-maps.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f0cca41a..e54923748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ title: Changelog ## Unreleased +### Features + +- Add support for TypeScript 5.9, #2989. + +### Bug Fixes + +- Fixed automatic discovery of entry points when not running in packages mode, #2988. + ## v0.28.8 (2025-07-28) ### Features diff --git a/src/lib/application.ts b/src/lib/application.ts index 779b3310a..68f3afb35 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -43,7 +43,6 @@ import { Outputs } from "./output/output.js"; import { validateMergeModuleWith } from "./validation/unusedMergeModuleWith.js"; import { diagnostic, diagnostics } from "./utils/loggers.js"; import { ValidatingFileRegistry } from "./utils/ValidatingFileRegistry.js"; -import { addInferredDeclarationMapPaths } from "./converter/factories/symbol-id.js"; import { Internationalization } from "./internationalization/internationalization.js"; const packageInfo = JSON.parse( @@ -822,11 +821,6 @@ export class Application extends AbstractComponent< continue; } - addInferredDeclarationMapPaths( - opts.getCompilerOptions(), - opts.getFileNames(), - ); - projectsToConvert.push({ dir, options: opts }); } diff --git a/src/lib/converter/factories/symbol-id.ts b/src/lib/converter/factories/symbol-id.ts index ee7b4b74b..75c45cdfe 100644 --- a/src/lib/converter/factories/symbol-id.ts +++ b/src/lib/converter/factories/symbol-id.ts @@ -1,12 +1,9 @@ import { ReflectionSymbolId } from "#models"; -import { findPackageForPath, getCommonDirectory, getQualifiedName, normalizePath, readFile } from "#node-utils"; -import { type NormalizedPath, Validation } from "#utils"; -import { existsSync } from "fs"; -import { join, relative, resolve } from "node:path"; +import { findPackageForPath, getQualifiedName, normalizePath, resolveDeclarationMaps } from "#node-utils"; +import { type NormalizedPath } from "#utils"; +import { relative } from "node:path"; import ts from "typescript"; -const declarationMapCache = new Map(); - let transientCount = 0; const transientIds = new WeakMap(); @@ -51,66 +48,3 @@ export function createSymbolIdImpl(symbol: ts.Symbol, declaration?: ts.Declarati return id; } - -function resolveDeclarationMaps(file: string): string { - if (!/\.d\.[cm]?ts$/.test(file)) return file; - if (declarationMapCache.has(file)) return declarationMapCache.get(file)!; - - const mapFile = file + ".map"; - if (!existsSync(mapFile)) return file; - - let sourceMap: unknown; - try { - sourceMap = JSON.parse(readFile(mapFile)) as unknown; - } catch { - return file; - } - - if ( - Validation.validate( - { - file: String, - sourceRoot: Validation.optional(String), - sources: [Array, String], - }, - sourceMap, - ) - ) { - // There's a pretty large assumption in here that we only have - // 1 source file per js file. This is a pretty standard typescript approach, - // but people might do interesting things with transpilation that could break this. - let source = sourceMap.sources[0]; - - // If we have a sourceRoot, trim any leading slash from the source, and join them - // Similar to how it's done at https://github.com/mozilla/source-map/blob/58819f09018d56ef84dc41ba9c93f554e0645169/lib/util.js#L412 - if (sourceMap.sourceRoot !== undefined) { - source = source.replace(/^\//, ""); - source = join(sourceMap.sourceRoot, source); - } - - const result = resolve(mapFile, "..", source); - declarationMapCache.set(file, result); - return result; - } - - return file; -} - -// See also: inferEntryPoints in entry-point.ts -export function addInferredDeclarationMapPaths( - opts: ts.CompilerOptions, - files: readonly string[], -) { - const rootDir = opts.rootDir || getCommonDirectory(files); - const declDir = opts.declarationDir || opts.outDir || rootDir; - - for (const file of files) { - const mapFile = normalizePath( - resolve(declDir, relative(rootDir, file)).replace( - /\.([cm]?[tj]s)x?$/, - ".d.$1", - ), - ); - declarationMapCache.set(mapFile, file); - } -} diff --git a/src/lib/utils/declaration-maps.ts b/src/lib/utils/declaration-maps.ts new file mode 100644 index 000000000..a6183d6f7 --- /dev/null +++ b/src/lib/utils/declaration-maps.ts @@ -0,0 +1,71 @@ +import type ts from "typescript"; +import { existsSync } from "fs"; +import { readFile } from "./fs.js"; +import { Validation } from "#utils"; +import { join, relative, resolve } from "path"; +import { getCommonDirectory, normalizePath } from "./paths.js"; + +const declarationMapCache = new Map(); + +export function resolveDeclarationMaps(file: string): string { + if (!/\.d\.[cm]?ts$/.test(file)) return file; + if (declarationMapCache.has(file)) return declarationMapCache.get(file)!; + + const mapFile = file + ".map"; + if (!existsSync(mapFile)) return file; + + let sourceMap: unknown; + try { + sourceMap = JSON.parse(readFile(mapFile)) as unknown; + } catch { + return file; + } + + if ( + Validation.validate( + { + file: String, + sourceRoot: Validation.optional(String), + sources: [Array, String], + }, + sourceMap, + ) + ) { + // There's a pretty large assumption in here that we only have + // 1 source file per js file. This is a pretty standard typescript approach, + // but people might do interesting things with transpilation that could break this. + let source = sourceMap.sources[0]; + + // If we have a sourceRoot, trim any leading slash from the source, and join them + // Similar to how it's done at https://github.com/mozilla/source-map/blob/58819f09018d56ef84dc41ba9c93f554e0645169/lib/util.js#L412 + if (sourceMap.sourceRoot !== undefined) { + source = source.replace(/^\//, ""); + source = join(sourceMap.sourceRoot, source); + } + + const result = resolve(mapFile, "..", source); + declarationMapCache.set(file, result); + return result; + } + + return file; +} + +// See also: inferEntryPoints in entry-point.ts +export function addInferredDeclarationMapPaths( + opts: ts.CompilerOptions, + files: readonly string[], +) { + const rootDir = opts.rootDir || getCommonDirectory(files); + const declDir = opts.declarationDir || opts.outDir || rootDir; + + for (const file of files) { + const mapFile = normalizePath( + resolve(declDir, relative(rootDir, file)).replace( + /\.([cm]?[tj]s)x?$/, + ".d.$1", + ), + ); + declarationMapCache.set(mapFile, file); + } +} diff --git a/src/lib/utils/entry-point.ts b/src/lib/utils/entry-point.ts index 4a28627e1..0e1aca810 100644 --- a/src/lib/utils/entry-point.ts +++ b/src/lib/utils/entry-point.ts @@ -6,6 +6,7 @@ import { deriveRootDir, getCommonDirectory, MinimatchSet, nicePath, normalizePat import type { Options } from "./options/index.js"; import { discoverPackageJson, glob, inferPackageEntryPointPaths, isDir } from "./fs.js"; import { assertNever, type GlobString, i18n, type Logger, type NormalizedPath } from "#utils"; +import { addInferredDeclarationMapPaths, resolveDeclarationMaps } from "./declaration-maps.js"; /** * Defines how entry points are interpreted. @@ -65,7 +66,7 @@ export function inferEntryPoints(logger: Logger, options: Options, programs?: ts options, ); - // See also: addInferredDeclarationMapPaths in ReflectionSymbolId + // See also: addInferredDeclarationMapPaths in symbol-id factory const jsToTsSource = new Map(); for (const program of programs) { const opts = program.getCompilerOptions(); @@ -86,7 +87,7 @@ export function inferEntryPoints(logger: Logger, options: Options, programs?: ts for (const [name, path] of pathEntries) { // Strip leading ./ from the display name const displayName = name.replace(/^\.\/?/, ""); - const targetPath = jsToTsSource.get(path) || path; + const targetPath = jsToTsSource.get(path) || resolveDeclarationMaps(path) || path; const program = programs.find((p) => p.getSourceFile(targetPath)); if (program) { @@ -107,6 +108,10 @@ export function inferEntryPoints(logger: Logger, options: Options, programs?: ts return []; } + logger.verbose( + `Inferred entry points to be:\n\t${entryPoints.map(e => nicePath(e.sourceFile.fileName)).join("\n\t")}`, + ); + return entryPoints; } @@ -413,6 +418,11 @@ function getEntryPrograms( projectReferences: options.getProjectReferences(), }); + addInferredDeclarationMapPaths( + options.getCompilerOptions(), + options.getFileNames(), + ); + const programs = [rootProgram]; // This might be a solution style tsconfig, in which case we need to add a program for each // reference so that the converter can look through each of these. @@ -433,6 +443,11 @@ function getEntryPrograms( projectReferences: ref.commandLine.projectReferences, }), ); + + addInferredDeclarationMapPaths( + ref.commandLine.options, + ref.commandLine.fileNames, + ); } } diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 605a8b406..a48c4f739 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -44,6 +44,7 @@ export type { SortStrategy } from "./sort.js"; export * from "./entry-point.js"; +export * from "./declaration-maps.js"; export * from "./highlighter.js"; export * from "./html.js"; export * from "./tsconfig.js"; From 303eb384e47045730a7c90b62db9151793092547 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 1 Aug 2025 08:57:33 -0600 Subject: [PATCH 04/46] Fix discovery of package.json when entry points are globbed Resolves #2985 --- CHANGELOG.md | 1 + src/lib/converter/plugins/PackagePlugin.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54923748..979f338e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ title: Changelog ### Bug Fixes - Fixed automatic discovery of entry points when not running in packages mode, #2988. +- Fixed discovery of package.json file when running with entry points containing a glob, #2985. ## v0.28.8 (2025-07-28) diff --git a/src/lib/converter/plugins/PackagePlugin.ts b/src/lib/converter/plugins/PackagePlugin.ts index 8dbe44b41..5225e910b 100644 --- a/src/lib/converter/plugins/PackagePlugin.ts +++ b/src/lib/converter/plugins/PackagePlugin.ts @@ -8,9 +8,9 @@ import { ConverterEvents } from "../converter-events.js"; import type { Converter } from "../converter.js"; import { type GlobString, i18n, MinimalSourceFile, type NormalizedPath, NormalizedPathUtils } from "#utils"; import { + deriveRootDir, discoverPackageJson, type EntryPointStrategy, - getCommonDirectory, nicePath, normalizePath, Option, @@ -79,7 +79,7 @@ export class PackagePlugin extends ConverterComponent { this.packageJson = undefined; const dirName = this.application.options.packageDir ?? - Path.resolve(getCommonDirectory(this.entryPoints.map(g => `${g}/`))); + Path.resolve(deriveRootDir(this.entryPoints)); this.application.logger.verbose( `Begin package.json search at ${nicePath(dirName)}`, From f1aee8556238f1b675ff928552c3f29c186fff69 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 1 Aug 2025 09:26:05 -0600 Subject: [PATCH 05/46] Be even more restrictive with parent links Resolves #2982 --- CHANGELOG.md | 1 + src/lib/converter/plugins/ImplementsPlugin.ts | 13 +- src/test/converter2/renderer/gh2982.ts | 6 + src/test/converter2/renderer/index.ts | 1 + .../specs/interfaces/GH2982.TMXDataNode.json | 352 ++++++++++++++++++ src/test/renderer/specs/modules.json | 60 ++- src/test/renderer/specs/modules/GH2982.json | 208 +++++++++++ .../renderer/specs/types/GH2982.TMXNode.json | 120 ++++++ 8 files changed, 744 insertions(+), 17 deletions(-) create mode 100644 src/test/converter2/renderer/gh2982.ts create mode 100644 src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json create mode 100644 src/test/renderer/specs/modules/GH2982.json create mode 100644 src/test/renderer/specs/types/GH2982.TMXNode.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 979f338e7..49ed1e43d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ title: Changelog ### Bug Fixes +- Fixed bug introduced in 0.28.8 where TypeDoc could not render docs when members inherited from a complex type alias, #2982. - Fixed automatic discovery of entry points when not running in packages mode, #2988. - Fixed discovery of package.json file when running with entry points containing a glob, #2985. diff --git a/src/lib/converter/plugins/ImplementsPlugin.ts b/src/lib/converter/plugins/ImplementsPlugin.ts index 332d1640c..cab484371 100644 --- a/src/lib/converter/plugins/ImplementsPlugin.ts +++ b/src/lib/converter/plugins/ImplementsPlugin.ts @@ -172,19 +172,24 @@ export class ImplementsPlugin extends ConverterComponent { // serialization/deserialization, might point to an unexpected location. (See the mixin // converter tests, I suspect this might actually be an indication of something else slightly // broken there, but don't want to spend more time with this right now.) + // #2982, even more unfortunately, we only want to keep the link if it is pointing to a reflection + // which will receive a link during rendering. + const isValidRef = (ref: ReferenceType) => + ref.reflection && !ref.reflection.parent?.kindOf(ReflectionKind.TypeLiteral); + for (const child of reflection.children || []) { - if (child.inheritedFrom && !child.inheritedFrom.reflection) { + if (child.inheritedFrom && !isValidRef(child.inheritedFrom)) { child.inheritedFrom = ReferenceType.createBrokenReference(child.inheritedFrom.name, project); } - if (child.overwrites && !child.overwrites.reflection) { + if (child.overwrites && !isValidRef(child.overwrites)) { child.overwrites = ReferenceType.createBrokenReference(child.overwrites.name, project); } for (const childSig of child.getAllSignatures()) { - if (childSig.inheritedFrom && !childSig.inheritedFrom.reflection) { + if (childSig.inheritedFrom && !isValidRef(childSig.inheritedFrom)) { childSig.inheritedFrom = ReferenceType.createBrokenReference(childSig.inheritedFrom.name, project); } - if (childSig.overwrites && !childSig.overwrites.reflection) { + if (childSig.overwrites && !isValidRef(childSig.overwrites)) { childSig.overwrites = ReferenceType.createBrokenReference(childSig.overwrites.name, project); } } diff --git a/src/test/converter2/renderer/gh2982.ts b/src/test/converter2/renderer/gh2982.ts new file mode 100644 index 000000000..678f957ec --- /dev/null +++ b/src/test/converter2/renderer/gh2982.ts @@ -0,0 +1,6 @@ +export type TMXNode = {} & { + base: T; +}; + +export interface TMXDataNode extends TMXNode<{ extra: any }> { +} diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 8d354b5ea..76142a6df 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -135,3 +135,4 @@ export interface DisabledGroups { } export * as ExpandType from "./expandType"; +export * as GH2982 from "./gh2982"; diff --git a/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json new file mode 100644 index 000000000..59e5f0c17 --- /dev/null +++ b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json @@ -0,0 +1,352 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": [ + { + "li": { + "tag": "a", + "props": { + "href": "../modules/GH2982.json" + }, + "children": "GH2982" + } + }, + { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "TMXDataNode" + } + } + ] + }, + { + "h1": "Interface TMXDataNode" + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-signature-keyword": "interface" + }, + " ", + { + "span.tsd-kind-interface": "TMXDataNode" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + { + "br": [] + }, + "    ", + { + "tag": "a.tsd-kind-property", + "props": { + "href": "#base" + }, + "children": "base" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + " ", + { + "span.tsd-kind-property": "extra" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "any" + }, + " ", + { + "span.tsd-signature-symbol": "}" + }, + { + "span.tsd-signature-symbol": ";" + }, + { + "br": [] + }, + { + "span.tsd-signature-symbol": "}" + } + ] + }, + { + "tag": "section.tsd-panel.tsd-hierarchy", + "props": { + "data-refl": "122" + }, + "children": [ + { + "h4": [ + "Hierarchy (", + { + "tag": "a", + "props": { + "href": "../hierarchy.html#GH2982.TMXDataNode" + }, + "children": "View Summary" + }, + ")" + ] + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": [ + { + "tag": "a.tsd-signature-type.tsd-kind-type-alias", + "props": { + "href": "../types/GH2982.TMXNode.json" + }, + "children": "TMXNode" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-symbol": "{" + }, + " ", + { + "span.tsd-kind-property": "extra" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "any" + }, + " ", + { + "span.tsd-signature-symbol": "}" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": { + "span.tsd-hierarchy-target": "TMXDataNode" + } + } + } + ] + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh2982.ts" + }, + "children": "gh2982.ts:5" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Properties" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link.tsd-is-inherited", + "props": { + "href": "#base" + }, + "children": { + "span": "base" + } + }, + "\n" + ] + } + ] + } + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Properties" + }, + "children": { + "h2": "Properties" + } + }, + { + "section": { + "section.tsd-panel.tsd-member.tsd-is-inherited": [ + { + "h3.tsd-anchor-link#base": [ + { + "span": "base" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#base", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-kind-property": "base" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + " ", + { + "span.tsd-kind-property": "extra" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "any" + }, + " ", + { + "span.tsd-signature-symbol": "}" + } + ] + }, + { + "aside.tsd-sources": [ + { + "p": "Inherited from TMXNode.base" + }, + { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh2982.ts" + }, + "children": "gh2982.ts:2" + } + ] + } + } + ] + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Properties" + }, + "children": "Properties" + }, + { + "div": { + "tag": "a.tsd-is-inherited", + "props": { + "href": "#base" + }, + "children": { + "span": "base" + } + } + } + ] + } + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index 21b6084dd..e56b3d3d5 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -106,6 +106,29 @@ ] } }, + { + "dd.tsd-member-summary": [] + }, + { + "dt.tsd-member-summary#gh2982": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "modules/GH2982.json" + }, + "children": "GH2982" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#gh2982", + "aria-label": "Permalink" + } + } + ] + } + }, { "dd.tsd-member-summary": [] } @@ -551,21 +574,32 @@ "children": "Namespaces" }, { - "div": { - "tag": "a", - "props": { - "href": "#expandtype" + "div": [ + { + "tag": "a", + "props": { + "href": "#expandtype" + }, + "children": { + "span": [ + "Expand", + { + "wbr": [] + }, + "Type" + ] + } }, - "children": { - "span": [ - "Expand", - { - "wbr": [] - }, - "Type" - ] + { + "tag": "a", + "props": { + "href": "#gh2982" + }, + "children": { + "span": "GH2982" + } } - } + ] } ] }, diff --git a/src/test/renderer/specs/modules/GH2982.json b/src/test/renderer/specs/modules/GH2982.json new file mode 100644 index 000000000..40c28d9dc --- /dev/null +++ b/src/test/renderer/specs/modules/GH2982.json @@ -0,0 +1,208 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "GH2982" + } + } + }, + { + "h1": "Namespace GH2982" + } + ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Interfaces" + }, + "children": { + "h2": "Interfaces" + } + }, + { + "dl.tsd-member-summaries": [ + { + "dt.tsd-member-summary#tmxdatanode": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "../interfaces/GH2982.TMXDataNode.json" + }, + "children": "TMXDataNode" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#tmxdatanode", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + } + ] + } + ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Type Aliases" + }, + "children": { + "h2": "Type Aliases" + } + }, + { + "dl.tsd-member-summaries": [ + { + "dt.tsd-member-summary#tmxnode": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "../types/GH2982.TMXNode.json" + }, + "children": "TMXNode" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#tmxnode", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + } + ] + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": [ + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Interfaces" + }, + "children": "Interfaces" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#tmxdatanode" + }, + "children": { + "span": [ + "TMX", + { + "wbr": [] + }, + "Data", + { + "wbr": [] + }, + "Node" + ] + } + } + } + ] + }, + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Type Aliases" + }, + "children": "Type Aliases" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#tmxnode" + }, + "children": { + "span": [ + "TMX", + { + "wbr": [] + }, + "Node" + ] + } + } + } + ] + } + ] + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/types/GH2982.TMXNode.json b/src/test/renderer/specs/types/GH2982.TMXNode.json new file mode 100644 index 000000000..31febec59 --- /dev/null +++ b/src/test/renderer/specs/types/GH2982.TMXNode.json @@ -0,0 +1,120 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": [ + { + "li": { + "tag": "a", + "props": { + "href": "../modules/GH2982.json" + }, + "children": "GH2982" + } + }, + { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "TMXNode" + } + } + ] + }, + { + "h1": "Type Alias TMXNode" + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-kind-type-alias": "TMXNode" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-symbol": "{}" + }, + " ", + { + "span.tsd-signature-symbol": "&" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + " ", + { + "span.tsd-kind-property": "base" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#t" + }, + "children": "T" + }, + " ", + { + "span.tsd-signature-symbol": "}" + } + ] + }, + { + "section.tsd-panel": [ + { + "h4": "Type Parameters" + }, + { + "ul.tsd-type-parameter-list": { + "li": { + "span#t": { + "span.tsd-kind-type-parameter": "T" + } + } + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh2982.ts" + }, + "children": "gh2982.ts:1" + } + ] + } + } + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": [] + } + } + ] +} From 344f74ce459f7efb7888403937035abb3fcfe866 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 1 Aug 2025 09:55:10 -0600 Subject: [PATCH 06/46] Bump version to 0.28.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a49c7b42..98b45fece 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.8", + "version": "0.28.9", "homepage": "https://typedoc.org", "type": "module", "exports": { From e764a51f4b3ed35cd488eccd09498312d9502608 Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Fri, 1 Aug 2025 15:55:59 +0000 Subject: [PATCH 07/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49ed1e43d..5a01b1d6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.9 (2025-08-01) + ### Features - Add support for TypeScript 5.9, #2989. From 7bdb05f7eb7cec6f809012831b16b54ba85f1220 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 9 Aug 2025 10:00:03 -0600 Subject: [PATCH 08/46] Fix inconsistent anchors for aliases Resolves #2990 --- CHANGELOG.md | 4 + scripts/rebuild_specs.js | 1 + .../default/partials/moduleReflection.tsx | 2 +- src/test/converter2/renderer/index.ts | 1 + .../specs/interfaces/GH2982.TMXDataNode.json | 2 +- src/test/renderer/specs/modules.json | 82 +++++++++++++++++++ 6 files changed, 90 insertions(+), 2 deletions(-) mode change 100644 => 100755 scripts/rebuild_specs.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a01b1d6d..1d2515f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ title: Changelog ## Unreleased +### Bug Fixes + +- Fixed inconsistent anchors on module pages for re-exports, #2990. + ## v0.28.9 (2025-08-01) ### Features diff --git a/scripts/rebuild_specs.js b/scripts/rebuild_specs.js old mode 100644 new mode 100755 index cbdcba2dc..dd333c4a7 --- a/scripts/rebuild_specs.js +++ b/scripts/rebuild_specs.js @@ -1,3 +1,4 @@ +#!/usr/bin/env node // @ts-check "use strict"; diff --git a/src/lib/output/themes/default/partials/moduleReflection.tsx b/src/lib/output/themes/default/partials/moduleReflection.tsx index fb358841b..31418441d 100644 --- a/src/lib/output/themes/default/partials/moduleReflection.tsx +++ b/src/lib/output/themes/default/partials/moduleReflection.tsx @@ -75,7 +75,7 @@ export function moduleMemberSummary( context: DefaultThemeRenderContext, member: DeclarationReflection | DocumentReflection, ) { - const id = context.slugger.slug(member.name); + const id = member.isReference() ? context.getAnchor(member)! : context.slugger.slug(member.name); context.page.pageHeadings.push({ link: `#${id}`, text: getDisplayName(member), diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 76142a6df..2dbb7e53d 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -136,3 +136,4 @@ export interface DisabledGroups { export * as ExpandType from "./expandType"; export * as GH2982 from "./gh2982"; +export { box as boxAlias }; diff --git a/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json index 59e5f0c17..82cb71b0b 100644 --- a/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json +++ b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json @@ -96,7 +96,7 @@ { "tag": "section.tsd-panel.tsd-hierarchy", "props": { - "data-refl": "122" + "data-refl": "123" }, "children": [ { diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index e56b3d3d5..5a189196d 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -516,6 +516,56 @@ ] } ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-References" + }, + "children": { + "h2": "References" + } + }, + { + "dl.tsd-member-summaries": [ + { + "dt.tsd-member-summary#boxalias": { + "span.tsd-member-summary-name": [ + { + "span": "boxAlias" + }, + { + "span": " → " + }, + { + "tag": "a", + "props": { + "href": "functions/box.json" + }, + "children": "box" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#boxalias", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + } + ] + } + ] } ] }, @@ -855,6 +905,38 @@ } } ] + }, + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-References" + }, + "children": "References" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#boxalias" + }, + "children": { + "span": [ + "box", + { + "wbr": [] + }, + "Alias" + ] + } + } + } + ] } ] } From 2118cc256ca0487cd9ce6a5d9e55b3f34b3f572d Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 9 Aug 2025 10:00:27 -0600 Subject: [PATCH 09/46] Avoid non-breaking spaces in renderer specs --- .../specs/interfaces/BaseInterface.json | 4 ++-- .../specs/interfaces/DisabledGroups.json | 4 ++-- .../ExpandType.ExpandedByDefault.json | 2 +- .../specs/interfaces/GH2982.TMXDataNode.json | 2 +- .../specs/interfaces/NoneCategory.json | 6 +++--- .../renderer/specs/interfaces/NoneGroup.json | 4 ++-- src/test/renderer/specs/modules.json | 2 +- .../specs/types/ExpandType.AExpanded.json | 6 +++--- .../specs/types/ExpandType.BExpanded.json | 6 +++--- .../specs/types/ExpandType.Expandable.json | 2 +- .../specs/types/ExpandType.Expandable2.json | 2 +- .../ExpandType.NestedBehavior1.AExpanded.json | 6 +++--- ...xpandType.NestedBehavior1.AllExpanded.json | 6 +++--- src/test/renderer/specs/types/Nested.json | 20 +++++++++---------- src/test/renderer/testRendererUtils.ts | 2 +- 15 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/test/renderer/specs/interfaces/BaseInterface.json b/src/test/renderer/specs/interfaces/BaseInterface.json index 46980afe2..9ccfa435d 100644 --- a/src/test/renderer/specs/interfaces/BaseInterface.json +++ b/src/test/renderer/specs/interfaces/BaseInterface.json @@ -41,7 +41,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-call-signature", "props": { @@ -65,7 +65,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-call-signature", "props": { diff --git a/src/test/renderer/specs/interfaces/DisabledGroups.json b/src/test/renderer/specs/interfaces/DisabledGroups.json index 90d525305..14e3d537a 100644 --- a/src/test/renderer/specs/interfaces/DisabledGroups.json +++ b/src/test/renderer/specs/interfaces/DisabledGroups.json @@ -41,7 +41,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -62,7 +62,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-call-signature", "props": { diff --git a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json index 4df2574ad..a0a0fbe17 100644 --- a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json +++ b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json @@ -52,7 +52,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json index 82cb71b0b..4a14d5c79 100644 --- a/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json +++ b/src/test/renderer/specs/interfaces/GH2982.TMXDataNode.json @@ -52,7 +52,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/interfaces/NoneCategory.json b/src/test/renderer/specs/interfaces/NoneCategory.json index f13e3d383..24d919665 100644 --- a/src/test/renderer/specs/interfaces/NoneCategory.json +++ b/src/test/renderer/specs/interfaces/NoneCategory.json @@ -41,7 +41,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -62,7 +62,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -83,7 +83,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/interfaces/NoneGroup.json b/src/test/renderer/specs/interfaces/NoneGroup.json index 8970f3e31..fdca9ae0d 100644 --- a/src/test/renderer/specs/interfaces/NoneGroup.json +++ b/src/test/renderer/specs/interfaces/NoneGroup.json @@ -41,7 +41,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -62,7 +62,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index 5a189196d..cc6e97839 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -541,7 +541,7 @@ "span": "boxAlias" }, { - "span": " → " + "span": " → " }, { "tag": "a", diff --git a/src/test/renderer/specs/types/ExpandType.AExpanded.json b/src/test/renderer/specs/types/ExpandType.AExpanded.json index 8b3b95b61..3fd838168 100644 --- a/src/test/renderer/specs/types/ExpandType.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.AExpanded.json @@ -61,7 +61,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -86,7 +86,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -111,7 +111,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.BExpanded.json b/src/test/renderer/specs/types/ExpandType.BExpanded.json index e8eff5cf4..2865052ec 100644 --- a/src/test/renderer/specs/types/ExpandType.BExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.BExpanded.json @@ -56,7 +56,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -81,7 +81,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -106,7 +106,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.Expandable.json b/src/test/renderer/specs/types/ExpandType.Expandable.json index be39fc09a..89de6658c 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable.json @@ -56,7 +56,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.Expandable2.json b/src/test/renderer/specs/types/ExpandType.Expandable2.json index 1660b2262..efcacd043 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable2.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable2.json @@ -56,7 +56,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json index 678a54354..6ecd11223 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json @@ -70,7 +70,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -95,7 +95,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -120,7 +120,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json index 69dd59a7a..70b147fe8 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json @@ -65,7 +65,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -90,7 +90,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -115,7 +115,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { diff --git a/src/test/renderer/specs/types/Nested.json b/src/test/renderer/specs/types/Nested.json index add5b69d4..cef1f3e4d 100644 --- a/src/test/renderer/specs/types/Nested.json +++ b/src/test/renderer/specs/types/Nested.json @@ -55,7 +55,7 @@ { "br": [] }, - "    ", + " ", { "tag": "a.tsd-kind-property", "props": { @@ -73,7 +73,7 @@ { "br": [] }, - "        ", + " ", { "span.tsd-kind-property": "anotherValue" }, @@ -90,7 +90,7 @@ { "br": [] }, - "        ", + " ", { "span.tsd-kind-property": "emptyObject" }, @@ -107,7 +107,7 @@ { "br": [] }, - "        ", + " ", { "span.tsd-kind-property": "moreOptions" }, @@ -139,7 +139,7 @@ { "br": [] }, - "        ", + " ", { "span.tsd-kind-property": "value" }, @@ -156,7 +156,7 @@ { "br": [] }, - "    ", + " ", { "span.tsd-signature-symbol": "}" }, @@ -274,7 +274,7 @@ { "br": [] }, - "    ", + " ", { "span.tsd-kind-property": "anotherValue" }, @@ -291,7 +291,7 @@ { "br": [] }, - "    ", + " ", { "span.tsd-kind-property": "emptyObject" }, @@ -308,7 +308,7 @@ { "br": [] }, - "    ", + " ", { "span.tsd-kind-property": "moreOptions" }, @@ -340,7 +340,7 @@ { "br": [] }, - "    ", + " ", { "span.tsd-kind-property": "value" }, diff --git a/src/test/renderer/testRendererUtils.ts b/src/test/renderer/testRendererUtils.ts index 1ecdd812f..544e441a7 100644 --- a/src/test/renderer/testRendererUtils.ts +++ b/src/test/renderer/testRendererUtils.ts @@ -48,7 +48,7 @@ function collapseStrings(data: any[]): unknown { function renderElementToSnapshot(element: JsxChildren): unknown { if (typeof element === "string" || typeof element === "number" || typeof element === "bigint") { - return element.toString(); + return element.toString().replaceAll("\u00a0", " "); } if (!element || typeof element === "boolean") { From b0065957eea88187744e3cd3493d9b020ddc1409 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 9 Aug 2025 15:14:45 -0600 Subject: [PATCH 10/46] Do not parse markdown footnotes as references Resolves #2991 --- CHANGELOG.md | 1 + src/lib/converter/comments/textParser.ts | 8 +++++++- src/test/comments.test.ts | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d2515f89..a16013601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ title: Changelog ### Bug Fixes - Fixed inconsistent anchors on module pages for re-exports, #2990. +- Markdown references which appear to be footnotes will no longer be checked for links, #2991. ## v0.28.9 (2025-08-01) diff --git a/src/lib/converter/comments/textParser.ts b/src/lib/converter/comments/textParser.ts index 2289aaa22..4078b7aef 100644 --- a/src/lib/converter/comments/textParser.ts +++ b/src/lib/converter/comments/textParser.ts @@ -258,7 +258,13 @@ function checkReference(data: TextParserData): RelativeLink | undefined { while (/[ \t]/.test(token.text[lookahead])) { ++lookahead; } - if (token.text[lookahead] === "[") { + // #2991, we check that this reference also doesn't look like a footnote reference + // as it is unlikely that someone uses that syntax without intending for footnote behavior. + // This introduces a problem if someone has an [^ref] and doesn't intend for that to + // be interpreted as a footnote, but as a reference, but we can't have it both ways, + // and having people rename their reference to not be confused with a footnote isn't a + // horrible workaround. + if (token.text[lookahead] === "[" && token.text[lookahead + 1] !== "^") { while ( lookahead < token.text.length && /[^\n\]]/.test(token.text[lookahead]) diff --git a/src/test/comments.test.ts b/src/test/comments.test.ts index d44ab06e8..352cdba30 100644 --- a/src/test/comments.test.ts +++ b/src/test/comments.test.ts @@ -1558,6 +1558,7 @@ describe("Comment Parser", () => { * [2]:<./example with space> * [3]: https://example.com * [4]: #hash + * [^footnote]: ./example.md */`); equal( @@ -1579,7 +1580,7 @@ describe("Comment Parser", () => { }, { kind: "text", - text: "\n[3]: https://example.com\n[4]: #hash", + text: "\n[3]: https://example.com\n[4]: #hash\n[^footnote]: ./example.md", }, ] satisfies CommentDisplayPart[], ); From 192d1b53864f4c21df131398c6b9719d75329277 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 9 Aug 2025 16:27:09 -0600 Subject: [PATCH 11/46] Remove test cases which use module instead of namespace Preemptively resolving breakage that will come from https://github.com/microsoft/TypeScript/issues/62211 --- src/test/converter/class/class.ts | 2 +- src/test/converter/class/specs-with-lump-categories.json | 4 ++-- src/test/converter/class/specs.json | 4 ++-- src/test/converter/enum/enum.ts | 2 +- src/test/converter/enum/specs.json | 4 ++-- src/test/converter/enum/specs.nodoc.json | 4 ++-- src/test/converter/function/function.ts | 2 +- src/test/converter/function/specs.json | 4 ++-- src/test/converter/interface/interface-implementation.ts | 2 +- src/test/converter/interface/specs.json | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/test/converter/class/class.ts b/src/test/converter/class/class.ts index e46637b75..a1b693ce2 100644 --- a/src/test/converter/class/class.ts +++ b/src/test/converter/class/class.ts @@ -106,7 +106,7 @@ export interface TestSubClass { mergedMethod(); } -export module TestSubClass { +export namespace TestSubClass { /** * staticMergedMethod short text. */ diff --git a/src/test/converter/class/specs-with-lump-categories.json b/src/test/converter/class/specs-with-lump-categories.json index 96ab944f1..386ab2fe6 100644 --- a/src/test/converter/class/specs-with-lump-categories.json +++ b/src/test/converter/class/specs-with-lump-categories.json @@ -565,7 +565,7 @@ { "fileName": "class.ts", "line": 109, - "character": 14, + "character": 17, "url": "typedoc://class.ts#L109" } ] @@ -2239,7 +2239,7 @@ { "fileName": "class.ts", "line": 109, - "character": 14, + "character": 17, "url": "typedoc://class.ts#L109" } ], diff --git a/src/test/converter/class/specs.json b/src/test/converter/class/specs.json index 96ab944f1..386ab2fe6 100644 --- a/src/test/converter/class/specs.json +++ b/src/test/converter/class/specs.json @@ -565,7 +565,7 @@ { "fileName": "class.ts", "line": 109, - "character": 14, + "character": 17, "url": "typedoc://class.ts#L109" } ] @@ -2239,7 +2239,7 @@ { "fileName": "class.ts", "line": 109, - "character": 14, + "character": 17, "url": "typedoc://class.ts#L109" } ], diff --git a/src/test/converter/enum/enum.ts b/src/test/converter/enum/enum.ts index 5152f41ff..394ee4a47 100644 --- a/src/test/converter/enum/enum.ts +++ b/src/test/converter/enum/enum.ts @@ -41,7 +41,7 @@ export enum ModuleEnum { /** * This is a module extending an enumeration. */ -export module ModuleEnum { +export namespace ModuleEnum { /** * This is a variable appended to an enumeration. */ diff --git a/src/test/converter/enum/specs.json b/src/test/converter/enum/specs.json index d59f01d7e..144d9a4ff 100644 --- a/src/test/converter/enum/specs.json +++ b/src/test/converter/enum/specs.json @@ -117,7 +117,7 @@ { "fileName": "enum.ts", "line": 44, - "character": 14, + "character": 17, "url": "typedoc://enum.ts#L44" } ] @@ -313,7 +313,7 @@ { "fileName": "enum.ts", "line": 44, - "character": 14, + "character": 17, "url": "typedoc://enum.ts#L44" } ] diff --git a/src/test/converter/enum/specs.nodoc.json b/src/test/converter/enum/specs.nodoc.json index d59f01d7e..144d9a4ff 100644 --- a/src/test/converter/enum/specs.nodoc.json +++ b/src/test/converter/enum/specs.nodoc.json @@ -117,7 +117,7 @@ { "fileName": "enum.ts", "line": 44, - "character": 14, + "character": 17, "url": "typedoc://enum.ts#L44" } ] @@ -313,7 +313,7 @@ { "fileName": "enum.ts", "line": 44, - "character": 14, + "character": 17, "url": "typedoc://enum.ts#L44" } ] diff --git a/src/test/converter/function/function.ts b/src/test/converter/function/function.ts index f90d3c5af..077a9a6f7 100644 --- a/src/test/converter/function/function.ts +++ b/src/test/converter/function/function.ts @@ -161,7 +161,7 @@ export function isNonNull(arg: T | null | undefined): arg is T { /** * This is the module extending the function moduleFunction(). */ -export module moduleFunction { +export namespace moduleFunction { /** * This variable is appended to a function. */ diff --git a/src/test/converter/function/specs.json b/src/test/converter/function/specs.json index eb4d6085a..8b391258c 100644 --- a/src/test/converter/function/specs.json +++ b/src/test/converter/function/specs.json @@ -169,7 +169,7 @@ { "fileName": "function.ts", "line": 164, - "character": 14, + "character": 17, "url": "typedoc://function.ts#L164" } ] @@ -1680,7 +1680,7 @@ { "fileName": "function.ts", "line": 164, - "character": 14, + "character": 17, "url": "typedoc://function.ts#L164" } ], diff --git a/src/test/converter/interface/interface-implementation.ts b/src/test/converter/interface/interface-implementation.ts index df9f78650..aefd892fb 100644 --- a/src/test/converter/interface/interface-implementation.ts +++ b/src/test/converter/interface/interface-implementation.ts @@ -1,4 +1,4 @@ -export module Forms { +export namespace Forms { /** * Function signature of an event listener callback */ diff --git a/src/test/converter/interface/specs.json b/src/test/converter/interface/specs.json index 5ca0c0914..c554d89a9 100644 --- a/src/test/converter/interface/specs.json +++ b/src/test/converter/interface/specs.json @@ -2235,7 +2235,7 @@ { "fileName": "interface-implementation.ts", "line": 1, - "character": 14, + "character": 17, "url": "typedoc://interface-implementation.ts#L1" } ] From 1f917bf0fd50dde23796501f939716d33a0d844c Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 10 Aug 2025 12:05:49 -0600 Subject: [PATCH 12/46] Clear comment cache between conversions --- src/lib/converter/converter.ts | 6 +++++- src/lib/models/ProjectReflection.ts | 17 ++++++++++++++++- src/test/programs.ts | 2 -- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 5e6b43615..296d2c0cb 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -36,7 +36,7 @@ import { unique, } from "#utils"; import type { DocumentationEntryPoint } from "../utils/entry-point.js"; -import type { CommentParserConfig } from "./comments/index.js"; +import { clearCommentCache, type CommentParserConfig } from "./comments/index.js"; import type { CommentStyle, ValidationOptions } from "../utils/options/declaration.js"; import { parseCommentString } from "./comments/parser.js"; import { lexCommentString } from "./comments/rawLexer.js"; @@ -343,6 +343,10 @@ export class Converter extends AbstractComponent { delete this.excludeCache; delete this.externalPatternCache; + // Also clear the comment cache so if we convert this ts.Program again + // later we will re-parse comments. + clearCommentCache(); + return project; } diff --git a/src/lib/models/ProjectReflection.ts b/src/lib/models/ProjectReflection.ts index 4a6ebaa0a..bc9fd66a5 100644 --- a/src/lib/models/ProjectReflection.ts +++ b/src/lib/models/ProjectReflection.ts @@ -10,7 +10,15 @@ import { ReflectionKind } from "./kind.js"; import { Comment, type CommentDisplayPart } from "./Comment.js"; import { ReflectionSymbolId } from "./ReflectionSymbolId.js"; import type { Deserializer, JSONOutput, Serializer } from "#serialization"; -import { assertNever, DefaultMap, i18n, type NormalizedPath, removeIfPresent, StableKeyMap } from "#utils"; +import { + assertNever, + DefaultMap, + i18n, + NonEnumerable, + type NormalizedPath, + removeIfPresent, + StableKeyMap, +} from "#utils"; import type { DocumentReflection } from "./DocumentReflection.js"; import type { FileRegistry } from "./FileRegistry.js"; @@ -28,18 +36,24 @@ export class ProjectReflection extends ContainerReflection { readonly variant = "project"; // Used to resolve references. + @NonEnumerable private symbolToReflectionIdMap: Map< ReflectionSymbolId, number | number[] > = new StableKeyMap(); + @NonEnumerable private reflectionIdToSymbolIdMap = new Map(); + @NonEnumerable private removedSymbolIds = new StableKeyMap(); // Maps a reflection ID to all references eventually referring to it. + @NonEnumerable private referenceGraph?: Map; + // Maps a reflection ID to all reflections with it as their parent. + @NonEnumerable private reflectionChildren = new DefaultMap(() => []); /** @@ -49,6 +63,7 @@ export class ProjectReflection extends ContainerReflection { * * This may be replaced with a `Map` someday. */ + @NonEnumerable reflections: { [id: number]: Reflection } = {}; /** diff --git a/src/test/programs.ts b/src/test/programs.ts index c63b42f26..394f6a1d7 100644 --- a/src/test/programs.ts +++ b/src/test/programs.ts @@ -13,7 +13,6 @@ import { import type { ModelToObject } from "../lib/serialization/schema.js"; import { createAppForTesting } from "../lib/application.js"; import { existsSync } from "fs"; -import { clearCommentCache } from "../lib/converter/comments/index.js"; import { diagnostics } from "../lib/utils/loggers.js"; import { normalizePath, readFile, ValidatingFileRegistry } from "#node-utils"; @@ -175,7 +174,6 @@ export function getConverter2Project(entries: string[], folder: string) { app.options.setValue("entryPoints", entryPoints); app.files = new ValidatingFileRegistry(); - clearCommentCache(); return app.converter.convert( files.map((file, index) => { return { From 4a01cd2ecc573c4c2c33aa4aceb64ce023bb9f95 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 10 Aug 2025 12:13:53 -0600 Subject: [PATCH 13/46] Bump version to 0.28.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98b45fece..2725280d5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.9", + "version": "0.28.10", "homepage": "https://typedoc.org", "type": "module", "exports": { From 0489e32d54e52eee329719bea347d9360e2db69d Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Sun, 10 Aug 2025 18:14:40 +0000 Subject: [PATCH 14/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a16013601..5d93ff70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.10 (2025-08-10) + ### Bug Fixes - Fixed inconsistent anchors on module pages for re-exports, #2990. From 708e77d8a0a622488bc25701142e6681ac8c6877 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 10 Aug 2025 20:27:36 -0600 Subject: [PATCH 15/46] Fix TS link resolution in first comment of file Resolves #2994 --- CHANGELOG.md | 4 ++++ src/lib/converter/comments/discovery.ts | 8 ++------ src/lib/types/ts-internal/index.d.ts | 14 -------------- src/test/converter2/issues/gh2994.d.ts | 13 +++++++++++++ src/test/issues.c2.test.ts | 8 +++++++- 5 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 src/test/converter2/issues/gh2994.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d93ff70e..a534c381a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ title: Changelog ## Unreleased +### Bug Fixes + +- Fixed link resolution not working correctly in first comment on the file in some cases, #2994. + ## v0.28.10 (2025-08-10) ### Bug Fixes diff --git a/src/lib/converter/comments/discovery.ts b/src/lib/converter/comments/discovery.ts index 9ef7fd5ea..2761125e1 100644 --- a/src/lib/converter/comments/discovery.ts +++ b/src/lib/converter/comments/discovery.ts @@ -357,15 +357,11 @@ function findJsDocForComment( if (ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) { const jsDocs = ts .getJSDocCommentsAndTags(node) - .map((doc) => ts.findAncestor(doc, ts.isJSDoc)) as ts.JSDoc[]; + .map((doc) => ts.findAncestor(doc, ts.isJSDoc)!); if (ts.isSourceFile(node)) { if (node.statements.length) { - jsDocs.push( - ...(ts - .getJSDocCommentsAndTags(node.statements[0]) - .map((doc) => ts.findAncestor(doc, ts.isJSDoc)) as ts.JSDoc[]), - ); + jsDocs.push(...node.statements[0].getChildren().filter(ts.isJSDoc)); } } diff --git a/src/lib/types/ts-internal/index.d.ts b/src/lib/types/ts-internal/index.d.ts index 9f10898d2..f9be4f771 100644 --- a/src/lib/types/ts-internal/index.d.ts +++ b/src/lib/types/ts-internal/index.d.ts @@ -23,22 +23,8 @@ declare module "typescript" { // https://github.com/microsoft/TypeScript/blob/v5.0.2/src/compiler/utilities.ts#L7432 export function getCheckFlags(symbol: ts.Symbol): CheckFlags; - // https://github.com/microsoft/TypeScript/blob/v5.0.2/src/compiler/utilities.ts#L4171 - export function getJSDocCommentsAndTags( - hostNode: Node, - noCache?: boolean, - ): readonly (JSDoc | JSDocTag)[]; - - export function getInterfaceBaseTypeNodes( - node: InterfaceDeclaration, - ): NodeArray | undefined; - export function getAllSuperTypeNodes(node: ts.Node): readonly ts.TypeNode[]; - export interface Signature { - thisParameter?: ts.Symbol; - } - // https://github.com/microsoft/TypeScript/blob/e213b2af3430bdc9cf5fbc76a8634d832e7aaaaa/src/compiler/types.ts#L5298-L5299 export interface UnionType { /* @internal */ diff --git a/src/test/converter2/issues/gh2994.d.ts b/src/test/converter2/issues/gh2994.d.ts new file mode 100644 index 000000000..9d4b50e16 --- /dev/null +++ b/src/test/converter2/issues/gh2994.d.ts @@ -0,0 +1,13 @@ +/** + * {@link x} <-- should be resolved with TS resolution + * @packageDocumentation + */ + +/** Required comment */ +import { x } from "gh2994"; + +export var y: 2; + +declare module "gh2994" { + var x: 1; +} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 4aaf6b6f0..d5fd02caa 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -17,7 +17,7 @@ import type { InlineTagDisplayPart } from "../lib/models/Comment.js"; import { getConverter2App, getConverter2Project } from "./programs.js"; import { TestLogger } from "./TestLogger.js"; import { equalKind, getComment, getLinks, getSigComment, query, querySig, reflToTree } from "./utils.js"; -import { DefaultTheme, KindRouter, PageEvent } from "../index.js"; +import { DefaultTheme, KindRouter, PageEvent, ReflectionSymbolId } from "../index.js"; const app = getConverter2App(); @@ -2144,4 +2144,10 @@ describe("Issue Tests", () => { equal(x.inheritedFrom?.reflection?.getFullName(), undefined); equal(x.inheritedFrom?.name, "Tricky.x"); }); + + it("#2994 uses TS link resolution in first comment of file", () => { + const project = convert(); + const link = project.comment?.summary.find(part => part.kind === "inline-tag"); + ok(link?.target instanceof ReflectionSymbolId); + }); }); From ef3a42e964b711760b571716646e61e5d008ac5f Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 16 Aug 2025 20:34:44 -0600 Subject: [PATCH 16/46] Convert compiler options before setting overrides Resolves #3000 --- .vscode/settings.json | 1 + CHANGELOG.md | 2 ++ src/lib/application.ts | 4 +-- src/lib/internationalization/locales/en.cts | 1 + src/lib/utils/entry-point.ts | 9 +++--- src/lib/utils/options/options.ts | 23 ++++++++++++--- src/test/converter2/issues/gh2631/crlf.md | 10 +++---- src/test/programs.ts | 4 +-- .../slow/internationalization-usage.test.ts | 5 ++-- src/test/utils/options/options.test.ts | 28 +++++++++++++++++++ .../utils/options/readers/tsconfig.test.ts | 2 +- 11 files changed, 69 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b305aa521..fb47a1c4a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,6 +66,7 @@ "Msys", "nodoc", "shiki", + "srcset", "tsbuildinfo", "tsdoc", "typedoc", diff --git a/CHANGELOG.md b/CHANGELOG.md index a534c381a..f7d38b248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ title: Changelog ### Bug Fixes - Fixed link resolution not working correctly in first comment on the file in some cases, #2994. +- The `compilerOptions` option now functions properly with non-boolean options, #3000. +- Configuration errors within the `compilerOptions` option are now handled gracefully, #3000. ## v0.28.10 (2025-08-10) diff --git a/src/lib/application.ts b/src/lib/application.ts index 68f3afb35..d3574b3e5 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -496,7 +496,7 @@ export class Application extends AbstractComponent< ); } - if (Object.keys(this.options.getCompilerOptions()).length === 0) { + if (Object.keys(this.options.getCompilerOptions(this.logger)).length === 0) { this.logger.warn(i18n.no_compiler_options_set()); } @@ -525,7 +525,7 @@ export class Application extends AbstractComponent< const host = ts.createWatchCompilerHost( tsconfigFile, - this.options.fixCompilerOptions({}), + this.options.fixCompilerOptions({}, this.logger), ts.sys, ts.createEmitAndSemanticDiagnosticsBuilderProgram, (d) => diagnostic(this.logger, d), diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index 703f37664..bf367d6b7 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -242,6 +242,7 @@ export = { options_file_0_does_not_exist: `The options file {0} does not exist`, failed_read_options_file_0: `Failed to parse {0}, ensure it exists and exports an object`, + failed_to_apply_compilerOptions_overrides_0: "Failed to apply compilerOptions overrides: {0}", // plugins invalid_plugin_0_missing_load_function: `Invalid structure in plugin {0}, no load function found`, diff --git a/src/lib/utils/entry-point.ts b/src/lib/utils/entry-point.ts index 0e1aca810..38511656c 100644 --- a/src/lib/utils/entry-point.ts +++ b/src/lib/utils/entry-point.ts @@ -344,7 +344,7 @@ export function getExpandedEntryPointsForPaths( options: Options, programs = getEntryPrograms(inputFiles, logger, options), ): DocumentationEntryPoint[] { - const compilerOptions = options.getCompilerOptions(); + const compilerOptions = options.getCompilerOptions(logger); const supportedFileRegex = compilerOptions.allowJs || compilerOptions.checkJs ? /\.([cm][tj]s|[tj]sx?)$/ : /\.([cm]ts|tsx?)$/; @@ -410,16 +410,16 @@ function getEntryPrograms( const rootProgram = noTsConfigFound ? ts.createProgram({ rootNames: inputFiles, - options: options.getCompilerOptions(), + options: options.getCompilerOptions(logger), }) : ts.createProgram({ rootNames: options.getFileNames(), - options: options.getCompilerOptions(), + options: options.getCompilerOptions(logger), projectReferences: options.getProjectReferences(), }); addInferredDeclarationMapPaths( - options.getCompilerOptions(), + options.getCompilerOptions(logger), options.getFileNames(), ); @@ -438,6 +438,7 @@ function getEntryPrograms( ts.createProgram({ options: options.fixCompilerOptions( ref.commandLine.options, + logger, ), rootNames: ref.commandLine.fileNames, projectReferences: ref.commandLine.projectReferences, diff --git a/src/lib/utils/options/options.ts b/src/lib/utils/options/options.ts index 49e0798d8..797cccb01 100644 --- a/src/lib/utils/options/options.ts +++ b/src/lib/utils/options/options.ts @@ -1,4 +1,4 @@ -import type ts from "typescript"; +import ts from "typescript"; import { resolve } from "path"; import { ParameterType } from "./declaration.js"; import type { OutputSpecification } from "../index.js"; @@ -361,19 +361,34 @@ export class Options { /** * Gets the set compiler options. */ - getCompilerOptions(): ts.CompilerOptions { - return this.fixCompilerOptions(this._compilerOptions); + getCompilerOptions(logger: Logger): ts.CompilerOptions { + return this.fixCompilerOptions(this._compilerOptions, logger); } /** @internal */ fixCompilerOptions( options: Readonly, + logger: Logger, ): ts.CompilerOptions { const overrides = this.getValue("compilerOptions"); const result = { ...options }; if (overrides) { - Object.assign(result, overrides); + const tsOptions = ts.convertCompilerOptionsFromJson(overrides, ".", "typedoc-overrides.json"); + + if (tsOptions.errors.length) { + for (const error of tsOptions.errors) { + logger.error( + i18n.failed_to_apply_compilerOptions_overrides_0( + ts.flattenDiagnosticMessageText(error.messageText, "\n"), + ), + ); + } + } else { + for (const key in overrides) { + result[key] = tsOptions.options[key]; + } + } } if (this.getValue("emit") !== "both") { diff --git a/src/test/converter2/issues/gh2631/crlf.md b/src/test/converter2/issues/gh2631/crlf.md index aa988a781..3d0cf7580 100644 --- a/src/test/converter2/issues/gh2631/crlf.md +++ b/src/test/converter2/issues/gh2631/crlf.md @@ -1,5 +1,5 @@ ---- -title: "Windows Line Endings" ---- - -This file contains CRLF line endings +--- +title: "Windows Line Endings" +--- + +This file contains CRLF line endings diff --git a/src/test/programs.ts b/src/test/programs.ts index 394f6a1d7..68b27b47c 100644 --- a/src/test/programs.ts +++ b/src/test/programs.ts @@ -96,7 +96,7 @@ export function getConverterProgram() { const app = getConverterApp(); converterProgram = ts.createProgram( app.options.getFileNames(), - app.options.getCompilerOptions(), + app.options.getCompilerOptions(app.logger), ); const errors = ts.getPreEmitDiagnostics(converterProgram); @@ -134,7 +134,7 @@ export function getConverter2Program() { const app = getConverter2App(); converter2Program = ts.createProgram( app.options.getFileNames(), - app.options.getCompilerOptions(), + app.options.getCompilerOptions(app.logger), ); const errors = ts.getPreEmitDiagnostics(converter2Program); diff --git a/src/test/slow/internationalization-usage.test.ts b/src/test/slow/internationalization-usage.test.ts index d1e4efd38..b669f03f2 100644 --- a/src/test/slow/internationalization-usage.test.ts +++ b/src/test/slow/internationalization-usage.test.ts @@ -9,7 +9,8 @@ describe("Internationalization", () => { it("Does not include strings in translatable object which are unused", () => { const options = new Options(); const tsconfigReader = new TSConfigReader(); - tsconfigReader.read(options, new Logger(), process.cwd()); + const logger = new Logger(); + tsconfigReader.read(options, logger, process.cwd()); const defaultLocaleTs = join( fileURLToPath(import.meta.url), @@ -26,7 +27,7 @@ describe("Internationalization", () => { ); }, getCurrentDirectory: () => process.cwd(), - getCompilationSettings: () => options.getCompilerOptions(), + getCompilationSettings: () => options.getCompilerOptions(logger), getDefaultLibFileName: (opts) => ts.getDefaultLibFilePath(opts), fileExists: ts.sys.fileExists, readFile: ts.sys.readFile, diff --git a/src/test/utils/options/options.test.ts b/src/test/utils/options/options.test.ts index f58134f57..3366d851d 100644 --- a/src/test/utils/options/options.test.ts +++ b/src/test/utils/options/options.test.ts @@ -3,6 +3,8 @@ import { type MapDeclarationOption, type NumberDeclarationOption, Option } from import { deepStrictEqual as equal, throws } from "assert"; import type { DeclarationOption, EmitStrategy } from "../../../lib/utils/options/index.js"; import { LogLevel } from "#utils"; +import { TestLogger } from "../../TestLogger.js"; +import ts from "typescript"; describe("Options", () => { let options: Options & { @@ -180,6 +182,32 @@ describe("Options", () => { throws(() => options.reset("thisOptionDoesNotExist" as never)); }); + + it("Handles tsconfig overrides which aren't strings, #3000", () => { + const logger = new TestLogger(); + const options = new Options(); + + options.setValue("compilerOptions", { + moduleResolution: "bundler", + }); + + const compilerOptions = options.getCompilerOptions(logger); + equal(compilerOptions.moduleResolution, ts.ModuleResolutionKind.Bundler); + }); + + it("Handles tsconfig overrides which are invalid, #3000", () => { + const logger = new TestLogger(); + const options = new Options(); + + options.setValue("compilerOptions", { + moduleResolution: "bad", + }); + + const compilerOptions = options.getCompilerOptions(logger); + equal(compilerOptions.moduleResolution, undefined); + + logger.expectMessage("error: Failed to apply compilerOptions overrides: *"); + }); }); describe("Option", () => { diff --git a/src/test/utils/options/readers/tsconfig.test.ts b/src/test/utils/options/readers/tsconfig.test.ts index 5bd666e81..f49cbe42d 100644 --- a/src/test/utils/options/readers/tsconfig.test.ts +++ b/src/test/utils/options/readers/tsconfig.test.ts @@ -162,7 +162,7 @@ describe("Options - TSConfigReader", () => { compilerOptions: { strict: true }, }); await readWithProject(project); - equal(options.getCompilerOptions().strict, true); + equal(options.getCompilerOptions(logger).strict, true); }); async function testTsdoc(tsdoc: object, cb?: () => void, reset = true) { From e5cd9d1946e8ef89f3b916689108fd8b488fe920 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 16 Aug 2025 21:10:11 -0600 Subject: [PATCH 17/46] Fix rendering of optional methods Resolves #2995 --- CHANGELOG.md | 1 + src/lib/output/formatter.tsx | 1 + src/test/converter2/renderer/gh2995.ts | 3 + src/test/converter2/renderer/index.ts | 1 + .../renderer/specs/interfaces/gh2995.json | 399 ++++++++++++++++++ src/test/renderer/specs/modules.json | 32 ++ 6 files changed, 437 insertions(+) create mode 100644 src/test/converter2/renderer/gh2995.ts create mode 100644 src/test/renderer/specs/interfaces/gh2995.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d38b248..d70528b85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ title: Changelog ### Bug Fixes - Fixed link resolution not working correctly in first comment on the file in some cases, #2994. +- Optional methods are now rendered with a trailing `?` in the reflection preview and signature, #2995. - The `compilerOptions` option now functions properly with non-boolean options, #3000. - Configuration errors within the `compilerOptions` option are now handled gracefully, #3000. diff --git a/src/lib/output/formatter.tsx b/src/lib/output/formatter.tsx index 8015cb002..ba2f874b1 100644 --- a/src/lib/output/formatter.tsx +++ b/src/lib/output/formatter.tsx @@ -961,6 +961,7 @@ export class FormattedCodeBuilder { const id = this.newId(); return group(id, [ name, + sig.parent.flags.isOptional ? simpleElement(?) : emptyNode, this.typeParameters(sig), ...this.parameters(sig, id), nodes( diff --git a/src/test/converter2/renderer/gh2995.ts b/src/test/converter2/renderer/gh2995.ts new file mode 100644 index 000000000..09f1a0e0d --- /dev/null +++ b/src/test/converter2/renderer/gh2995.ts @@ -0,0 +1,3 @@ +export interface gh2995 { + optionalMethod?(filter: string, args: string[]): any; +} diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 2dbb7e53d..5d8abb16f 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -136,4 +136,5 @@ export interface DisabledGroups { export * as ExpandType from "./expandType"; export * as GH2982 from "./gh2982"; +export { gh2995 } from "./gh2995"; export { box as boxAlias }; diff --git a/src/test/renderer/specs/interfaces/gh2995.json b/src/test/renderer/specs/interfaces/gh2995.json new file mode 100644 index 000000000..c4182b433 --- /dev/null +++ b/src/test/renderer/specs/interfaces/gh2995.json @@ -0,0 +1,399 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "gh2995" + } + } + }, + { + "h1": "Interface gh2995" + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-signature-keyword": "interface" + }, + " ", + { + "span.tsd-kind-interface": "gh2995" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + { + "br": [] + }, + " ", + { + "tag": "a.tsd-kind-call-signature", + "props": { + "href": "#optionalmethod-1" + }, + "children": "optionalMethod" + }, + { + "span.tsd-signature-symbol": "?" + }, + { + "span.tsd-signature-symbol": "(" + }, + { + "span.tsd-kind-parameter": "filter" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "string" + }, + { + "span.tsd-signature-symbol": "," + }, + " ", + { + "span.tsd-kind-parameter": "args" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "string" + }, + { + "span.tsd-signature-symbol": "[]" + }, + { + "span.tsd-signature-symbol": ")" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "any" + }, + { + "span.tsd-signature-symbol": ";" + }, + { + "br": [] + }, + { + "span.tsd-signature-symbol": "}" + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh2995.ts" + }, + "children": "gh2995.ts:1" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Methods" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link", + "props": { + "href": "#optionalmethod" + }, + "children": { + "span": [ + "optional", + { + "wbr": [] + }, + "Method?" + ] + } + }, + "\n" + ] + } + ] + } + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": { + "h2": "Methods" + } + }, + { + "section": { + "section.tsd-panel.tsd-member": [ + { + "h3.tsd-anchor-link#optionalmethod": [ + { + "code.tsd-tag": "Optional" + }, + { + "span": [ + "optional", + { + "wbr": [] + }, + "Method" + ] + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#optionalmethod", + "aria-label": "Permalink" + } + } + ] + }, + { + "ul.tsd-signatures": { + "li.": [ + { + "div.tsd-signature.tsd-anchor-link#optionalmethod-1": [ + { + "span.tsd-kind-call-signature": "optionalMethod" + }, + { + "span.tsd-signature-symbol": "?" + }, + { + "span.tsd-signature-symbol": "(" + }, + { + "span.tsd-kind-parameter": "filter" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "string" + }, + { + "span.tsd-signature-symbol": "," + }, + " ", + { + "span.tsd-kind-parameter": "args" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "string" + }, + { + "span.tsd-signature-symbol": "[]" + }, + { + "span.tsd-signature-symbol": ")" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "any" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#optionalmethod-1", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-description": [ + { + "div.tsd-parameters": [ + { + "h4.tsd-parameters-title": "Parameters" + }, + { + "ul.tsd-parameter-list": [ + { + "li": { + "span": [ + { + "span.tsd-kind-parameter": "filter" + }, + ": ", + { + "span.tsd-signature-type": "string" + } + ] + } + }, + { + "li": { + "span": [ + { + "span.tsd-kind-parameter": "args" + }, + ": ", + { + "span.tsd-signature-type": "string" + }, + { + "span.tsd-signature-symbol": "[]" + } + ] + } + } + ] + } + ] + }, + { + "h4.tsd-returns-title": [ + "Returns ", + { + "span.tsd-signature-type": "any" + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh2995.ts" + }, + "children": "gh2995.ts:2" + } + ] + } + } + } + ] + } + ] + } + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": "Methods" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#optionalmethod" + }, + "children": { + "span": [ + "optional", + { + "wbr": [] + }, + "Method" + ] + } + } + } + ] + } + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index cc6e97839..f3dad2abe 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -356,6 +356,29 @@ { "dd.tsd-member-summary": [] }, + { + "dt.tsd-member-summary#gh2995": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "interfaces/gh2995.json" + }, + "children": "gh2995" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#gh2995", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + }, { "dt.tsd-member-summary#nonecategory": { "span.tsd-member-summary-name": [ @@ -803,6 +826,15 @@ ] } }, + { + "tag": "a", + "props": { + "href": "#gh2995" + }, + "children": { + "span": "gh2995" + } + }, { "tag": "a", "props": { From 06a4239653e206d0a8676c58320f4c3f57735053 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 16 Aug 2025 22:09:40 -0600 Subject: [PATCH 18/46] Pick up shorthand property's variable comments Resolves #2999 --- CHANGELOG.md | 5 +++++ src/lib/converter/comments/discovery.ts | 16 ++++++++++++++++ src/test/converter2/issues/gh2999.ts | 10 ++++++++++ src/test/issues.c2.test.ts | 8 ++++++++ 4 files changed, 39 insertions(+) create mode 100644 src/test/converter2/issues/gh2999.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d70528b85..e7aabc3a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ title: Changelog ## Unreleased +### Features + +- Object properties declared with shorthand property assignment will now use the variable's comment + if they do not have their own comment, #2999. + ### Bug Fixes - Fixed link resolution not working correctly in first comment on the file in some cases, #2994. diff --git a/src/lib/converter/comments/discovery.ts b/src/lib/converter/comments/discovery.ts index 2761125e1..423d5aa99 100644 --- a/src/lib/converter/comments/discovery.ts +++ b/src/lib/converter/comments/discovery.ts @@ -525,6 +525,22 @@ function declarationToCommentNodes( }); } + // #2999 automatically pick up comments from the value symbol for shorthand assignments + if (ts.isShorthandPropertyAssignment(node)) { + const sourceSymbol = checker.getShorthandAssignmentValueSymbol(node); + if (sourceSymbol?.valueDeclaration) { + const commentNode = declarationToCommentNodeIgnoringParents(sourceSymbol.valueDeclaration); + if (commentNode) { + result.push( + { + node: commentNode, + inheritedFromParentDeclaration: true, + }, + ); + } + } + } + // With overloaded functions/methods, TypeScript will use the comment on the first signature // declaration if ( diff --git a/src/test/converter2/issues/gh2999.ts b/src/test/converter2/issues/gh2999.ts new file mode 100644 index 000000000..fabc7c768 --- /dev/null +++ b/src/test/converter2/issues/gh2999.ts @@ -0,0 +1,10 @@ +/** + * A test object with property a. + */ +const LocalObject = { + a: 1, +}; + +export const Options = { + LocalObject, +}; diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index d5fd02caa..496dbbeb9 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2150,4 +2150,12 @@ describe("Issue Tests", () => { const link = project.comment?.summary.find(part => part.kind === "inline-tag"); ok(link?.target instanceof ReflectionSymbolId); }); + + it("#2999 picks up parent comments from shorthand property assignments", () => { + const project = convert(); + const opts = query(project, "Options"); + equal(opts.type?.type, "reflection"); + const local = opts.type.declaration.getChildByName("LocalObject"); + equal(Comment.combineDisplayParts(local?.comment?.summary), "A test object with property a."); + }); }); From 8f47c24f17204a3e2b86b48e7f8ae6933f19ae77 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 24 Aug 2025 20:05:59 -0600 Subject: [PATCH 19/46] Fix rendering of "Type Declaration" header Ref: #3002 --- .npmrc | 3 ++ CHANGELOG.md | 1 + site/tags/primaryExport.md | 4 +- src/lib/internationalization/locales/en.cts | 2 +- .../default/partials/member.declaration.tsx | 47 ++++++++++--------- .../specs/types/ExpandType.AExpanded.json | 2 +- .../specs/types/ExpandType.BExpanded.json | 2 +- .../ExpandType.NestedBehavior1.AExpanded.json | 2 +- ...xpandType.NestedBehavior1.AllExpanded.json | 6 +-- src/test/renderer/specs/types/Nested.json | 2 +- .../renderer/specs/types/UnionComments.json | 2 +- 11 files changed, 40 insertions(+), 33 deletions(-) diff --git a/.npmrc b/.npmrc index 38a20c41b..ce1fd3424 100644 --- a/.npmrc +++ b/.npmrc @@ -6,3 +6,6 @@ audit = false # While we're on the TS beta, need this flag. legacy-peer-deps = true + +# This breaks some of the scripts in the scripts directory +update-notifier = false diff --git a/CHANGELOG.md b/CHANGELOG.md index e7aabc3a1..304366829 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ title: Changelog - Optional methods are now rendered with a trailing `?` in the reflection preview and signature, #2995. - The `compilerOptions` option now functions properly with non-boolean options, #3000. - Configuration errors within the `compilerOptions` option are now handled gracefully, #3000. +- Fixed improper casing of "Type Declaration" header, #3002. ## v0.28.10 (2025-08-10) diff --git a/site/tags/primaryExport.md b/site/tags/primaryExport.md index ab3533632..c1a5b13f4 100644 --- a/site/tags/primaryExport.md +++ b/site/tags/primaryExport.md @@ -1,8 +1,8 @@ --- -title: "@primaryModifier" +title: "@primaryExport" --- -# @primaryModifier +# @primaryExport **Tag Kind:** [Modifier](../tags.md#modifier-tags) diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index bf367d6b7..dd83dca43 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -506,7 +506,7 @@ export = { // Page headings/labels theme_implements: "Implements", theme_indexable: "Indexable", - theme_type_declaration: "Type declaration", + theme_type_declaration: "Type Declaration", theme_index: "Index", theme_hierarchy: "Hierarchy", theme_hierarchy_summary: "Hierarchy Summary", diff --git a/src/lib/output/themes/default/partials/member.declaration.tsx b/src/lib/output/themes/default/partials/member.declaration.tsx index 4086ebcb8..e304723d2 100644 --- a/src/lib/output/themes/default/partials/member.declaration.tsx +++ b/src/lib/output/themes/default/partials/member.declaration.tsx @@ -1,9 +1,28 @@ -import type { DeclarationReflection } from "../../../../models/index.js"; +import type { DeclarationReflection } from "#models"; import { JSX } from "#utils"; import { FormattedCodeBuilder, FormattedCodeGenerator, type FormatterNode, Wrap } from "../../../formatter.js"; import { hasTypeParameters } from "../../lib.js"; import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext.js"; +function shouldRenderDefaultValue(props: DeclarationReflection) { + const defaultValue = props.defaultValue; + + if (defaultValue === undefined) { + return false; + } + + /** Fix for #2717. If type is the same as value the default value is omitted */ + if (props.type && props.type.type === "literal") { + const reflectionTypeString = props.type.toString(); + + if (reflectionTypeString === defaultValue.toString()) { + return false; + } + } + + return true; +} + export function memberDeclaration(context: DefaultThemeRenderContext, props: DeclarationReflection) { const builder = new FormattedCodeBuilder(context.router, context.model); const content: FormatterNode[] = []; @@ -11,31 +30,15 @@ export function memberDeclaration(context: DefaultThemeRenderContext, props: Dec const generator = new FormattedCodeGenerator(context.options.getValue("typePrintWidth")); generator.node({ type: "nodes", content }, Wrap.Detect); - /** Fix for #2717. If type is the same as value the default value is omitted */ - function shouldRenderDefaultValue() { - if (props.type && props.type.type === "literal") { - const reflectionTypeString = props.type.toString(); - - const defaultValue = props.defaultValue; - - if (defaultValue === undefined || reflectionTypeString === defaultValue.toString()) { - return false; - } - } - return true; - } - return ( <>
{generator.toElement()} - {!!props.defaultValue && shouldRenderDefaultValue() && ( - <> - - {" = "} - {props.defaultValue} - - + {shouldRenderDefaultValue(props) && ( + + {" = "} + {props.defaultValue} + )}
diff --git a/src/test/renderer/specs/types/ExpandType.AExpanded.json b/src/test/renderer/specs/types/ExpandType.AExpanded.json index 3fd838168..fa0d5b018 100644 --- a/src/test/renderer/specs/types/ExpandType.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.AExpanded.json @@ -271,7 +271,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { diff --git a/src/test/renderer/specs/types/ExpandType.BExpanded.json b/src/test/renderer/specs/types/ExpandType.BExpanded.json index 2865052ec..232327a24 100644 --- a/src/test/renderer/specs/types/ExpandType.BExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.BExpanded.json @@ -318,7 +318,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json index 6ecd11223..922d86eae 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json @@ -332,7 +332,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json index 70b147fe8..bcb57d04b 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json @@ -275,7 +275,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { @@ -359,7 +359,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { @@ -443,7 +443,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": { diff --git a/src/test/renderer/specs/types/Nested.json b/src/test/renderer/specs/types/Nested.json index cef1f3e4d..5778fa04a 100644 --- a/src/test/renderer/specs/types/Nested.json +++ b/src/test/renderer/specs/types/Nested.json @@ -365,7 +365,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul.tsd-parameters": [ diff --git a/src/test/renderer/specs/types/UnionComments.json b/src/test/renderer/specs/types/UnionComments.json index f338513ee..06e4ab4f0 100644 --- a/src/test/renderer/specs/types/UnionComments.json +++ b/src/test/renderer/specs/types/UnionComments.json @@ -50,7 +50,7 @@ { "div.tsd-type-declaration": [ { - "h4": "Type declaration" + "h4": "Type Declaration" }, { "ul": [ From 2077c80cbbce1260fe30d75f62d841fb84eaecc8 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 24 Aug 2025 21:12:46 -0600 Subject: [PATCH 20/46] Bump version to 0.28.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2725280d5..d95921ac6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.10", + "version": "0.28.11", "homepage": "https://typedoc.org", "type": "module", "exports": { From 17347c9af22d2bbf322e3c8eaa92eae10a6f7690 Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Mon, 25 Aug 2025 03:13:42 +0000 Subject: [PATCH 21/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 304366829..fe48fd9b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.11 (2025-08-25) + ### Features - Object properties declared with shorthand property assignment will now use the variable's comment From 34d2c33975e6f01c766aa9a41f219027c233c24c Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 18:10:32 -0600 Subject: [PATCH 22/46] Fix #3003 --- CHANGELOG.md | 5 +++++ src/lib/converter/comments/discovery.ts | 15 +++++++++++++++ src/lib/converter/symbols.ts | 12 +++++++++++- src/lib/internationalization/locales/en.cts | 2 ++ src/test/converter2/issues/gh3003/enums.ts | 9 +++++++++ src/test/converter2/issues/gh3003/index.ts | 17 +++++++++++++++++ src/test/issues.c2.test.ts | 13 +++++++++++++ src/test/utils.ts | 2 +- 8 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/test/converter2/issues/gh3003/enums.ts create mode 100644 src/test/converter2/issues/gh3003/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fe48fd9b6..2f8f9994a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ title: Changelog ## Unreleased +### Bug Fixes + +- Variables marked with `@enum` now work for symbols imported from another module, #3003. +- Improved magic introduced with #2999 to work with imported symbols, #3003. + ## v0.28.11 (2025-08-25) ### Features diff --git a/src/lib/converter/comments/discovery.ts b/src/lib/converter/comments/discovery.ts index 423d5aa99..719bf2c9e 100644 --- a/src/lib/converter/comments/discovery.ts +++ b/src/lib/converter/comments/discovery.ts @@ -4,6 +4,7 @@ import { CommentStyle } from "../../utils/options/declaration.js"; import { nicePath } from "../../utils/paths.js"; import { ok } from "assert"; import { assertNever, filter, firstDefined, i18n, type Logger } from "#utils"; +import { resolveAliasedSymbol } from "../utils/symbols.js"; const variablePropertyKinds = [ ts.SyntaxKind.PropertyDeclaration, @@ -539,6 +540,20 @@ function declarationToCommentNodes( ); } } + + // #3003 even more magic for handling an imported symbol which appears in a shorthand property assignment + const originalSymbol = sourceSymbol && resolveAliasedSymbol(sourceSymbol, checker); + if (originalSymbol !== sourceSymbol && originalSymbol?.valueDeclaration) { + const commentNode = declarationToCommentNodeIgnoringParents(originalSymbol?.valueDeclaration); + if (commentNode) { + result.push( + { + node: commentNode, + inheritedFromParentDeclaration: true, + }, + ); + } + } } // With overloaded functions/methods, TypeScript will use the comment on the first signature diff --git a/src/lib/converter/symbols.ts b/src/lib/converter/symbols.ts index 6ae22c7b9..7358e3e45 100644 --- a/src/lib/converter/symbols.ts +++ b/src/lib/converter/symbols.ts @@ -1133,7 +1133,17 @@ function convertVariableAsEnum( context.finalizeDeclarationReflection(reflection); const rc = context.withScope(reflection); - const declaration = symbol.declarations!.find(ts.isVariableDeclaration)!; + const declaration = symbol.valueDeclaration; + if (!declaration) { + context.logger.error( + i18n.converting_0_as_enum_requires_value_declaration( + symbol.name, + ), + symbol.declarations?.[0], + ); + return; + } + const type = context.checker.getTypeAtLocation(declaration); for (const prop of type.getProperties()) { diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index dd83dca43..301cbf806 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -51,6 +51,8 @@ export = { `Converting {0} as a class requires a declaration which represents a non-type value`, converting_0_as_class_without_construct_signatures: `{0} is being converted as a class, but does not have any construct signatures`, + converting_0_as_enum_requires_value_declaration: + `Converting {0} as an enum requires a declaration which represents a non-type value`, comment_for_0_should_not_contain_block_or_modifier_tags: `The comment for {0} should not contain any block or modifier tags`, diff --git a/src/test/converter2/issues/gh3003/enums.ts b/src/test/converter2/issues/gh3003/enums.ts new file mode 100644 index 000000000..32a4410ac --- /dev/null +++ b/src/test/converter2/issues/gh3003/enums.ts @@ -0,0 +1,9 @@ +/** + * This is a custom enum that is exported as a constant object. + * + * @enum + */ +export const CustomEnum = { + /** A */ + A: "A", +} as const; diff --git a/src/test/converter2/issues/gh3003/index.ts b/src/test/converter2/issues/gh3003/index.ts new file mode 100644 index 000000000..142ac290b --- /dev/null +++ b/src/test/converter2/issues/gh3003/index.ts @@ -0,0 +1,17 @@ +import { CustomEnum } from "./enums.js"; + +/** + * This is a second custom enum that is exported as a constant object. + * + * @enum + */ +const CustomEnum2 = { + ...CustomEnum, + D: "D", +} as const; + +/** @namespace */ +export const ExportedObject = { + CustomEnum, + CustomEnum2, +}; diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 496dbbeb9..c91e54fe7 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2158,4 +2158,17 @@ describe("Issue Tests", () => { const local = opts.type.declaration.getChildByName("LocalObject"); equal(Comment.combineDisplayParts(local?.comment?.summary), "A test object with property a."); }); + + it("#3003 handles @enum on properties within @namespace", () => { + const project = convert(); + + const a = query(project, "ExportedObject.CustomEnum"); + equalKind(a, ReflectionKind.Enum); + equal(a.children?.map(c => c.name), ["A"]); + equal(a.children?.map(c => c.type?.toString()), ['"A"']); + const b = query(project, "ExportedObject.CustomEnum2"); + equalKind(b, ReflectionKind.Enum); + equal(b.children?.map(c => c.name), ["A", "D"]); + equal(b.children?.map(c => c.type?.toString()), ['"A"', '"D"']); + }); }); diff --git a/src/test/utils.ts b/src/test/utils.ts index 409e65795..1830ef414 100644 --- a/src/test/utils.ts +++ b/src/test/utils.ts @@ -108,7 +108,7 @@ export function equalKind(refl: Reflection, kind: ReflectionKind) { equal( refl.kind, kind, - `Expected ${ReflectionKind[kind]} but got ${ReflectionKind[refl.kind]}`, + `Expected ${ReflectionKind[kind]} but got ${ReflectionKind[refl.kind]} for ${refl.getFullName()}`, ); } From 51c7ff207732d0d2aa409577eae9e27321576456 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 19:49:46 -0600 Subject: [PATCH 23/46] Fix link resolution with percent encoded URLs Ref #3006 --- CHANGELOG.md | 1 + src/lib/converter/comments/textParser.ts | 20 +++++++++++-------- src/test/converter2/issues/gh3006/index.ts | 9 +++++++++ .../converter2/issues/gh3006/two words.md | 1 + src/test/issues.c2.test.ts | 11 ++++++++++ 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/test/converter2/issues/gh3006/index.ts create mode 100644 src/test/converter2/issues/gh3006/two words.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f8f9994a..d073f914b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ title: Changelog - Variables marked with `@enum` now work for symbols imported from another module, #3003. - Improved magic introduced with #2999 to work with imported symbols, #3003. +- Fixed relative link resolution to file names containing percent encoded URLs, #3006. ## v0.28.11 (2025-08-25) diff --git a/src/lib/converter/comments/textParser.ts b/src/lib/converter/comments/textParser.ts index 4078b7aef..e98f18fa9 100644 --- a/src/lib/converter/comments/textParser.ts +++ b/src/lib/converter/comments/textParser.ts @@ -223,10 +223,11 @@ function checkMarkdownLink( if (link.ok) { // Only make a relative-link display part if it's actually a relative link. // Discard protocol:// links, unix style absolute paths, and windows style absolute paths. - if (isRelativePath(link.str)) { + const decoded = decodeURI(link.str); + if (isRelativePath(decoded)) { const { target, anchor } = files.register( sourcePath, - link.str as NormalizedPath, + decoded as NormalizedPath, ) || { target: undefined, anchor: undefined }; return { pos: lookahead, @@ -284,10 +285,11 @@ function checkReference(data: TextParserData): RelativeLink | undefined { ); if (link.ok) { - if (isRelativePath(link.str)) { + const decoded = decodeURI(link.str); + if (isRelativePath(decoded)) { const { target, anchor } = files.register( sourcePath, - link.str as NormalizedPath, + decoded as NormalizedPath, ) || { target: undefined, anchor: undefined }; return { pos: lookahead, @@ -377,10 +379,11 @@ function checkAttributeDirectPath( pos: number, end: number, ): RelativeLink[] { - if (isRelativePath(text.trim())) { + const decoded = decodeURI(text.trim()); + if (isRelativePath(decoded)) { const { target, anchor } = data.files.register( data.sourcePath, - text.trim() as NormalizedPath, + decoded as NormalizedPath, ) || { target: undefined, anchor: undefined }; return [{ pos, @@ -413,11 +416,12 @@ function checkAttributeSrcSet(data: TextParserData, text: string, pos: number, _ // TypeDoc: We don't exactly match this, PR welcome! For now, just permit anything // that's not whitespace or a comma const url = text.slice(textPos).match(/^[^\t\r\f\n ,]+/); + const decoded = url && decodeURI(url[0]); - if (url && isRelativePath(url[0])) { + if (decoded && isRelativePath(decoded)) { const { target, anchor } = data.files.register( data.sourcePath, - url[0] as NormalizedPath, + decoded as NormalizedPath, ) || { target: undefined, anchor: undefined }; result.push({ pos: pos + textPos, diff --git a/src/test/converter2/issues/gh3006/index.ts b/src/test/converter2/issues/gh3006/index.ts new file mode 100644 index 000000000..990e7896a --- /dev/null +++ b/src/test/converter2/issues/gh3006/index.ts @@ -0,0 +1,9 @@ +/** + * @document two words.md + * @module + */ + +/** + * [link](./two%20words.md) + */ +export const x = 1; diff --git a/src/test/converter2/issues/gh3006/two words.md b/src/test/converter2/issues/gh3006/two words.md new file mode 100644 index 000000000..feafbd5dd --- /dev/null +++ b/src/test/converter2/issues/gh3006/two words.md @@ -0,0 +1 @@ +This document's name contains a space, #3006 diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index c91e54fe7..87f894055 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2171,4 +2171,15 @@ describe("Issue Tests", () => { equal(b.children?.map(c => c.name), ["A", "D"]); equal(b.children?.map(c => c.type?.toString()), ['"A"', '"D"']); }); + + it("#3006 handles documents containing spaces in their names", () => { + const project = convert(); + equal(["two words"], project.documents?.map(doc => doc.name)); + const doc = project.documents?.[0]; + const x = query(project, "x"); + + ok(x.comment?.summary[1].kind === "relative-link"); + ok(x.comment.summary[1].target); + ok(project.files.resolve(x.comment.summary[1].target, project) === doc); + }); }); From 0a716b2abfed0038ba450a85516b5f7cd3bb572f Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 20:25:28 -0600 Subject: [PATCH 24/46] Fix relative links to README file Resolves #3006 --- CHANGELOG.md | 3 + eslint.config.mjs | 7 + package.json | 4 +- pnpm-lock.yaml | 144 +++++++++--------- src/index.ts | 1 + src/lib/converter/comments/parser.ts | 12 +- src/lib/converter/plugins/CommentPlugin.ts | 7 +- src/lib/converter/plugins/IncludePlugin.ts | 6 +- src/lib/models/Comment.ts | 43 +++--- src/lib/models/DeclarationReflection.ts | 6 +- src/lib/models/FileRegistry.ts | 2 +- src/lib/models/ProjectReflection.ts | 8 +- src/lib/models/Reflection.ts | 8 +- src/lib/output/themes/MarkedPlugin.tsx | 11 +- .../output/themes/default/DefaultTheme.tsx | 9 +- .../themes/default/partials/comment.tsx | 46 +++--- .../default/partials/member.declaration.tsx | 2 +- .../default/partials/moduleReflection.tsx | 2 +- .../themes/default/partials/navigation.tsx | 4 +- .../themes/default/partials/typeDetails.tsx | 39 +++-- .../themes/default/templates/reflection.tsx | 2 +- src/lib/serialization/deserializer.ts | 8 +- src/lib/serialization/schema.ts | 6 +- src/lib/utils-common/i18n.ts | 3 +- src/lib/utils-common/index.ts | 1 + src/lib/utils-common/validation.ts | 4 +- src/lib/utils/options/declaration.ts | 15 +- src/lib/utils/options/defaults.ts | 14 +- src/lib/utils/options/readers/tsconfig.ts | 12 +- src/lib/utils/options/sources/typedoc.ts | 2 +- src/test/Repository.test.ts | 2 +- src/test/converter2/renderer/index.ts | 1 + src/test/merge.test.ts | 11 +- .../renderer/specs/classes/BaseClass.json | 3 - .../renderer/specs/classes/GenericClass.json | 11 +- .../specs/classes/ModifiersClass.json | 3 - .../renderer/specs/classes/RenderClass.json | 29 +--- .../renderer/specs/enums/Enumeration.json | 6 - src/test/renderer/specs/functions/box.json | 6 - .../specs/interfaces/BaseInterface.json | 3 - .../specs/interfaces/DisabledGroups.json | 5 +- .../ExpandType.ExpandedByDefault.json | 3 - .../specs/interfaces/NoneCategory.json | 6 - .../renderer/specs/interfaces/NoneGroup.json | 3 - src/test/renderer/specs/modules.json | 11 +- .../modules/ExpandType.NestedBehavior1.json | 5 - .../specs/types/ExpandType.AExpanded.json | 8 - .../specs/types/ExpandType.BExpanded.json | 3 - .../specs/types/ExpandType.Expandable.json | 3 - .../specs/types/ExpandType.Expandable2.json | 3 - .../ExpandType.NestedBehavior1.AExpanded.json | 8 - ...xpandType.NestedBehavior1.AllExpanded.json | 9 -- src/test/renderer/specs/types/Nested.json | 20 +-- src/test/utils.ts | 2 +- 54 files changed, 255 insertions(+), 340 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d073f914b..a9e5524ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ title: Changelog - Variables marked with `@enum` now work for symbols imported from another module, #3003. - Improved magic introduced with #2999 to work with imported symbols, #3003. - Fixed relative link resolution to file names containing percent encoded URLs, #3006. +- Linking to the project's README file with a relative link will now behave as expected, #3006. +- Reduced unnecessary HTML element rendering in default theme. + API: `Reflection.hasComment` and `Comment.hasVisibleComponent` now accepts an optional `notRenderedTags` parameter. ## v0.28.11 (2025-08-25) diff --git a/eslint.config.mjs b/eslint.config.mjs index a72f396c1..ff73874f2 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -53,6 +53,13 @@ const config = { // This is sometimes useful for clarity "@typescript-eslint/no-unnecessary-type-arguments": "off", + // It'd be kind of nice to be able to turn this on, but it doesn't seem to be worth the additional + // pain at this point. Turning it on adds ~300 lint errors, of which manual review found 1 bug, and + // whose suggestions would have introduced 3 bugs that I noticed, and potentially more... and it + // also didn't catch the bug which I originally turned it on for! Ideally, I'd like a version of + // this which ONLY checks for boolean comparisons of type number. + "@typescript-eslint/strict-boolean-expressions": "off", + // We still use `any` fairly frequently... "@typescript-eslint/ban-types": "off", "@typescript-eslint/no-explicit-any": "off", diff --git a/package.json b/package.json index d95921ac6..970aeb368 100644 --- a/package.json +++ b/package.json @@ -50,13 +50,13 @@ "c8": "^10.1.3", "dprint": "^0.50.1", "esbuild": "^0.25.8", - "eslint": "^9.32.0", + "eslint": "^9.34.0", "mocha": "^11.7.1", "puppeteer": "^24.11.1", "semver": "^7.7.2", "tsx": "^4.20.3", "typescript": "5.9.2", - "typescript-eslint": "^8.38.0" + "typescript-eslint": "^8.41.0" }, "files": [ "/bin", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7809dfed2..f20c82e1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,8 +70,8 @@ importers: specifier: 5.9.2 version: 5.9.2 typescript-eslint: - specifier: ^8.38.0 - version: 8.38.0(eslint@9.32.0)(typescript@5.9.2) + specifier: ^8.41.0 + version: 8.41.0(eslint@9.32.0)(typescript@5.9.2) packages: @@ -442,63 +442,63 @@ packages: '@types/yauzl@2.10.3': resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.38.0': - resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} + '@typescript-eslint/eslint-plugin@8.41.0': + resolution: {integrity: sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.38.0 + '@typescript-eslint/parser': ^8.41.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.38.0': - resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} + '@typescript-eslint/parser@8.41.0': + resolution: {integrity: sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.38.0': - resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} + '@typescript-eslint/project-service@8.41.0': + resolution: {integrity: sha512-b8V9SdGBQzQdjJ/IO3eDifGpDBJfvrNTp2QD9P2BeqWTGrRibgfgIlBSw6z3b6R7dPzg752tOs4u/7yCLxksSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.38.0': - resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} + '@typescript-eslint/scope-manager@8.41.0': + resolution: {integrity: sha512-n6m05bXn/Cd6DZDGyrpXrELCPVaTnLdPToyhBoFkLIMznRUQUEQdSp96s/pcWSQdqOhrgR1mzJ+yItK7T+WPMQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.38.0': - resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} + '@typescript-eslint/tsconfig-utils@8.41.0': + resolution: {integrity: sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.38.0': - resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} + '@typescript-eslint/type-utils@8.41.0': + resolution: {integrity: sha512-63qt1h91vg3KsjVVonFJWjgSK7pZHSQFKH6uwqxAH9bBrsyRhO6ONoKyXxyVBzG1lJnFAJcKAcxLS54N1ee1OQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.38.0': - resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} + '@typescript-eslint/types@8.41.0': + resolution: {integrity: sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.38.0': - resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} + '@typescript-eslint/typescript-estree@8.41.0': + resolution: {integrity: sha512-D43UwUYJmGhuwHfY7MtNKRZMmfd8+p/eNSfFe6tH5mbVDto+VQCayeAt35rOx3Cs6wxD16DQtIKw/YXxt5E0UQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.38.0': - resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} + '@typescript-eslint/utils@8.41.0': + resolution: {integrity: sha512-udbCVstxZ5jiPIXrdH+BZWnPatjlYwJuJkDA4Tbo3WyYLh8NvB+h/bKeSZHDOFKfphsZYJQqaFtLeXEqurQn1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.38.0': - resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} + '@typescript-eslint/visitor-keys@8.41.0': + resolution: {integrity: sha512-+GeGMebMCy0elMNg67LRNoVnUFPIm37iu5CmHESVx56/9Jsfdpsvbv605DQ81Pi/x11IdKUsS5nzgTYbCQU9fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typestrong/fs-fixture-builder@https://codeload.github.com/TypeStrong/fs-fixture-builder/tar.gz/34113409e3a171e68ce5e2b55461ef5c35591cfe': @@ -1297,12 +1297,12 @@ packages: typed-query-selector@2.12.0: resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} - typescript-eslint@8.38.0: - resolution: {integrity: sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==} + typescript-eslint@8.41.0: + resolution: {integrity: sha512-n66rzs5OBXW3SFSnZHr2T685q1i4ODm2nulFJhMZBotaTavsS8TrI3d7bDlRSs9yWo7HmyWrN9qDu14Qv7Y0Dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} @@ -1674,14 +1674,14 @@ snapshots: '@types/node': 18.19.113 optional: true - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/type-utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/parser': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.41.0 + '@typescript-eslint/type-utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.41.0 eslint: 9.32.0 graphemer: 1.4.0 ignore: 7.0.5 @@ -1691,41 +1691,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/scope-manager': 8.41.0 + '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.41.0 debug: 4.4.1(supports-color@8.1.1) eslint: 9.32.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.41.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@5.9.2) + '@typescript-eslint/types': 8.41.0 debug: 4.4.1(supports-color@8.1.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.38.0': + '@typescript-eslint/scope-manager@8.41.0': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/visitor-keys': 8.41.0 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.41.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.38.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.41.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) debug: 4.4.1(supports-color@8.1.1) eslint: 9.32.0 ts-api-utils: 2.1.0(typescript@5.9.2) @@ -1733,14 +1733,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.38.0': {} + '@typescript-eslint/types@8.41.0': {} - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.41.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.38.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/project-service': 8.41.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.41.0(typescript@5.9.2) + '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/visitor-keys': 8.41.0 debug: 4.4.1(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 @@ -1751,20 +1751,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/utils@8.41.0(eslint@9.32.0)(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.41.0 + '@typescript-eslint/types': 8.41.0 + '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) eslint: 9.32.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.38.0': + '@typescript-eslint/visitor-keys@8.41.0': dependencies: - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/types': 8.41.0 eslint-visitor-keys: 4.2.1 '@typestrong/fs-fixture-builder@https://codeload.github.com/TypeStrong/fs-fixture-builder/tar.gz/34113409e3a171e68ce5e2b55461ef5c35591cfe': {} @@ -2627,12 +2627,12 @@ snapshots: typed-query-selector@2.12.0: {} - typescript-eslint@8.38.0(eslint@9.32.0)(typescript@5.9.2): + typescript-eslint@8.41.0(eslint@9.32.0)(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) eslint: 9.32.0 typescript: 5.9.2 transitivePeerDependencies: diff --git a/src/index.ts b/src/index.ts index 166802605..aefdf11bc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -141,6 +141,7 @@ export { type NormalizedPathOrModule, type NormalizedPathOrModuleOrFunction, type SymbolReference, + type TagString, type TranslatedString, translateTagName, } from "#utils"; diff --git a/src/lib/converter/comments/parser.ts b/src/lib/converter/comments/parser.ts index cc016ab2b..924054b77 100644 --- a/src/lib/converter/comments/parser.ts +++ b/src/lib/converter/comments/parser.ts @@ -2,7 +2,7 @@ import assert, { ok } from "assert"; import { parseDocument as parseYamlDoc } from "yaml"; import type { CommentContextOptionalChecker, CommentParserConfig } from "./index.js"; import { Comment, type CommentDisplayPart, CommentTag, type InlineTagDisplayPart } from "../../models/index.js"; -import type { MinimalSourceFile } from "#utils"; +import type { MinimalSourceFile, TagString } from "#utils"; import { nicePath } from "../../utils/paths.js"; import { type Token, TokenSyntaxKind } from "./lexer.js"; import { extractTagName } from "./tagName.js"; @@ -235,7 +235,7 @@ export function parseCommentString( return { content, frontmatter: frontmatterData }; } -const HAS_USER_IDENTIFIER: `@${string}`[] = [ +const HAS_USER_IDENTIFIER: TagString[] = [ "@callback", "@param", "@prop", @@ -389,7 +389,7 @@ function blockTag( content = blockContent(comment, lexer, config, i18n, warning, files); } - return new CommentTag(tagName as `@${string}`, content); + return new CommentTag(tagName as TagString, content); } /** @@ -613,11 +613,11 @@ function blockContent( next.text = "@inheritDoc"; } if (config.modifierTags.has(next.text)) { - comment.modifierTags.add(next.text as `@${string}`); + comment.modifierTags.add(next.text as TagString); break; } else if (!atNewLine && !config.blockTags.has(next.text)) { // Treat unknown tag as a modifier, but warn about it. - comment.modifierTags.add(next.text as `@${string}`); + comment.modifierTags.add(next.text as TagString); warning( i18n.treating_unrecognized_tag_0_as_modifier(next.text), next, @@ -751,7 +751,7 @@ function inlineTag( const inlineTag: InlineTagDisplayPart = { kind: "inline-tag", - tag: tagName.text as `@${string}`, + tag: tagName.text as TagString, text: content.join(""), }; if (tagName.tsLinkTarget) { diff --git a/src/lib/converter/plugins/CommentPlugin.ts b/src/lib/converter/plugins/CommentPlugin.ts index b59d5cd43..67c013b69 100644 --- a/src/lib/converter/plugins/CommentPlugin.ts +++ b/src/lib/converter/plugins/CommentPlugin.ts @@ -22,6 +22,7 @@ import { removeIf, removeIfPresent, setIntersection, + type TagString, unique, } from "#utils"; import { ConverterComponent } from "../components.js"; @@ -56,7 +57,7 @@ const NEVER_RENDERED = [ // We might make this user configurable at some point, but for now, // this set is configured here. const MUTUALLY_EXCLUSIVE_MODIFIERS = [ - new Set<`@${string}`>([ + new Set([ "@alpha", "@beta", "@experimental", @@ -122,10 +123,10 @@ const MUTUALLY_EXCLUSIVE_MODIFIERS = [ */ export class CommentPlugin extends ConverterComponent { @Option("excludeTags") - accessor excludeTags!: `@${string}`[]; + accessor excludeTags!: TagString[]; @Option("cascadedModifierTags") - accessor cascadedModifierTags!: `@${string}`[]; + accessor cascadedModifierTags!: TagString[]; @Option("excludeInternal") accessor excludeInternal!: boolean; diff --git a/src/lib/converter/plugins/IncludePlugin.ts b/src/lib/converter/plugins/IncludePlugin.ts index 4228418e3..56da69733 100644 --- a/src/lib/converter/plugins/IncludePlugin.ts +++ b/src/lib/converter/plugins/IncludePlugin.ts @@ -358,7 +358,7 @@ type RegionTagRETuple = [ (regionName: string) => RegExp, (regionName: string) => RegExp, ]; -const regionTagREsByExt: Record = { +const regionTagREsByExt: Record = { bat: [ [ (regionName) => new RegExp(`:: *#region *${regionName} *\n`, "g"), @@ -407,14 +407,14 @@ const regionTagREsByExt: Record = { ], }; regionTagREsByExt["fs"] = [ - ...regionTagREsByExt["ts"], + ...regionTagREsByExt["ts"]!, [ (regionName) => new RegExp(`(#_region) *${regionName} *\n`, "g"), (regionName) => new RegExp(`(#_endregion) *${regionName} *\n`, "g"), ], ]; regionTagREsByExt["java"] = [ - ...regionTagREsByExt["ts"], + ...regionTagREsByExt["ts"]!, [ (regionName) => new RegExp(`// * *${regionName} *\n`, "g"), (regionName) => new RegExp(`// * *${regionName} *\n`, "g"), diff --git a/src/lib/models/Comment.ts b/src/lib/models/Comment.ts index 08fb76395..70316f50b 100644 --- a/src/lib/models/Comment.ts +++ b/src/lib/models/Comment.ts @@ -1,4 +1,4 @@ -import { assertNever, i18n, NonEnumerable, type NormalizedPath, removeIf } from "#utils"; +import { assertNever, i18n, NonEnumerable, type NormalizedPath, removeIf, type TagString } from "#utils"; import type { Reflection, ReflectionId } from "./Reflection.js"; import { ReflectionSymbolId } from "./ReflectionSymbolId.js"; @@ -35,7 +35,7 @@ export type CommentDisplayPart = */ export interface InlineTagDisplayPart { kind: "inline-tag"; - tag: `@${string}`; + tag: TagString; text: string; target?: Reflection | string | ReflectionSymbolId; tsLinkText?: string; @@ -80,7 +80,7 @@ export class CommentTag { /** * The name of this tag, e.g. `@returns`, `@example` */ - tag: `@${string}`; + tag: TagString; /** * Some tags, (`@typedef`, `@param`, `@property`, etc.) may have a user defined identifier associated with them. @@ -103,7 +103,7 @@ export class CommentTag { /** * Create a new CommentTag instance. */ - constructor(tag: `@${string}`, text: CommentDisplayPart[]) { + constructor(tag: TagString, text: CommentDisplayPart[]) { this.tag = tag; this.content = text; } @@ -396,7 +396,7 @@ export class Comment { /** * All modifier tags present on the comment, e.g. `@alpha`, `@beta`. */ - modifierTags: Set<`@${string}`> = new Set(); + modifierTags: Set = new Set(); /** * Label associated with this reflection, if any (https://tsdoc.org/pages/tags/label/) @@ -436,7 +436,7 @@ export class Comment { constructor( summary: CommentDisplayPart[] = [], blockTags: CommentTag[] = [], - modifierTags: Set<`@${string}`> = new Set(), + modifierTags: Set = new Set(), ) { this.summary = summary; this.blockTags = blockTags; @@ -542,15 +542,20 @@ export class Comment { } /** - * Has this comment a visible component? + * Checks if this comment contains any visible text. * - * @returns TRUE when this comment has a visible component. + * @returns TRUE when this reflection has a visible comment. */ - hasVisibleComponent(): boolean { - return ( - this.summary.some((x) => x.kind !== "text" || x.text !== "") || - this.blockTags.length > 0 - ); + hasVisibleComponent(notRenderedTags?: readonly TagString[]): boolean { + if (this.summary.some((x) => x.kind !== "text" || x.text !== "")) { + return true; + } + + if (notRenderedTags) { + return this.blockTags.some(tag => !notRenderedTags.includes(tag.tag)); + } else { + return this.blockTags.length > 0; + } } /** @@ -559,11 +564,11 @@ export class Comment { * @param tagName The name of the tag to look for. * @returns TRUE when this comment contains a tag with the given name, otherwise FALSE. */ - hasModifier(tagName: `@${string}`): boolean { + hasModifier(tagName: TagString): boolean { return this.modifierTags.has(tagName); } - removeModifier(tagName: `@${string}`) { + removeModifier(tagName: TagString) { this.modifierTags.delete(tagName); } @@ -573,18 +578,18 @@ export class Comment { * @param tagName The name of the tag to look for. * @returns The found tag or undefined. */ - getTag(tagName: `@${string}`): CommentTag | undefined { + getTag(tagName: TagString): CommentTag | undefined { return this.blockTags.find((tag) => tag.tag === tagName); } /** * Get all tags with the given tag name. */ - getTags(tagName: `@${string}`): CommentTag[] { + getTags(tagName: TagString): CommentTag[] { return this.blockTags.filter((tag) => tag.tag === tagName); } - getIdentifiedTag(identifier: string, tagName: `@${string}`) { + getIdentifiedTag(identifier: string, tagName: TagString) { return this.blockTags.find( (tag) => tag.tag === tagName && tag.name === identifier, ); @@ -594,7 +599,7 @@ export class Comment { * Removes all block tags with the given tag name from the comment. * @param tagName */ - removeTags(tagName: `@${string}`) { + removeTags(tagName: TagString) { removeIf(this.blockTags, (tag) => tag.tag === tagName); } diff --git a/src/lib/models/DeclarationReflection.ts b/src/lib/models/DeclarationReflection.ts index 6f225773b..50b94e773 100644 --- a/src/lib/models/DeclarationReflection.ts +++ b/src/lib/models/DeclarationReflection.ts @@ -354,11 +354,7 @@ export class DeclarationReflection extends ContainerReflection { new ReflectionSymbolId(sid), ); } else { - de.logger.warn( - i18n.serialized_project_referenced_0_not_part_of_project( - id.toString(), - ), - ); + de.logger.warn(i18n.serialized_project_referenced_0_not_part_of_project(id)); } } }); diff --git a/src/lib/models/FileRegistry.ts b/src/lib/models/FileRegistry.ts index 0081c87cc..6cda93a04 100644 --- a/src/lib/models/FileRegistry.ts +++ b/src/lib/models/FileRegistry.ts @@ -85,7 +85,7 @@ export class FileRegistry { project: ProjectReflection, ): string | Reflection | undefined { const reflId = this.mediaToReflection.get(id); - if (reflId) { + if (typeof reflId === "number") { return project.getReflectionById(reflId); } return this.mediaToPath.get(id); diff --git a/src/lib/models/ProjectReflection.ts b/src/lib/models/ProjectReflection.ts index bc9fd66a5..68ae7586f 100644 --- a/src/lib/models/ProjectReflection.ts +++ b/src/lib/models/ProjectReflection.ts @@ -368,7 +368,7 @@ export class ProjectReflection extends ContainerReflection { this.reflectionIdToSymbolIdMap.set(reflection.id, id); const previous = this.symbolToReflectionIdMap.get(id); - if (previous) { + if (typeof previous !== "undefined") { if (typeof previous === "number") { this.symbolToReflectionIdMap.set(id, [previous, reflection.id]); } else { @@ -440,11 +440,7 @@ export class ProjectReflection extends ContainerReflection { if (refl) { this.registerSymbolId(refl, new ReflectionSymbolId(sid)); } else { - de.logger.warn( - i18n.serialized_project_referenced_0_not_part_of_project( - id.toString(), - ), - ); + de.logger.warn(i18n.serialized_project_referenced_0_not_part_of_project(id)); } } }); diff --git a/src/lib/models/Reflection.ts b/src/lib/models/Reflection.ts index 9468671d1..a854fcd62 100644 --- a/src/lib/models/Reflection.ts +++ b/src/lib/models/Reflection.ts @@ -1,7 +1,7 @@ import { Comment } from "./Comment.js"; import { splitUnquotedString } from "./utils.js"; import type { ProjectReflection } from "./ProjectReflection.js"; -import { i18n, type NeverIfInternal, NonEnumerable, type TranslatedString } from "#utils"; +import { i18n, type NeverIfInternal, NonEnumerable, type TagString, type TranslatedString } from "#utils"; import { ReflectionKind } from "./kind.js"; import type { Deserializer, JSONOutput, Serializer } from "#serialization"; import type { ReflectionVariant } from "./variant.js"; @@ -392,12 +392,12 @@ export abstract class Reflection { } /** - * Has this reflection a visible comment? + * Checks if this reflection has a comment which contains any visible text. * * @returns TRUE when this reflection has a visible comment. */ - hasComment(): boolean { - return this.comment ? this.comment.hasVisibleComponent() : false; + hasComment(notRenderedTags?: readonly TagString[]): boolean { + return this.comment ? this.comment.hasVisibleComponent(notRenderedTags) : false; } hasGetterOrSetter(): boolean { diff --git a/src/lib/output/themes/MarkedPlugin.tsx b/src/lib/output/themes/MarkedPlugin.tsx index 6c422dc1f..924b28ca9 100644 --- a/src/lib/output/themes/MarkedPlugin.tsx +++ b/src/lib/output/themes/MarkedPlugin.tsx @@ -232,7 +232,16 @@ export class MarkedPlugin extends ContextAwareRendererComponent { const refl = page.project.files.resolve(part.target, page.model.project); let url: string | undefined; if (typeof refl === "object") { - url = context.urlTo(refl); + // #3006, this is an unfortunate heuristic. If there is a relative link to the project + // the user probably created it by linking to the directory of the project or to + // the project's readme. Since the readme doesn't get its own reflection, we can't + // reliably disambiguate this and instead will arbitrarily decide to reference the + // root index page in this case. + if (refl.isProject()) { + url = context.relativeURL("./"); + } else { + url = context.urlTo(refl); + } } else { const fileName = page.project.files.getName(part.target); if (fileName) { diff --git a/src/lib/output/themes/default/DefaultTheme.tsx b/src/lib/output/themes/default/DefaultTheme.tsx index 3c699240a..10a2c5c99 100644 --- a/src/lib/output/themes/default/DefaultTheme.tsx +++ b/src/lib/output/themes/default/DefaultTheme.tsx @@ -15,7 +15,7 @@ import type { PageEvent, RendererEvent } from "../../events.js"; import type { MarkedPlugin } from "../../plugins/index.js"; import { DefaultThemeRenderContext } from "./DefaultThemeRenderContext.js"; import { getIcons, type Icons } from "./partials/icon.js"; -import { filterMap, JSX } from "#utils"; +import { filterMap, JSX, type TagString } from "#utils"; import { classNames, getDisplayName, toStyleClass } from "../lib.js"; import { PageKind, type Router } from "../../router.js"; import { loadHighlighter, Option } from "#node-utils"; @@ -365,8 +365,8 @@ function getReflectionClasses(reflection: Reflection, filters: Record - refl.comment?.hasModifier(key as `@${string}`) || refl.comment?.getTag(key as `@${string}`), + (refl) => refl.comment?.hasModifier(key as TagString) || refl.comment?.getTag(key as TagString), ) ) { classes.add(toStyleClass(`tsd-is-${key.substring(1)}`)); diff --git a/src/lib/output/themes/default/partials/comment.tsx b/src/lib/output/themes/default/partials/comment.tsx index 1f0109381..46731e511 100644 --- a/src/lib/output/themes/default/partials/comment.tsx +++ b/src/lib/output/themes/default/partials/comment.tsx @@ -69,30 +69,34 @@ export function commentTags(context: DefaultThemeRenderContext, props: Reflectio skipSave.forEach((skip, i) => (props.comment!.blockTags[i].skipRendering = skip)); + const tagsContents = tags.map((item) => { + const name = item.name + ? `${translateTagName(item.tag)}: ${item.name}` + : translateTagName(item.tag); + + const anchor = context.slugger.slug(name); + + return ( + <> +
+ + +
+ + ); + }); + return ( <> {beforeTags} -
- {tags.map((item) => { - const name = item.name - ? `${translateTagName(item.tag)}: ${item.name}` - : translateTagName(item.tag); - - const anchor = context.slugger.slug(name); - - return ( - <> -
- - -
- - ); - })} -
+ {tagsContents.length > 0 && ( +
+ {tagsContents} +
+ )} {afterTags} ); diff --git a/src/lib/output/themes/default/partials/member.declaration.tsx b/src/lib/output/themes/default/partials/member.declaration.tsx index e304723d2..510caa883 100644 --- a/src/lib/output/themes/default/partials/member.declaration.tsx +++ b/src/lib/output/themes/default/partials/member.declaration.tsx @@ -15,7 +15,7 @@ function shouldRenderDefaultValue(props: DeclarationReflection) { if (props.type && props.type.type === "literal") { const reflectionTypeString = props.type.toString(); - if (reflectionTypeString === defaultValue.toString()) { + if (reflectionTypeString === defaultValue) { return false; } } diff --git a/src/lib/output/themes/default/partials/moduleReflection.tsx b/src/lib/output/themes/default/partials/moduleReflection.tsx index 31418441d..89a4dd4d9 100644 --- a/src/lib/output/themes/default/partials/moduleReflection.tsx +++ b/src/lib/output/themes/default/partials/moduleReflection.tsx @@ -16,7 +16,7 @@ export function moduleReflection(context: DefaultThemeRenderContext, mod: Declar return ( <> - {mod.hasComment() && ( + {mod.hasComment(context.options.getValue("notRenderedTags")) && (
{context.commentSummary(mod)} {context.commentTags(mod)} diff --git a/src/lib/output/themes/default/partials/navigation.tsx b/src/lib/output/themes/default/partials/navigation.tsx index 480859b02..39e9efa93 100644 --- a/src/lib/output/themes/default/partials/navigation.tsx +++ b/src/lib/output/themes/default/partials/navigation.tsx @@ -1,5 +1,5 @@ import { type Reflection, ReflectionFlag, ReflectionFlags } from "../../../../models/index.js"; -import { i18n, JSX, translateTagName } from "#utils"; +import { i18n, JSX, type TagString, translateTagName } from "#utils"; import type { PageEvent, PageHeading } from "../../../events.js"; import { classNames, getDisplayName, wbr } from "../../lib.js"; import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext.js"; @@ -65,7 +65,7 @@ export function settings(context: DefaultThemeRenderContext) { buildFilterItem( context, filterName, - translateTagName(key as `@${string}`), + translateTagName(key as TagString), defaultFilters[key], ), ); diff --git a/src/lib/output/themes/default/partials/typeDetails.tsx b/src/lib/output/themes/default/partials/typeDetails.tsx index d0c1e1e99..fbf4a6748 100644 --- a/src/lib/output/themes/default/partials/typeDetails.tsx +++ b/src/lib/output/themes/default/partials/typeDetails.tsx @@ -7,24 +7,29 @@ import { type SignatureReflection, } from "../../../../models/index.js"; import type { ReferenceType, SomeType, TypeVisitor } from "../../../../models/types.js"; -import { assert, i18n, JSX } from "#utils"; +import { assert, i18n, JSX, type TagString } from "#utils"; import { classNames, getKindClass } from "../../lib.js"; import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext.js"; import { anchorTargetIfPresent } from "./anchor-icon.js"; -function renderingTypeDetailsIsUseful(container: Reflection, type: SomeType): boolean { +function renderingTypeDetailsIsUseful( + container: Reflection, + type: SomeType, + notRenderedTags: readonly TagString[], +): boolean { const isUsefulVisitor: Partial> = { array(type) { - return renderingTypeDetailsIsUseful(container, type.elementType); + return renderingTypeDetailsIsUseful(container, type.elementType, notRenderedTags); }, intersection(type) { - return type.types.some(t => renderingTypeDetailsIsUseful(container, t)); + return type.types.some(t => renderingTypeDetailsIsUseful(container, t, notRenderedTags)); }, union(type) { - return !!type.elementSummaries || type.types.some(t => renderingTypeDetailsIsUseful(container, t)); + return !!type.elementSummaries || + type.types.some(t => renderingTypeDetailsIsUseful(container, t, notRenderedTags)); }, reflection(type) { - return renderingChildIsUseful(type.declaration); + return renderingChildIsUseful(type.declaration, notRenderedTags); }, reference(type) { return shouldExpandReference(container, type); @@ -44,7 +49,7 @@ export function typeDeclaration( "typeDeclaration(reflectionOwningType, type) called incorrectly", ); - if (renderingTypeDetailsIsUseful(reflectionOwningType, type)) { + if (renderingTypeDetailsIsUseful(reflectionOwningType, type, context.options.getValue("notRenderedTags"))) { return (

{i18n.theme_type_declaration()}

@@ -194,7 +199,7 @@ export function typeDetailsIfUseful( "typeDetailsIfUseful(reflectionOwningType, type) called incorrectly", ); - if (type && renderingTypeDetailsIsUseful(reflectionOwningType, type)) { + if (type && renderingTypeDetailsIsUseful(reflectionOwningType, type, context.options.getValue("notRenderedTags"))) { return context.typeDetails(reflectionOwningType, type, false); } } @@ -314,6 +319,8 @@ function renderChild( // standard type if (child.type) { + const notRenderedTags = context.options.getValue("notRenderedTags"); + return (
  • @@ -327,7 +334,7 @@ function renderChild( {context.type(child.type)}
    {highlightOrComment(child)} - {child.getProperties().some(renderingChildIsUseful) && ( + {child.getProperties().some(prop => renderingChildIsUseful(prop, notRenderedTags)) && (
      {child.getProperties().map((c) => renderChild(context, c, renderAnchors))}
    @@ -401,7 +408,7 @@ function renderIndexSignature(context: DefaultThemeRenderContext, index: Signatu ); } -function renderingChildIsUseful(refl: DeclarationReflection) { +function renderingChildIsUseful(refl: DeclarationReflection, notRenderedTags: readonly TagString[]) { // Object types directly under a variable/type alias will always be considered useful. // This probably isn't ideal, but it is an easy thing to check when assigning URLs // in the default theme, so we'll make the assumption that those properties ought to always @@ -415,20 +422,20 @@ function renderingChildIsUseful(refl: DeclarationReflection) { return true; } - if (renderingThisChildIsUseful(refl)) { + if (renderingThisChildIsUseful(refl, notRenderedTags)) { return true; } - return refl.getProperties().some(renderingThisChildIsUseful); + return refl.getProperties().some(prop => renderingThisChildIsUseful(prop, notRenderedTags)); } -function renderingThisChildIsUseful(refl: DeclarationReflection) { - if (refl.hasComment()) return true; +function renderingThisChildIsUseful(refl: DeclarationReflection, notRenderedTags: readonly TagString[]) { + if (refl.hasComment(notRenderedTags)) return true; const declaration = refl.type?.type === "reflection" ? refl.type.declaration : refl; - if (declaration.hasComment()) return true; + if (declaration.hasComment(notRenderedTags)) return true; return declaration.getAllSignatures().some((sig) => { - return sig.hasComment() || sig.parameters?.some((p) => p.hasComment()); + return sig.hasComment(notRenderedTags) || sig.parameters?.some((p) => p.hasComment(notRenderedTags)); }); } diff --git a/src/lib/output/themes/default/templates/reflection.tsx b/src/lib/output/themes/default/templates/reflection.tsx index 6c949995d..2fd4735a3 100644 --- a/src/lib/output/themes/default/templates/reflection.tsx +++ b/src/lib/output/themes/default/templates/reflection.tsx @@ -27,7 +27,7 @@ export function reflectionTemplate(context: DefaultThemeRenderContext, props: Pa return ( <> - {props.model.hasComment() && ( + {props.model.hasComment(context.options.getValue("notRenderedTags")) && (
    {context.commentSummary(props.model)} {context.commentTags(props.model)} diff --git a/src/lib/serialization/deserializer.ts b/src/lib/serialization/deserializer.ts index d2cb57bde..141c3a29d 100644 --- a/src/lib/serialization/deserializer.ts +++ b/src/lib/serialization/deserializer.ts @@ -134,7 +134,7 @@ export class Deserializer { return new IntrinsicType(obj.name); }, literal(obj) { - if (obj.value && typeof obj.value === "object") { + if (typeof obj.value === "object" && obj.value != null) { return new LiteralType( BigInt( `${obj.value.negative ? "-" : ""}${obj.value.value}`, @@ -352,15 +352,15 @@ export class Deserializer { return project; } - revive>( + revive>( source: NonNullable, creator: (obj: T) => U, ): U; - revive>( + revive>( source: T | undefined, creator: (obj: T) => U, ): U | undefined; - revive>( + revive>( source: T | undefined, creator: (obj: T) => U, ): U | undefined { diff --git a/src/lib/serialization/schema.ts b/src/lib/serialization/schema.ts index 34debec86..d55900d71 100644 --- a/src/lib/serialization/schema.ts +++ b/src/lib/serialization/schema.ts @@ -30,7 +30,7 @@ */ import type * as M from "#models"; -import type { IfInternal, NormalizedPath } from "#utils"; +import type { IfInternal, NormalizedPath, TagString } from "#utils"; // Keep this in sync with JSON_SCHEMA_VERSION in ProjectReflection.ts export const SCHEMA_VERSION = "2.0"; @@ -365,7 +365,7 @@ export interface ReflectionFlags extends Partial> { summary: CommentDisplayPart[]; - modifierTags?: `@${string}`[]; + modifierTags?: TagString[]; } /** @category Comments */ @@ -390,7 +390,7 @@ export type CommentDisplayPart = */ export interface InlineTagDisplayPart { kind: "inline-tag"; - tag: `@${string}`; + tag: TagString; text: string; target?: string | ReflectionId | ReflectionSymbolId; tsLinkText?: string; diff --git a/src/lib/utils-common/i18n.ts b/src/lib/utils-common/i18n.ts index 3ee361204..97044c53d 100644 --- a/src/lib/utils-common/i18n.ts +++ b/src/lib/utils-common/i18n.ts @@ -1,5 +1,6 @@ // Type only import to non-bundled file // eslint-disable-next-line no-restricted-imports +import type { TagString } from "#utils"; import type { TranslationProxy } from "../internationalization/internationalization.js"; let translations: Record = {}; @@ -36,7 +37,7 @@ export const i18n = new Proxy({}, { }, }) as TranslationProxy; -export function translateTagName(tag: `@${string}`): TranslatedString { +export function translateTagName(tag: TagString): TranslatedString { const tagName = tag.substring(1); if (Object.prototype.hasOwnProperty.call(translations, `tag_${tagName}`)) { return translations[`tag_${tagName}`] as TranslatedString; diff --git a/src/lib/utils-common/index.ts b/src/lib/utils-common/index.ts index 135c9068a..be18a0756 100644 --- a/src/lib/utils-common/index.ts +++ b/src/lib/utils-common/index.ts @@ -16,3 +16,4 @@ export * from "./path.js"; export * from "./set.js"; export * from "./string.js"; export * as Validation from "./validation.js"; +export type { TagString } from "./validation.js"; diff --git a/src/lib/utils-common/validation.ts b/src/lib/utils-common/validation.ts index eca8886d9..f6c01aa33 100644 --- a/src/lib/utils-common/validation.ts +++ b/src/lib/utils-common/validation.ts @@ -119,6 +119,8 @@ export function optional(x: T): Optional { return { [opt]: x }; } -export function isTagString(x: unknown): x is `@${string}` { +export type TagString = `@${string}`; + +export function isTagString(x: unknown): x is TagString { return typeof x === "string" && /^@[a-z][a-z0-9-]*$/i.test(x); } diff --git a/src/lib/utils/options/declaration.ts b/src/lib/utils/options/declaration.ts index 61ca04387..ef234c17d 100644 --- a/src/lib/utils/options/declaration.ts +++ b/src/lib/utils/options/declaration.ts @@ -11,6 +11,7 @@ import { type NormalizedPath, type NormalizedPathOrModule, type NormalizedPathOrModuleOrFunction, + type TagString, type TranslatedString, } from "#utils"; import type { TranslationProxy } from "../../internationalization/internationalization.js"; @@ -297,7 +298,7 @@ export interface TypeDocOptionMap { private?: boolean; inherited?: boolean; external?: boolean; - [tag: `@${string}`]: boolean; + [tag: TagString]: boolean; }>; searchCategoryBoosts: ManuallyValidatedOption>; searchGroupBoosts: ManuallyValidatedOption>; @@ -309,15 +310,15 @@ export interface TypeDocOptionMap { preserveLinkText: boolean; jsDocCompatibility: JsDocCompatibility; suppressCommentWarningsInDeclarationFiles: boolean; - blockTags: `@${string}`[]; - inlineTags: `@${string}`[]; - modifierTags: `@${string}`[]; - excludeTags: `@${string}`[]; - notRenderedTags: `@${string}`[]; + blockTags: TagString[]; + inlineTags: TagString[]; + modifierTags: TagString[]; + excludeTags: TagString[]; + notRenderedTags: TagString[]; externalSymbolLinkMappings: ManuallyValidatedOption< Record> >; - cascadedModifierTags: `@${string}`[]; + cascadedModifierTags: TagString[]; // Organization categorizeByGroup: boolean; diff --git a/src/lib/utils/options/defaults.ts b/src/lib/utils/options/defaults.ts index 20d6d1472..277f0e035 100644 --- a/src/lib/utils/options/defaults.ts +++ b/src/lib/utils/options/defaults.ts @@ -4,7 +4,7 @@ */ import type { BundledLanguage } from "@gerrit0/mini-shiki"; import * as TagDefaults from "./tsdoc-defaults.js"; -import type { EnumKeys } from "#utils"; +import type { EnumKeys, TagString } from "#utils"; import type { ReflectionKind } from "../../models/index.js"; export const excludeNotDocumentedKinds: readonly EnumKeys< @@ -31,7 +31,7 @@ export const excludeNotDocumentedKinds: readonly EnumKeys< "Reference", ]; -export const excludeTags: readonly `@${string}`[] = [ +export const excludeTags: readonly TagString[] = [ "@override", "@virtual", "@privateRemarks", @@ -41,17 +41,17 @@ export const excludeTags: readonly `@${string}`[] = [ "@inlineType", ]; -export const blockTags: readonly `@${string}`[] = TagDefaults.blockTags; -export const inlineTags: readonly `@${string}`[] = TagDefaults.inlineTags; -export const modifierTags: readonly `@${string}`[] = TagDefaults.modifierTags; +export const blockTags: readonly TagString[] = TagDefaults.blockTags; +export const inlineTags: readonly TagString[] = TagDefaults.inlineTags; +export const modifierTags: readonly TagString[] = TagDefaults.modifierTags; -export const cascadedModifierTags: readonly `@${string}`[] = [ +export const cascadedModifierTags: readonly TagString[] = [ "@alpha", "@beta", "@experimental", ]; -export const notRenderedTags: readonly `@${string}`[] = [ +export const notRenderedTags: readonly TagString[] = [ "@showCategories", "@showGroups", "@hideCategories", diff --git a/src/lib/utils/options/readers/tsconfig.ts b/src/lib/utils/options/readers/tsconfig.ts index 45add3be1..42d1a439f 100644 --- a/src/lib/utils/options/readers/tsconfig.ts +++ b/src/lib/utils/options/readers/tsconfig.ts @@ -5,14 +5,14 @@ import ts from "typescript"; import type { Options, OptionsReader } from "../options.js"; import { isFile } from "../../fs.js"; import { ok } from "assert"; -import { i18n, type Logger, type TranslatedString, unique, Validation } from "#utils"; +import { i18n, type Logger, type TagString, type TranslatedString, unique, Validation } from "#utils"; import { nicePath, normalizePath } from "../../paths.js"; import { createRequire } from "module"; import { tsdocBlockTags, tsdocInlineTags, tsdocModifierTags } from "../tsdoc-defaults.js"; import { findTsConfigFile, getTypeDocOptionsFromTsConfig, readTsConfig } from "../../tsconfig.js"; import { diagnostics } from "../../loggers.js"; -function isSupportForTags(obj: unknown): obj is Record<`@${string}`, boolean> { +function isSupportForTags(obj: unknown): obj is Record { return ( Validation.validate({}, obj) && Object.entries(obj).every(([key, val]) => { @@ -148,15 +148,15 @@ export class TSConfigReader implements OptionsReader { const config = this.readTsDoc(logger, tsdoc); if (!config) return; - const supported = (tag: { tagName: `@${string}` }) => { + const supported = (tag: { tagName: TagString }) => { return config.supportForTags ? !!config.supportForTags[tag.tagName] : true; }; - const blockTags: `@${string}`[] = []; - const inlineTags: `@${string}`[] = []; - const modifierTags: `@${string}`[] = []; + const blockTags: TagString[] = []; + const inlineTags: TagString[] = []; + const modifierTags: TagString[] = []; if (!config.noStandardTags) { blockTags.push(...tsdocBlockTags); diff --git a/src/lib/utils/options/sources/typedoc.ts b/src/lib/utils/options/sources/typedoc.ts index c1658768c..6799ee531 100644 --- a/src/lib/utils/options/sources/typedoc.ts +++ b/src/lib/utils/options/sources/typedoc.ts @@ -650,7 +650,7 @@ export function addTypeDocOptions(options: Pick) { }, validate(value) { const knownKeys = ["protected", "private", "inherited", "external"]; - if (!value || typeof value !== "object") { + if (typeof value !== "object" || !value) { throw new Error( i18n.option_0_must_be_an_object("visibilityFilters"), ); diff --git a/src/test/Repository.test.ts b/src/test/Repository.test.ts index f87891295..014addabb 100644 --- a/src/test/Repository.test.ts +++ b/src/test/Repository.test.ts @@ -260,7 +260,7 @@ describe("RepositoryManager - git enabled", () => { it("Handles a nested repository", () => { const sub = normalizePath(join(fix.cwd, "sub_repo/repo.txt")); - const repo = manager.getRepository(sub) as GitRepository; + const repo = manager.getRepository(sub) as GitRepository | undefined; ok(repo); equal(repo.path, normalizePath(join(fix.cwd, "sub_repo"))); equal(repo.getURL(sub, 1), "link:repo.txt"); diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 5d8abb16f..4ccad6fcd 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -131,6 +131,7 @@ export interface NoneGroup { /** @disableGroups */ export interface DisabledGroups { a: 1; + /** [link to readme #3006](./index.ts) */ b(): void; } diff --git a/src/test/merge.test.ts b/src/test/merge.test.ts index 65d58c782..b38356bc2 100644 --- a/src/test/merge.test.ts +++ b/src/test/merge.test.ts @@ -1,8 +1,9 @@ import { deepStrictEqual as equal, ok } from "assert"; import { join } from "path"; -import { Application, type DeclarationReflection, EntryPointStrategy, normalizePath, ReferenceType } from "../index.js"; +import { Application, EntryPointStrategy, normalizePath, ReferenceType } from "../index.js"; import { getConverterBase } from "./programs.js"; import { TestLogger } from "./TestLogger.js"; +import { query } from "./utils.js"; const base = getConverterBase(); @@ -29,12 +30,8 @@ describe("Merging projects", () => { ["alias", "class"], ); - const crossRef = project.getChildByName( - "alias.MergedCrossReference", - ) as DeclarationReflection; - const testClass = project.getChildByName("class.class.TestClass"); - ok(testClass, "Missing test class"); - ok(crossRef, "Missing MergedCrossReference"); + const crossRef = query(project, "alias.MergedCrossReference"); + const testClass = query(project, "class.class.TestClass"); ok(crossRef.type instanceof ReferenceType); ok( diff --git a/src/test/renderer/specs/classes/BaseClass.json b/src/test/renderer/specs/classes/BaseClass.json index 288a179ce..9aa168302 100644 --- a/src/test/renderer/specs/classes/BaseClass.json +++ b/src/test/renderer/specs/classes/BaseClass.json @@ -433,9 +433,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/classes/GenericClass.json b/src/test/renderer/specs/classes/GenericClass.json index 0322a9cfe..8e8824309 100644 --- a/src/test/renderer/specs/classes/GenericClass.json +++ b/src/test/renderer/specs/classes/GenericClass.json @@ -26,14 +26,9 @@ ] }, { - "section.tsd-panel.tsd-comment": [ - { - "div.tsd-comment.tsd-typography": "

    Generic class

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] - } - ] + "section.tsd-panel.tsd-comment": { + "div.tsd-comment.tsd-typography": "

    Generic class

    \n" + } }, { "section.tsd-panel": [ diff --git a/src/test/renderer/specs/classes/ModifiersClass.json b/src/test/renderer/specs/classes/ModifiersClass.json index 17d479fa2..5d76ca4b9 100644 --- a/src/test/renderer/specs/classes/ModifiersClass.json +++ b/src/test/renderer/specs/classes/ModifiersClass.json @@ -218,9 +218,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/classes/RenderClass.json b/src/test/renderer/specs/classes/RenderClass.json index e87d21064..05fb799e2 100644 --- a/src/test/renderer/specs/classes/RenderClass.json +++ b/src/test/renderer/specs/classes/RenderClass.json @@ -26,14 +26,9 @@ ] }, { - "section.tsd-panel.tsd-comment": [ - { - "div.tsd-comment.tsd-typography": "

    Renderer class

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] - } - ] + "section.tsd-panel.tsd-comment": { + "div.tsd-comment.tsd-typography": "

    Renderer class

    \n" + } }, { "tag": "section.tsd-panel.tsd-hierarchy", @@ -107,9 +102,6 @@ }, { "div.tsd-comment.tsd-typography": "

    Index signature

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } @@ -392,9 +384,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": [ { @@ -495,9 +484,6 @@ { "div.tsd-comment.tsd-typography": "

    Property

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { @@ -988,9 +974,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": [ { @@ -1093,9 +1076,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { @@ -1190,9 +1170,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/enums/Enumeration.json b/src/test/renderer/specs/enums/Enumeration.json index 3c5e62ba9..35b35df3c 100644 --- a/src/test/renderer/specs/enums/Enumeration.json +++ b/src/test/renderer/specs/enums/Enumeration.json @@ -167,9 +167,6 @@ { "div.tsd-comment.tsd-typography": "

    Value1 comment

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { @@ -221,9 +218,6 @@ { "div.tsd-comment.tsd-typography": "

    Value2 comment

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/functions/box.json b/src/test/renderer/specs/functions/box.json index 17a67cef3..7d317b856 100644 --- a/src/test/renderer/specs/functions/box.json +++ b/src/test/renderer/specs/functions/box.json @@ -148,9 +148,6 @@ }, { "div.tsd-comment.tsd-typography": "

    Item comment

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } @@ -184,9 +181,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/interfaces/BaseInterface.json b/src/test/renderer/specs/interfaces/BaseInterface.json index 9ccfa435d..0097acc1b 100644 --- a/src/test/renderer/specs/interfaces/BaseInterface.json +++ b/src/test/renderer/specs/interfaces/BaseInterface.json @@ -357,9 +357,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/interfaces/DisabledGroups.json b/src/test/renderer/specs/interfaces/DisabledGroups.json index 14e3d537a..81ddbd754 100644 --- a/src/test/renderer/specs/interfaces/DisabledGroups.json +++ b/src/test/renderer/specs/interfaces/DisabledGroups.json @@ -247,6 +247,9 @@ }, { "div.tsd-description": [ + { + "div.tsd-comment.tsd-typography": "

    link to readme #3006

    \n" + }, { "h4.tsd-returns-title": [ "Returns ", @@ -265,7 +268,7 @@ "props": { "href": "index.ts" }, - "children": "index.ts:134" + "children": "index.ts:135" } ] } diff --git a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json index a0a0fbe17..9ee09478a 100644 --- a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json +++ b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json @@ -183,9 +183,6 @@ { "div.tsd-comment.tsd-typography": "

    B

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/interfaces/NoneCategory.json b/src/test/renderer/specs/interfaces/NoneCategory.json index 24d919665..8f9f12a08 100644 --- a/src/test/renderer/specs/interfaces/NoneCategory.json +++ b/src/test/renderer/specs/interfaces/NoneCategory.json @@ -235,9 +235,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { @@ -303,9 +300,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/interfaces/NoneGroup.json b/src/test/renderer/specs/interfaces/NoneGroup.json index fdca9ae0d..925274d34 100644 --- a/src/test/renderer/specs/interfaces/NoneGroup.json +++ b/src/test/renderer/specs/interfaces/NoneGroup.json @@ -193,9 +193,6 @@ } ] }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index f3dad2abe..35cc03b77 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -16,14 +16,9 @@ ] }, { - "section.tsd-panel.tsd-comment": [ - { - "div.tsd-comment.tsd-typography": "

    Module comment

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] - } - ] + "section.tsd-panel.tsd-comment": { + "div.tsd-comment.tsd-typography": "

    Module comment

    \n" + } }, { "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", diff --git a/src/test/renderer/specs/modules/ExpandType.NestedBehavior1.json b/src/test/renderer/specs/modules/ExpandType.NestedBehavior1.json index 6f1e2a05b..c78078397 100644 --- a/src/test/renderer/specs/modules/ExpandType.NestedBehavior1.json +++ b/src/test/renderer/specs/modules/ExpandType.NestedBehavior1.json @@ -36,11 +36,6 @@ } ] }, - { - "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": [] - } - }, { "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", "props": { diff --git a/src/test/renderer/specs/types/ExpandType.AExpanded.json b/src/test/renderer/specs/types/ExpandType.AExpanded.json index fa0d5b018..948d80e77 100644 --- a/src/test/renderer/specs/types/ExpandType.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.AExpanded.json @@ -36,11 +36,6 @@ } ] }, - { - "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": [] - } - }, { "div.tsd-signature": [ { @@ -291,9 +286,6 @@ }, { "div.tsd-comment.tsd-typography": "

    A

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } diff --git a/src/test/renderer/specs/types/ExpandType.BExpanded.json b/src/test/renderer/specs/types/ExpandType.BExpanded.json index 232327a24..5ff4ad414 100644 --- a/src/test/renderer/specs/types/ExpandType.BExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.BExpanded.json @@ -338,9 +338,6 @@ }, { "div.tsd-comment.tsd-typography": "

    B

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } diff --git a/src/test/renderer/specs/types/ExpandType.Expandable.json b/src/test/renderer/specs/types/ExpandType.Expandable.json index 89de6658c..3415947d4 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable.json @@ -187,9 +187,6 @@ { "div.tsd-comment.tsd-typography": "

    A

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/types/ExpandType.Expandable2.json b/src/test/renderer/specs/types/ExpandType.Expandable2.json index efcacd043..4352329a9 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable2.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable2.json @@ -187,9 +187,6 @@ { "div.tsd-comment.tsd-typography": "

    C

    \n" }, - { - "div.tsd-comment.tsd-typography": [] - }, { "aside.tsd-sources": { "ul": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json index 922d86eae..dc8d54c08 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json @@ -45,11 +45,6 @@ } ] }, - { - "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": [] - } - }, { "div.tsd-signature": [ { @@ -352,9 +347,6 @@ }, { "div.tsd-comment.tsd-typography": "

    B

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json index bcb57d04b..6d9e9baa2 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json @@ -295,9 +295,6 @@ }, { "div.tsd-comment.tsd-typography": "

    A

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } @@ -379,9 +376,6 @@ }, { "div.tsd-comment.tsd-typography": "

    B

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } @@ -463,9 +457,6 @@ }, { "div.tsd-comment.tsd-typography": "

    C

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } diff --git a/src/test/renderer/specs/types/Nested.json b/src/test/renderer/specs/types/Nested.json index 5778fa04a..1e79630df 100644 --- a/src/test/renderer/specs/types/Nested.json +++ b/src/test/renderer/specs/types/Nested.json @@ -26,14 +26,9 @@ ] }, { - "section.tsd-panel.tsd-comment": [ - { - "div.tsd-comment.tsd-typography": "

    Type alias with nested properties

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] - } - ] + "section.tsd-panel.tsd-comment": { + "div.tsd-comment.tsd-typography": "

    Type alias with nested properties

    \n" + } }, { "div.tsd-signature": [ @@ -389,9 +384,6 @@ }, { "div.tsd-comment.tsd-typography": "

    Another value

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] }, @@ -445,9 +437,6 @@ }, { "div.tsd-comment.tsd-typography": "

    More options

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] }, @@ -471,9 +460,6 @@ }, { "div.tsd-comment.tsd-typography": "

    Value

    \n" - }, - { - "div.tsd-comment.tsd-typography": [] } ] } diff --git a/src/test/utils.ts b/src/test/utils.ts index 1830ef414..40b801487 100644 --- a/src/test/utils.ts +++ b/src/test/utils.ts @@ -60,7 +60,7 @@ export function querySig( ): SignatureReflection { const decl = query(project, name); ok( - decl.signatures?.length ?? 0 > index, + (decl.signatures?.length ?? 0) > index, `Reflection "${name}" does not contain signature`, ); return decl.signatures![index]; From bfed02dbb36c0cb0d0fb508da913c89e6ff2a0b6 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 20:29:08 -0600 Subject: [PATCH 25/46] Upgrade deps --- package.json | 12 +- pnpm-lock.yaml | 438 ++++++++++++++++++++++++------------------------- 2 files changed, 225 insertions(+), 225 deletions(-) diff --git a/package.json b/package.json index 970aeb368..a1139a432 100644 --- a/package.json +++ b/package.json @@ -31,17 +31,17 @@ "pnpm": ">= 10" }, "dependencies": { - "@gerrit0/mini-shiki": "^3.9.0", + "@gerrit0/mini-shiki": "^3.12.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", - "yaml": "^2.8.0" + "yaml": "^2.8.1" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" }, "devDependencies": { - "@eslint/js": "^9.32.0", + "@eslint/js": "^9.34.0", "@types/lunr": "^2.3.7", "@types/markdown-it": "^14.1.2", "@types/mocha": "^10.0.10", @@ -49,12 +49,12 @@ "@typestrong/fs-fixture-builder": "github:TypeStrong/fs-fixture-builder#34113409e3a171e68ce5e2b55461ef5c35591cfe", "c8": "^10.1.3", "dprint": "^0.50.1", - "esbuild": "^0.25.8", + "esbuild": "^0.25.9", "eslint": "^9.34.0", "mocha": "^11.7.1", - "puppeteer": "^24.11.1", + "puppeteer": "^24.17.1", "semver": "^7.7.2", - "tsx": "^4.20.3", + "tsx": "^4.20.5", "typescript": "5.9.2", "typescript-eslint": "^8.41.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f20c82e1e..b2ad20010 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@gerrit0/mini-shiki': - specifier: ^3.9.0 - version: 3.9.0 + specifier: ^3.12.0 + version: 3.12.0 lunr: specifier: ^2.3.9 version: 2.3.9 @@ -21,12 +21,12 @@ importers: specifier: ^9.0.5 version: 9.0.5 yaml: - specifier: ^2.8.0 - version: 2.8.0 + specifier: ^2.8.1 + version: 2.8.1 devDependencies: '@eslint/js': - specifier: ^9.32.0 - version: 9.32.0 + specifier: ^9.34.0 + version: 9.34.0 '@types/lunr': specifier: ^2.3.7 version: 2.3.7 @@ -49,29 +49,29 @@ importers: specifier: ^0.50.1 version: 0.50.1 esbuild: - specifier: ^0.25.8 - version: 0.25.8 + specifier: ^0.25.9 + version: 0.25.9 eslint: - specifier: ^9.32.0 - version: 9.32.0 + specifier: ^9.34.0 + version: 9.34.0 mocha: specifier: ^11.7.1 version: 11.7.1 puppeteer: - specifier: ^24.11.1 - version: 24.11.1(typescript@5.9.2) + specifier: ^24.17.1 + version: 24.17.1(typescript@5.9.2) semver: specifier: ^7.7.2 version: 7.7.2 tsx: - specifier: ^4.20.3 - version: 4.20.3 + specifier: ^4.20.5 + version: 4.20.5 typescript: specifier: 5.9.2 version: 5.9.2 typescript-eslint: specifier: ^8.41.0 - version: 8.41.0(eslint@9.32.0)(typescript@5.9.2) + version: 8.41.0(eslint@9.34.0)(typescript@5.9.2) packages: @@ -132,158 +132,158 @@ packages: cpu: [x64] os: [win32] - '@esbuild/aix-ppc64@0.25.8': - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.8': - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.8': - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.8': - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.8': - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.8': - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.8': - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.8': - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.8': - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.8': - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.8': - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.8': - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.8': - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.8': - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.8': - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.8': - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.8': - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.8': - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.8': - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.8': - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.8': - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.8': - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.8': - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.8': - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.8': - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.8': - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -302,32 +302,32 @@ packages: resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.3.0': - resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==} + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.15.1': - resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.32.0': - resolution: {integrity: sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==} + '@eslint/js@9.34.0': + resolution: {integrity: sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.3.4': - resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@gerrit0/mini-shiki@3.9.0': - resolution: {integrity: sha512-p58r5PE/hIKtE7aYzeDYZr4DPrOidwoUFPX3p6rPEZWtb7zWX3b7Bu9LZ17XODFiRO4x/VzTE15KYNEaZ3khuw==} + '@gerrit0/mini-shiki@3.12.0': + resolution: {integrity: sha512-CF1vkfe2ViPtmoFEvtUWilEc4dOCiFzV8+J7/vEISSsslKQ97FjeTPNMCqUhZEiKySmKRgK3UO/CxtkyOp7DvA==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -383,22 +383,22 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@puppeteer/browsers@2.10.5': - resolution: {integrity: sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==} + '@puppeteer/browsers@2.10.8': + resolution: {integrity: sha512-f02QYEnBDE0p8cteNoPYHHjbDuwyfbe4cCIVlNi8/MRicIxFW4w4CfgU0LNgWEID6s06P+hRJ1qjpBLMhPRCiQ==} engines: {node: '>=18'} hasBin: true - '@shikijs/engine-oniguruma@3.9.1': - resolution: {integrity: sha512-WPlL/xqviwS3te4unSGGGfflKsuHLMI6tPdNYvgz/IygcBT6UiwDFSzjBKyebwi5GGSlXsjjdoJLIBnAplmEZw==} + '@shikijs/engine-oniguruma@3.12.0': + resolution: {integrity: sha512-IfDl3oXPbJ/Jr2K8mLeQVpnF+FxjAc7ZPDkgr38uEw/Bg3u638neSrpwqOTnTHXt1aU0Fk1/J+/RBdst1kVqLg==} - '@shikijs/langs@3.9.1': - resolution: {integrity: sha512-Vyy2Yv9PP3Veh3VSsIvNncOR+O93wFsNYgN2B6cCCJlS7H9SKFYc55edsqernsg8WT/zam1cfB6llJsQWLnVhA==} + '@shikijs/langs@3.12.0': + resolution: {integrity: sha512-HIca0daEySJ8zuy9bdrtcBPhcYBo8wR1dyHk1vKrOuwDsITtZuQeGhEkcEfWc6IDyTcom7LRFCH6P7ljGSCEiQ==} - '@shikijs/themes@3.9.1': - resolution: {integrity: sha512-zAykkGECNICCMXpKeVvq04yqwaSuAIvrf8MjsU5bzskfg4XreU+O0B5wdNCYRixoB9snd3YlZ373WV5E/g5T9A==} + '@shikijs/themes@3.12.0': + resolution: {integrity: sha512-/lxvQxSI5s4qZLV/AuFaA4Wt61t/0Oka/P9Lmpr1UV+HydNCczO3DMHOC/CsXCCpbv4Zq8sMD0cDa7mvaVoj0Q==} - '@shikijs/types@3.9.1': - resolution: {integrity: sha512-rqM3T7a0iM1oPKz9iaH/cVgNX9Vz1HERcUcXJ94/fulgVdwqfnhXzGxO4bLrAnh/o5CPLy3IcYedogfV+Ns0Qg==} + '@shikijs/types@3.12.0': + resolution: {integrity: sha512-jsFzm8hCeTINC3OCmTZdhR9DOl/foJWplH2Px0bTi4m8z59fnsueLsweX82oGcjRQ7mfQAluQYKGoH2VzsWY4A==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -628,8 +628,8 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chromium-bidi@5.1.0: - resolution: {integrity: sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==} + chromium-bidi@8.0.0: + resolution: {integrity: sha512-d1VmE0FD7lxZQHzcDUCKZSNRtRwISXDsdg4HjdTR5+Ll5nQ/vzU12JeNmupD6VWffrPSlrnGhEWlLESKH3VO+g==} peerDependencies: devtools-protocol: '*' @@ -687,8 +687,8 @@ packages: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} engines: {node: '>= 14'} - devtools-protocol@0.0.1464554: - resolution: {integrity: sha512-CAoP3lYfwAGQTaAXYvA6JZR0fjGUb7qec1qf4mToyoH2TZgUFeIqYcjh6f9jNuhHfuZiEdH+PONHYrLhRQX6aw==} + devtools-protocol@0.0.1475386: + resolution: {integrity: sha512-RQ809ykTfJ+dgj9bftdeL2vRVxASAuGU+I9LEx9Ij5TXU5HrgAQVmzi72VA+mkzscE12uzlRv5/tWWv9R9J1SA==} diff@7.0.0: resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} @@ -721,8 +721,8 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} hasBin: true @@ -751,8 +751,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.32.0: - resolution: {integrity: sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==} + eslint@9.34.0: + resolution: {integrity: sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1149,12 +1149,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - puppeteer-core@24.11.1: - resolution: {integrity: sha512-I0Gv3jWBRY9E3NTBElp7br7Gaid5RbFTxCRRMHym1kCf0ompO0Pel4REGsGDwMWkg3uwFzIH7t7qXs3T4DKRWA==} + puppeteer-core@24.17.1: + resolution: {integrity: sha512-Msh/kf9k1XFN0wuKiT4/npMmMWOT7kPBEUw01gWvRoKOOoz3It9TEmWjnt4Gl4eO+p73VMrvR+wfa0dm9rfxjw==} engines: {node: '>=18'} - puppeteer@24.11.1: - resolution: {integrity: sha512-QbccB/LgxX4tSZRzr9KQ1Jajdvu3n35Dlf/Otjz0QfR+6mDoZdMWLcWF94uQoC3OJerCyYm5hlU2Ru4nBoId2A==} + puppeteer@24.17.1: + resolution: {integrity: sha512-KIuX0w+0um4TUbm55yFl2WIsbgjya2BHIgW9ylTuhavtwjXCOM7lMo9oLR1jQnCxrFvm9h/Yeb+zfs4nlgntPg==} engines: {node: '>=18'} hasBin: true @@ -1259,8 +1259,8 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - tar-fs@3.0.10: - resolution: {integrity: sha512-C1SwlQGNLe/jPNqapK8epDsXME7CAJR5RL3GcE6KWx1d9OUByzoHVcbu1VPI8tevg9H8Alae0AApHHFGzrD5zA==} + tar-fs@3.1.0: + resolution: {integrity: sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==} tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} @@ -1285,8 +1285,8 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.20.3: - resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + tsx@4.20.5: + resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==} engines: {node: '>=18.0.0'} hasBin: true @@ -1361,8 +1361,8 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yaml@2.8.0: - resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} hasBin: true @@ -1427,87 +1427,87 @@ snapshots: '@dprint/win32-x64@0.50.1': optional: true - '@esbuild/aix-ppc64@0.25.8': + '@esbuild/aix-ppc64@0.25.9': optional: true - '@esbuild/android-arm64@0.25.8': + '@esbuild/android-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.25.8': + '@esbuild/android-arm@0.25.9': optional: true - '@esbuild/android-x64@0.25.8': + '@esbuild/android-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.25.8': + '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/darwin-x64@0.25.8': + '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.25.8': + '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-x64@0.25.8': + '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.25.8': + '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-arm@0.25.8': + '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-ia32@0.25.8': + '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-loong64@0.25.8': + '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-mips64el@0.25.8': + '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/linux-ppc64@0.25.8': + '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/linux-riscv64@0.25.8': + '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/linux-s390x@0.25.8': + '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/linux-x64@0.25.8': + '@esbuild/linux-x64@0.25.9': optional: true - '@esbuild/netbsd-arm64@0.25.8': + '@esbuild/netbsd-arm64@0.25.9': optional: true - '@esbuild/netbsd-x64@0.25.8': + '@esbuild/netbsd-x64@0.25.9': optional: true - '@esbuild/openbsd-arm64@0.25.8': + '@esbuild/openbsd-arm64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.25.8': + '@esbuild/openbsd-x64@0.25.9': optional: true - '@esbuild/openharmony-arm64@0.25.8': + '@esbuild/openharmony-arm64@0.25.9': optional: true - '@esbuild/sunos-x64@0.25.8': + '@esbuild/sunos-x64@0.25.9': optional: true - '@esbuild/win32-arm64@0.25.8': + '@esbuild/win32-arm64@0.25.9': optional: true - '@esbuild/win32-ia32@0.25.8': + '@esbuild/win32-ia32@0.25.9': optional: true - '@esbuild/win32-x64@0.25.8': + '@esbuild/win32-x64@0.25.9': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0)': + '@eslint-community/eslint-utils@4.7.0(eslint@9.34.0)': dependencies: - eslint: 9.32.0 + eslint: 9.34.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -1520,9 +1520,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.3.0': {} + '@eslint/config-helpers@0.3.1': {} - '@eslint/core@0.15.1': + '@eslint/core@0.15.2': dependencies: '@types/json-schema': 7.0.15 @@ -1540,21 +1540,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.32.0': {} + '@eslint/js@9.34.0': {} '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.3.4': + '@eslint/plugin-kit@0.3.5': dependencies: - '@eslint/core': 0.15.1 + '@eslint/core': 0.15.2 levn: 0.4.1 - '@gerrit0/mini-shiki@3.9.0': + '@gerrit0/mini-shiki@3.12.0': dependencies: - '@shikijs/engine-oniguruma': 3.9.1 - '@shikijs/langs': 3.9.1 - '@shikijs/themes': 3.9.1 - '@shikijs/types': 3.9.1 + '@shikijs/engine-oniguruma': 3.12.0 + '@shikijs/langs': 3.12.0 + '@shikijs/themes': 3.12.0 + '@shikijs/types': 3.12.0 '@shikijs/vscode-textmate': 10.0.2 '@humanfs/core@0.19.1': {} @@ -1605,33 +1605,33 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@puppeteer/browsers@2.10.5': + '@puppeteer/browsers@2.10.8': dependencies: debug: 4.4.1(supports-color@8.1.1) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.5.0 semver: 7.7.2 - tar-fs: 3.0.10 + tar-fs: 3.1.0 yargs: 17.7.2 transitivePeerDependencies: - bare-buffer - supports-color - '@shikijs/engine-oniguruma@3.9.1': + '@shikijs/engine-oniguruma@3.12.0': dependencies: - '@shikijs/types': 3.9.1 + '@shikijs/types': 3.12.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.9.1': + '@shikijs/langs@3.12.0': dependencies: - '@shikijs/types': 3.9.1 + '@shikijs/types': 3.12.0 - '@shikijs/themes@3.9.1': + '@shikijs/themes@3.12.0': dependencies: - '@shikijs/types': 3.9.1 + '@shikijs/types': 3.12.0 - '@shikijs/types@3.9.1': + '@shikijs/types@3.12.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -1674,15 +1674,15 @@ snapshots: '@types/node': 18.19.113 optional: true - '@typescript-eslint/eslint-plugin@8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.41.0(eslint@9.34.0)(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.41.0 - '@typescript-eslint/type-utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.41.0(eslint@9.34.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.34.0)(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.41.0 - eslint: 9.32.0 + eslint: 9.34.0 graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -1691,14 +1691,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/parser@8.41.0(eslint@9.34.0)(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.41.0 '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.41.0 debug: 4.4.1(supports-color@8.1.1) - eslint: 9.32.0 + eslint: 9.34.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -1721,13 +1721,13 @@ snapshots: dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.41.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.41.0(eslint@9.34.0)(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.41.0(eslint@9.34.0)(typescript@5.9.2) debug: 4.4.1(supports-color@8.1.1) - eslint: 9.32.0 + eslint: 9.34.0 ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: @@ -1751,13 +1751,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.41.0(eslint@9.32.0)(typescript@5.9.2)': + '@typescript-eslint/utils@8.41.0(eslint@9.34.0)(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0) '@typescript-eslint/scope-manager': 8.41.0 '@typescript-eslint/types': 8.41.0 '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) - eslint: 9.32.0 + eslint: 9.34.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -1875,9 +1875,9 @@ snapshots: dependencies: readdirp: 4.1.2 - chromium-bidi@5.1.0(devtools-protocol@0.0.1464554): + chromium-bidi@8.0.0(devtools-protocol@0.0.1475386): dependencies: - devtools-protocol: 0.0.1464554 + devtools-protocol: 0.0.1475386 mitt: 3.0.1 zod: 3.25.67 @@ -1930,7 +1930,7 @@ snapshots: escodegen: 2.1.0 esprima: 4.0.1 - devtools-protocol@0.0.1464554: {} + devtools-protocol@0.0.1475386: {} diff@7.0.0: {} @@ -1964,34 +1964,34 @@ snapshots: dependencies: is-arrayish: 0.2.1 - esbuild@0.25.8: + esbuild@0.25.9: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 escalade@3.2.0: {} @@ -2014,16 +2014,16 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.32.0: + eslint@9.34.0: dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.34.0) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 - '@eslint/config-helpers': 0.3.0 - '@eslint/core': 0.15.1 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.32.0 - '@eslint/plugin-kit': 0.3.4 + '@eslint/js': 9.34.0 + '@eslint/plugin-kit': 0.3.5 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -2456,12 +2456,12 @@ snapshots: punycode@2.3.1: {} - puppeteer-core@24.11.1: + puppeteer-core@24.17.1: dependencies: - '@puppeteer/browsers': 2.10.5 - chromium-bidi: 5.1.0(devtools-protocol@0.0.1464554) + '@puppeteer/browsers': 2.10.8 + chromium-bidi: 8.0.0(devtools-protocol@0.0.1475386) debug: 4.4.1(supports-color@8.1.1) - devtools-protocol: 0.0.1464554 + devtools-protocol: 0.0.1475386 typed-query-selector: 2.12.0 ws: 8.18.3 transitivePeerDependencies: @@ -2470,13 +2470,13 @@ snapshots: - supports-color - utf-8-validate - puppeteer@24.11.1(typescript@5.9.2): + puppeteer@24.17.1(typescript@5.9.2): dependencies: - '@puppeteer/browsers': 2.10.5 - chromium-bidi: 5.1.0(devtools-protocol@0.0.1464554) + '@puppeteer/browsers': 2.10.8 + chromium-bidi: 8.0.0(devtools-protocol@0.0.1475386) cosmiconfig: 9.0.0(typescript@5.9.2) - devtools-protocol: 0.0.1464554 - puppeteer-core: 24.11.1 + devtools-protocol: 0.0.1475386 + puppeteer-core: 24.17.1 typed-query-selector: 2.12.0 transitivePeerDependencies: - bare-buffer @@ -2578,7 +2578,7 @@ snapshots: dependencies: has-flag: 4.0.0 - tar-fs@3.0.10: + tar-fs@3.1.0: dependencies: pump: 3.0.3 tar-stream: 3.1.7 @@ -2614,9 +2614,9 @@ snapshots: tslib@2.8.1: {} - tsx@4.20.3: + tsx@4.20.5: dependencies: - esbuild: 0.25.8 + esbuild: 0.25.9 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 @@ -2627,13 +2627,13 @@ snapshots: typed-query-selector@2.12.0: {} - typescript-eslint@8.41.0(eslint@9.32.0)(typescript@5.9.2): + typescript-eslint@8.41.0(eslint@9.34.0)(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.32.0)(typescript@5.9.2))(eslint@9.32.0)(typescript@5.9.2) - '@typescript-eslint/parser': 8.41.0(eslint@9.32.0)(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.41.0(@typescript-eslint/parser@8.41.0(eslint@9.34.0)(typescript@5.9.2))(eslint@9.34.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.41.0(eslint@9.34.0)(typescript@5.9.2) '@typescript-eslint/typescript-estree': 8.41.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.41.0(eslint@9.32.0)(typescript@5.9.2) - eslint: 9.32.0 + '@typescript-eslint/utils': 8.41.0(eslint@9.34.0)(typescript@5.9.2) + eslint: 9.34.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -2680,7 +2680,7 @@ snapshots: y18n@5.0.8: {} - yaml@2.8.0: {} + yaml@2.8.1: {} yargs-parser@21.1.1: {} From 0c3ad25a27b443b7a9048ad740a7461a5d6c2264 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 20:31:39 -0600 Subject: [PATCH 26/46] Fix new ESLint issues --- .../themes/default/partials/member.signature.body.tsx | 2 +- src/lib/output/themes/default/partials/typeDetails.tsx | 8 ++++---- src/lib/utils-common/i18n.ts | 2 +- src/lib/utils/options/readers/arguments.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) 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 f22486924..627721300 100644 --- a/src/lib/output/themes/default/partials/member.signature.body.tsx +++ b/src/lib/output/themes/default/partials/member.signature.body.tsx @@ -25,7 +25,7 @@ export function memberSignatureBody(
  • {context.reflectionFlags(item)} - {!!item.flags.isRest && ...} + {item.flags.isRest && ...} {item.name} {": "} {context.type(item.type)} diff --git a/src/lib/output/themes/default/partials/typeDetails.tsx b/src/lib/output/themes/default/partials/typeDetails.tsx index fbf4a6748..829a81de8 100644 --- a/src/lib/output/themes/default/partials/typeDetails.tsx +++ b/src/lib/output/themes/default/partials/typeDetails.tsx @@ -295,9 +295,9 @@ function renderChild( return (
  • - {!!child.flags.isRest && ...} + {child.flags.isRest && ...} {child.name} - {!!child.flags.isOptional && "?"}: function + {child.flags.isOptional && "?"}: function
    {context.memberSignatures(child)} @@ -325,10 +325,10 @@ function renderChild(
  • {context.reflectionFlags(child)} - {!!child.flags.isRest && ...} + {child.flags.isRest && ...} {child.name} - {!!child.flags.isOptional && "?"} + {child.flags.isOptional && "?"} {": "} {context.type(child.type)} diff --git a/src/lib/utils-common/i18n.ts b/src/lib/utils-common/i18n.ts index 97044c53d..22129a2dc 100644 --- a/src/lib/utils-common/i18n.ts +++ b/src/lib/utils-common/i18n.ts @@ -1,7 +1,7 @@ // Type only import to non-bundled file // eslint-disable-next-line no-restricted-imports -import type { TagString } from "#utils"; import type { TranslationProxy } from "../internationalization/internationalization.js"; +import type { TagString } from "./validation.js"; let translations: Record = {}; diff --git a/src/lib/utils/options/readers/arguments.ts b/src/lib/utils/options/readers/arguments.ts index 9b277d526..2e8dbb3c6 100644 --- a/src/lib/utils/options/readers/arguments.ts +++ b/src/lib/utils/options/readers/arguments.ts @@ -81,7 +81,7 @@ export class ArgumentsReader implements OptionsReader { decl.type === ParameterType.Boolean || decl.type === ParameterType.Flags ) { - const value = String(this.args[index]).toLowerCase(); + const value = String(this.args.at(index)).toLowerCase(); if (value === "true" || value === "false") { trySet(decl.name, value === "true"); @@ -114,7 +114,7 @@ export class ArgumentsReader implements OptionsReader { if (decl && decl.type === ParameterType.Flags) { const flagName = name.split(".", 2)[1]; - const value = String(this.args[index]).toLowerCase(); + const value = String(this.args.at(index)).toLowerCase(); if (value === "true" || value === "false") { trySet(decl.name, { [flagName]: value === "true" }); From 40f17fba3a5073c832e8102c8a7125464b2c28a0 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 31 Aug 2025 20:36:48 -0600 Subject: [PATCH 27/46] Bump version to 0.28.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1139a432..a10ecdb0a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.11", + "version": "0.28.12", "homepage": "https://typedoc.org", "type": "module", "exports": { From b3a4869bcbc054a37d0fbb0bc71339325a26f2ee Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Mon, 1 Sep 2025 02:37:35 +0000 Subject: [PATCH 28/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e5524ac..02338a966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.12 (2025-09-01) + ### Bug Fixes - Variables marked with `@enum` now work for symbols imported from another module, #3003. From 1269e3ab6d169e89724328ada21a14ecaba89525 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Tue, 2 Sep 2025 08:31:10 -0600 Subject: [PATCH 29/46] Make parent links even more restrictive Resolves #3007 --- CHANGELOG.md | 4 + scripts/testcase.js | 3 +- src/lib/converter/plugins/ImplementsPlugin.ts | 9 +- src/test/converter2/renderer/gh3007.ts | 16 + src/test/converter2/renderer/index.ts | 1 + .../specs/classes/GH3007.DOMBase.json | 505 ++++++++++++++++++ .../specs/classes/GH3007.DOMClass.json | 288 ++++++++++ .../specs/interfaces/GH3007.DOMIterable.json | 343 ++++++++++++ src/test/renderer/specs/modules.json | 32 ++ src/test/renderer/specs/modules/GH3007.json | 244 +++++++++ 10 files changed, 1441 insertions(+), 4 deletions(-) create mode 100644 src/test/converter2/renderer/gh3007.ts create mode 100644 src/test/renderer/specs/classes/GH3007.DOMBase.json create mode 100644 src/test/renderer/specs/classes/GH3007.DOMClass.json create mode 100644 src/test/renderer/specs/interfaces/GH3007.DOMIterable.json create mode 100644 src/test/renderer/specs/modules/GH3007.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 02338a966..aa89c3007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ title: Changelog ## Unreleased +### Bug Fixes + +- Fixed bug introduced in 0.28.8 where TypeDoc could not render docs with some mixin classes, #3007. + ## v0.28.12 (2025-09-01) ### Bug Fixes diff --git a/scripts/testcase.js b/scripts/testcase.js index 2a5c0d744..0756dae45 100755 --- a/scripts/testcase.js +++ b/scripts/testcase.js @@ -66,7 +66,8 @@ async function main() { const ext = process.argv[3] ? `.${process.argv[3]}` : guessExtension(code); const file = `src/test/converter2/issues/gh${issue}${ext}`; await writeFile(file, code.content); - await exec(`code ${file} src/test/issues.c2.test.ts`); + console.log(file); + console.log("src/test/issues.c2.test.ts"); } void main(); diff --git a/src/lib/converter/plugins/ImplementsPlugin.ts b/src/lib/converter/plugins/ImplementsPlugin.ts index cab484371..383a4ac2c 100644 --- a/src/lib/converter/plugins/ImplementsPlugin.ts +++ b/src/lib/converter/plugins/ImplementsPlugin.ts @@ -172,10 +172,13 @@ export class ImplementsPlugin extends ConverterComponent { // serialization/deserialization, might point to an unexpected location. (See the mixin // converter tests, I suspect this might actually be an indication of something else slightly // broken there, but don't want to spend more time with this right now.) - // #2982, even more unfortunately, we only want to keep the link if it is pointing to a reflection - // which will receive a link during rendering. + // #2982/#3007, even more unfortunately, we only want to keep the link if it is pointing + // to a reflection which will receive a link during rendering, we pick this based on it being + // the type of member we expect to point to. const isValidRef = (ref: ReferenceType) => - ref.reflection && !ref.reflection.parent?.kindOf(ReflectionKind.TypeLiteral); + !!ref.reflection?.parent?.kindOf( + ReflectionKind.ClassOrInterface | ReflectionKind.Method | ReflectionKind.Constructor, + ); for (const child of reflection.children || []) { if (child.inheritedFrom && !isValidRef(child.inheritedFrom)) { diff --git a/src/test/converter2/renderer/gh3007.ts b/src/test/converter2/renderer/gh3007.ts new file mode 100644 index 000000000..5b00f7d70 --- /dev/null +++ b/src/test/converter2/renderer/gh3007.ts @@ -0,0 +1,16 @@ +interface MixinConstructor U, U> { + new (...args: ConstructorParameters): U; +} + +export declare class DOMBase { + [Symbol.iterator](): Iterator; +} + +export interface DOMIterable extends Partial> { +} + +declare const DOMClass_base: MixinConstructor & object>; + +export declare class DOMClass extends DOMClass_base { + private constructor(); +} diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 4ccad6fcd..05a839724 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -138,4 +138,5 @@ export interface DisabledGroups { export * as ExpandType from "./expandType"; export * as GH2982 from "./gh2982"; export { gh2995 } from "./gh2995"; +export * as GH3007 from "./gh3007"; export { box as boxAlias }; diff --git a/src/test/renderer/specs/classes/GH3007.DOMBase.json b/src/test/renderer/specs/classes/GH3007.DOMBase.json new file mode 100644 index 000000000..18378c675 --- /dev/null +++ b/src/test/renderer/specs/classes/GH3007.DOMBase.json @@ -0,0 +1,505 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": [ + { + "li": { + "tag": "a", + "props": { + "href": "../modules/GH3007.json" + }, + "children": "GH3007" + } + }, + { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "DOMBase" + } + } + ] + }, + { + "h1": "Class DOMBase" + } + ] + }, + { + "section.tsd-panel": [ + { + "h4": "Type Parameters" + }, + { + "ul.tsd-type-parameter-list": { + "li": { + "span#t": [ + { + "span.tsd-kind-type-parameter": "T" + }, + " ", + { + "span.tsd-signature-keyword": "extends" + }, + " ", + { + "span.tsd-signature-type": "Node" + } + ] + } + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:5" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": [ + { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Constructors" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link", + "props": { + "href": "#constructor" + }, + "children": { + "span": "constructor" + } + }, + "\n" + ] + } + ] + }, + { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Methods" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]" + } + }, + "\n" + ] + } + ] + } + ] + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Constructors" + }, + "children": { + "h2": "Constructors" + } + }, + { + "section": { + "section.tsd-panel.tsd-member": [ + { + "h3.tsd-anchor-link#constructor": [ + { + "span": "constructor" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#constructor", + "aria-label": "Permalink" + } + } + ] + }, + { + "ul.tsd-signatures": { + "li.": [ + { + "div.tsd-signature.tsd-anchor-link#constructordombase": [ + { + "span.tsd-signature-keyword": "new" + }, + " ", + { + "span.tsd-kind-constructor-signature": "DOMBase" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#constructordombaset" + }, + "children": "T" + }, + " ", + { + "span.tsd-signature-keyword": "extends" + }, + " ", + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "span.tsd-signature-symbol": "()" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "tag": "a.tsd-signature-type.tsd-kind-class", + "props": { + "href": "" + }, + "children": "DOMBase" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#constructordombaset" + }, + "children": "T" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#constructordombase", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-description": [ + { + "section.tsd-panel": [ + { + "h4": "Type Parameters" + }, + { + "ul.tsd-type-parameter-list": { + "li": { + "span#constructordombaset": [ + { + "span.tsd-kind-type-parameter": "T" + }, + " ", + { + "span.tsd-signature-keyword": "extends" + }, + " ", + { + "span.tsd-signature-type": "Node" + } + ] + } + } + } + ] + }, + { + "h4.tsd-returns-title": [ + "Returns ", + { + "tag": "a.tsd-signature-type.tsd-kind-class", + "props": { + "href": "" + }, + "children": "DOMBase" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#constructordombaset" + }, + "children": "T" + }, + { + "span.tsd-signature-symbol": ">" + } + ] + } + ] + } + ] + } + } + ] + } + } + ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": { + "h2": "Methods" + } + }, + { + "section": { + "section.tsd-panel.tsd-member": [ + { + "h3.tsd-anchor-link#iterator": [ + { + "span": "[iterator]" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#iterator", + "aria-label": "Permalink" + } + } + ] + }, + { + "ul.tsd-signatures": { + "li.": [ + { + "div.tsd-signature.tsd-anchor-link#iterator-1": [ + { + "span.tsd-kind-call-signature": "\"[iterator]\"" + }, + { + "span.tsd-signature-symbol": "()" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#constructordombaset" + }, + "children": "T" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#iterator-1", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-description": [ + { + "h4.tsd-returns-title": [ + "Returns ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-type-parameter", + "props": { + "href": "#constructordombaset" + }, + "children": "T" + }, + { + "span.tsd-signature-symbol": ">" + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:6" + } + ] + } + } + } + ] + } + ] + } + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": [ + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Constructors" + }, + "children": "Constructors" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#constructor" + }, + "children": { + "span": "constructor" + } + } + } + ] + }, + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": "Methods" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]" + } + } + } + ] + } + ] + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/classes/GH3007.DOMClass.json b/src/test/renderer/specs/classes/GH3007.DOMClass.json new file mode 100644 index 000000000..8bfe89f19 --- /dev/null +++ b/src/test/renderer/specs/classes/GH3007.DOMClass.json @@ -0,0 +1,288 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": [ + { + "li": { + "tag": "a", + "props": { + "href": "../modules/GH3007.json" + }, + "children": "GH3007" + } + }, + { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "DOMClass" + } + } + ] + }, + { + "h1": "Class DOMClass" + } + ] + }, + { + "tag": "section.tsd-panel.tsd-hierarchy", + "props": { + "data-refl": "146" + }, + "children": [ + { + "h4": "Hierarchy" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": [ + { + "span.tsd-signature-type": "DOMClass_base" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": { + "span.tsd-hierarchy-target": "DOMClass" + } + } + } + ] + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:14" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Methods" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link.tsd-is-inherited", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]" + } + }, + "\n" + ] + } + ] + } + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": { + "h2": "Methods" + } + }, + { + "section": { + "section.tsd-panel.tsd-member.tsd-is-inherited": [ + { + "h3.tsd-anchor-link#iterator": [ + { + "span": "[iterator]" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#iterator", + "aria-label": "Permalink" + } + } + ] + }, + { + "ul.tsd-signatures.tsd-is-inherited": { + "li.tsd-is-inherited": [ + { + "div.tsd-signature.tsd-anchor-link#iterator-1": [ + { + "span.tsd-kind-call-signature": "\"[iterator]\"" + }, + { + "span.tsd-signature-symbol": "()" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#iterator-1", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-description": [ + { + "h4.tsd-returns-title": [ + "Returns ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + } + ] + }, + { + "aside.tsd-sources": [ + { + "p": "Inherited from DOMClass_base.[iterator]" + }, + { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:6" + } + ] + } + } + ] + } + ] + } + ] + } + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Methods" + }, + "children": "Methods" + }, + { + "div": { + "tag": "a.tsd-is-inherited", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]" + } + } + } + ] + } + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/interfaces/GH3007.DOMIterable.json b/src/test/renderer/specs/interfaces/GH3007.DOMIterable.json new file mode 100644 index 000000000..e907f6478 --- /dev/null +++ b/src/test/renderer/specs/interfaces/GH3007.DOMIterable.json @@ -0,0 +1,343 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": [ + { + "li": { + "tag": "a", + "props": { + "href": "../modules/GH3007.json" + }, + "children": "GH3007" + } + }, + { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "DOMIterable" + } + } + ] + }, + { + "h1": "Interface DOMIterable" + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-signature-keyword": "interface" + }, + " ", + { + "span.tsd-kind-interface": "DOMIterable" + }, + " ", + { + "span.tsd-signature-symbol": "{" + }, + { + "br": [] + }, + " ", + { + "tag": "a.tsd-kind-property", + "props": { + "href": "#iterator" + }, + "children": "\"[iterator]\"" + }, + { + "span.tsd-signature-symbol": "?:" + }, + " ", + { + "span.tsd-signature-symbol": "()" + }, + " ", + { + "span.tsd-signature-symbol": "=>" + }, + " ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "span.tsd-signature-symbol": ";" + }, + { + "br": [] + }, + { + "span.tsd-signature-symbol": "}" + } + ] + }, + { + "tag": "section.tsd-panel.tsd-hierarchy", + "props": { + "data-refl": "142" + }, + "children": [ + { + "h4": "Hierarchy" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": [ + { + "span.tsd-signature-type": "Partial" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "tag": "a.tsd-signature-type.tsd-kind-class", + "props": { + "href": "../classes/GH3007.DOMBase.json" + }, + "children": "DOMBase" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "span.tsd-signature-symbol": ">" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": { + "span.tsd-hierarchy-target": "DOMIterable" + } + } + } + ] + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:9" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Properties" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link.tsd-is-inherited", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]?" + } + }, + "\n" + ] + } + ] + } + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Properties" + }, + "children": { + "h2": "Properties" + } + }, + { + "section": { + "section.tsd-panel.tsd-member.tsd-is-inherited": [ + { + "h3.tsd-anchor-link#iterator": [ + { + "code.tsd-tag": "Optional" + }, + { + "span": "[iterator]" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#iterator", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-signature": [ + { + "span.tsd-kind-property": "\"[iterator]\"" + }, + { + "span.tsd-signature-symbol": "?:" + }, + " ", + { + "span.tsd-signature-symbol": "()" + }, + " ", + { + "span.tsd-signature-symbol": "=>" + }, + " ", + { + "span.tsd-signature-type": "Iterator" + }, + { + "span.tsd-signature-symbol": "<" + }, + { + "span.tsd-signature-type": "Node" + }, + { + "span.tsd-signature-symbol": ">" + } + ] + }, + { + "aside.tsd-sources": [ + { + "p": "Inherited from Partial.[iterator]" + }, + { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3007.ts" + }, + "children": "gh3007.ts:6" + } + ] + } + } + ] + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Properties" + }, + "children": "Properties" + }, + { + "div": { + "tag": "a.tsd-is-inherited", + "props": { + "href": "#iterator" + }, + "children": { + "span": "[iterator]" + } + } + } + ] + } + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index 35cc03b77..a11456c96 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -124,6 +124,29 @@ ] } }, + { + "dd.tsd-member-summary": [] + }, + { + "dt.tsd-member-summary#gh3007": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "modules/GH3007.json" + }, + "children": "GH3007" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#gh3007", + "aria-label": "Permalink" + } + } + ] + } + }, { "dd.tsd-member-summary": [] } @@ -666,6 +689,15 @@ "children": { "span": "GH2982" } + }, + { + "tag": "a", + "props": { + "href": "#gh3007" + }, + "children": { + "span": "GH3007" + } } ] } diff --git a/src/test/renderer/specs/modules/GH3007.json b/src/test/renderer/specs/modules/GH3007.json new file mode 100644 index 000000000..f409f158f --- /dev/null +++ b/src/test/renderer/specs/modules/GH3007.json @@ -0,0 +1,244 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "GH3007" + } + } + }, + { + "h1": "Namespace GH3007" + } + ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Classes" + }, + "children": { + "h2": "Classes" + } + }, + { + "dl.tsd-member-summaries": [ + { + "dt.tsd-member-summary#dombase": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "../classes/GH3007.DOMBase.json" + }, + "children": "DOMBase" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#dombase", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + }, + { + "dt.tsd-member-summary#domclass": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "../classes/GH3007.DOMClass.json" + }, + "children": "DOMClass" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#domclass", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + } + ] + } + ] + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Interfaces" + }, + "children": { + "h2": "Interfaces" + } + }, + { + "dl.tsd-member-summaries": [ + { + "dt.tsd-member-summary#domiterable": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "../interfaces/GH3007.DOMIterable.json" + }, + "children": "DOMIterable" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#domiterable", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + } + ] + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": [ + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Classes" + }, + "children": "Classes" + }, + { + "div": [ + { + "tag": "a", + "props": { + "href": "#dombase" + }, + "children": { + "span": [ + "DOM", + { + "wbr": [] + }, + "Base" + ] + } + }, + { + "tag": "a", + "props": { + "href": "#domclass" + }, + "children": { + "span": [ + "DOM", + { + "wbr": [] + }, + "Class" + ] + } + } + ] + } + ] + }, + { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Interfaces" + }, + "children": "Interfaces" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#domiterable" + }, + "children": { + "span": [ + "DOM", + { + "wbr": [] + }, + "Iterable" + ] + } + } + } + ] + } + ] + } + ] + } + } + } + ] +} From e0fd143143f10538f32c63487e6bae953ac06d54 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Sat, 6 Sep 2025 02:52:19 -0700 Subject: [PATCH 30/46] docs(tags): fix link to packageDocumentation This link was broken. --- site/tags/packageDocumentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/tags/packageDocumentation.md b/site/tags/packageDocumentation.md index eac3d3690..f1e54c5d6 100644 --- a/site/tags/packageDocumentation.md +++ b/site/tags/packageDocumentation.md @@ -5,7 +5,7 @@ title: "@packageDocumentation" # @packageDocumentation **Tag Kind:** [Modifier](../tags.md#modifier-tags)
    -**TSDoc Reference:** [@packageDocumentation](https://tsdoc.org/pages/tags/packageDocumentation/) +**TSDoc Reference:** [@packageDocumentation](https://tsdoc.org/pages/tags/packagedocumentation/) The `@packageDocumentation` tag is used to mark a comment as referring to a file rather than the declaration following it. The TypeDoc specific [`@module`](module.md) tag can be used for the same purpose when semantically clearer. From 8f94288e5d46a37847dfd9527966e4a64076b548 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 13 Sep 2025 10:52:24 -0600 Subject: [PATCH 31/46] Fix #3012 --- CHANGELOG.md | 1 + src/lib/converter/comments/parser.ts | 7 +++++++ src/lib/converter/plugins/InheritDocPlugin.ts | 2 ++ src/lib/internationalization/locales/en.cts | 2 ++ src/test/converter2/issues/gh3012.ts | 12 ++++++++++++ src/test/issues.c2.test.ts | 9 +++++++++ 6 files changed, 33 insertions(+) create mode 100644 src/test/converter2/issues/gh3012.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index aa89c3007..d907c6674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ title: Changelog ### Bug Fixes - Fixed bug introduced in 0.28.8 where TypeDoc could not render docs with some mixin classes, #3007. +- `@inheritDoc` will now correctly overwrite `@remarks` and `@returns` blocks on the target comment, #3012. ## v0.28.12 (2025-09-01) diff --git a/src/lib/converter/comments/parser.ts b/src/lib/converter/comments/parser.ts index 924054b77..5d2adeb49 100644 --- a/src/lib/converter/comments/parser.ts +++ b/src/lib/converter/comments/parser.ts @@ -346,6 +346,13 @@ function postProcessComment( ), ); } + if ((inlineInheritDoc.length || inheritDoc.length) && returns.length) { + warning( + i18n.content_in_returns_block_overwritten_by_inheritdoc_in_comment_at_0( + getPosition(), + ), + ); + } } const aliasedTags = new Map([["@return", "@returns"]]); diff --git a/src/lib/converter/plugins/InheritDocPlugin.ts b/src/lib/converter/plugins/InheritDocPlugin.ts index 56b53409c..b9763e65f 100644 --- a/src/lib/converter/plugins/InheritDocPlugin.ts +++ b/src/lib/converter/plugins/InheritDocPlugin.ts @@ -150,6 +150,8 @@ export class InheritDocPlugin extends ConverterComponent { } target.comment.removeTags("@inheritDoc"); + target.comment.removeTags("@remarks"); + target.comment.removeTags("@returns"); target.comment.summary = Comment.cloneDisplayParts( source.comment.summary, ); diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index 301cbf806..db746e7bd 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -81,6 +81,8 @@ export = { "Content in the summary section will be overwritten by the @inheritDoc tag in comment at {0}", content_in_remarks_block_overwritten_by_inheritdoc_in_comment_at_0: "Content in the @remarks block will be overwritten by the @inheritDoc tag in comment at {0}", + content_in_returns_block_overwritten_by_inheritdoc_in_comment_at_0: + "Content in the @returns block will be overwritten by the @inheritDoc tag in comment at {0}", example_tag_literal_name: "The first line of an example tag will be taken literally as the example name, and should only contain text", inheritdoc_tag_properly_capitalized: "The @inheritDoc tag should be properly capitalized", diff --git a/src/test/converter2/issues/gh3012.ts b/src/test/converter2/issues/gh3012.ts new file mode 100644 index 000000000..6a226968d --- /dev/null +++ b/src/test/converter2/issues/gh3012.ts @@ -0,0 +1,12 @@ +/** + * @remarks DictRemarks + */ +export const DictionarySchema = {}; + +/** + * {@inheritDoc DictionarySchema} + * + * @remarks + * Alias of {@link DictionarySchema} + */ +export const NullProtoObjectSchema = DictionarySchema; diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 87f894055..c645ff455 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2182,4 +2182,13 @@ describe("Issue Tests", () => { ok(x.comment.summary[1].target); ok(project.files.resolve(x.comment.summary[1].target, project) === doc); }); + + it("#3012 removes @remarks from inheriting comment", () => { + const project = convert(); + const nullProto = query(project, "NullProtoObjectSchema"); + equal(nullProto.comment?.blockTags.map(t => t.tag), ["@remarks"]); + equal(nullProto.comment?.blockTags.map(t => Comment.combineDisplayParts(t.content)), ["DictRemarks"]); + + logger.expectMessage("warn: Content in the @remarks block will be overwritten*"); + }); }); From 12a3f3aacf434a320c8db7852c8b7826cea94538 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 13 Sep 2025 10:56:53 -0600 Subject: [PATCH 32/46] Fix tests --- src/test/converter/inheritance/inherit-doc.ts | 1 - src/test/converter/inheritance/specs.json | 17 ++++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/test/converter/inheritance/inherit-doc.ts b/src/test/converter/inheritance/inherit-doc.ts index 6e0c495d2..09a330282 100644 --- a/src/test/converter/inheritance/inherit-doc.ts +++ b/src/test/converter/inheritance/inherit-doc.ts @@ -71,7 +71,6 @@ export function functionSource(arg1: T, arg2: T): string { * @typeParam T - This will be inherited * @param arg1 - This will be inherited * @param arg2 - This will be inherited - * @returns This will be inherited */ export function functionTargetLocal(arg1: T, arg2: T) { return ""; diff --git a/src/test/converter/inheritance/specs.json b/src/test/converter/inheritance/specs.json index 4e458b53e..8bb200c3e 100644 --- a/src/test/converter/inheritance/specs.json +++ b/src/test/converter/inheritance/specs.json @@ -466,9 +466,9 @@ "sources": [ { "fileName": "inherit-doc.ts", - "line": 76, + "line": 75, "character": 16, - "url": "typedoc://inherit-doc.ts#L76" + "url": "typedoc://inherit-doc.ts#L75" } ], "signatures": [ @@ -504,15 +504,6 @@ } ] }, - { - "tag": "@returns", - "content": [ - { - "kind": "text", - "text": "This will be inherited" - } - ] - }, { "tag": "@returns", "content": [ @@ -527,9 +518,9 @@ "sources": [ { "fileName": "inherit-doc.ts", - "line": 76, + "line": 75, "character": 16, - "url": "typedoc://inherit-doc.ts#L76" + "url": "typedoc://inherit-doc.ts#L75" } ], "typeParameters": [ From 3b84d2db017d8fd7803e8195200af4f84d69657f Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 13 Sep 2025 11:53:21 -0600 Subject: [PATCH 33/46] Use basePath option for relative links Resolves #3009 --- CHANGELOG.md | 6 +++ index.html | 6 --- site/declaration-references.md | 8 ++-- site/options.md | 2 +- site/options/input.md | 20 +++++++--- site/options/output.md | 7 ++-- site/options/package-options.md | 3 +- src/lib/application.ts | 10 ++++- src/lib/converter/plugins/SourcePlugin.ts | 9 +++-- src/lib/internationalization/locales/en.cts | 4 +- src/lib/utils/ValidatingFileRegistry.ts | 22 +++++++++-- src/lib/utils/entry-point.ts | 5 ++- src/lib/utils/options/declaration.ts | 3 +- src/lib/utils/options/sources/typedoc.ts | 43 +++++++++------------ src/test/converter2/issues/gh3009.ts | 7 ++++ src/test/issues.c2.test.ts | 20 +++++++++- src/test/programs.ts | 2 +- 17 files changed, 118 insertions(+), 59 deletions(-) delete mode 100644 index.html create mode 100644 src/test/converter2/issues/gh3009.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d907c6674..f97e2d1b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ title: Changelog ## Unreleased +### Features + +- The `basePath` option now also affects relative link resolution, TypeDoc will also check for + paths relative to the provided base path. If you instead want TypeDoc to only change the rendered + base path for sources, use the `displayBasePath` option, #3009. + ### Bug Fixes - Fixed bug introduced in 0.28.8 where TypeDoc could not render docs with some mixin classes, #3007. diff --git a/index.html b/index.html deleted file mode 100644 index cf7ca8870..000000000 --- a/index.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - Wagtail - - diff --git a/site/declaration-references.md b/site/declaration-references.md index 18ed72494..d0213666c 100644 --- a/site/declaration-references.md +++ b/site/declaration-references.md @@ -4,10 +4,10 @@ title: Declaration References # Declaration References -> [!note] -> If [--useTsLinkResolution](options/comments.md#usetslinkresolution) is turned on (the default) this page likely -> **does not apply** for your links. Declaration references are used only if that option is off or TypeScript -> fails to resolve a link. +> [!note] If [--useTsLinkResolution](options/comments.md#usetslinkresolution) is turned on (the default) this page +> likely **does not apply** for your links within comments (though it will be used for +> [external documents](./external-documents.md) and for the readme file). Declaration references are used only if that option is +> off or TypeScript fails to resolve a link. Some tags like [`{@link}`](tags/link.md) and [`{@inheritDoc}`](tags/inheritDoc.md) can refer to other members of the documentation. These tags use declaration references to name another declaration. diff --git a/site/options.md b/site/options.md index 8d39b3642..b5b3b9782 100644 --- a/site/options.md +++ b/site/options.md @@ -35,7 +35,7 @@ Options which control TypeDoc's HTML output. ## Comment Options -Options which control how TypeDoc parses comments. +Options which control how TypeDoc parses comments and documents. {@listOptions options/comments.md} diff --git a/site/options/input.md b/site/options/input.md index e7bdaf311..fbfdbf9a3 100644 --- a/site/options/input.md +++ b/site/options/input.md @@ -35,7 +35,7 @@ If a `"typedoc"` [conditional export](https://nodejs.org/api/packages.html#condi TypeDoc will use it instead of the `"import"` export condition. The set of entry points provided to TypeDoc determines the names displayed in the documentation. -By default, TypeDoc will derive a [basePath](output.md#basepath) based on your entry point +By default, TypeDoc will derive a [displayBasePath](output.md#displaybasepath) based on your entry point paths to determine the displayed module name, but it can be also be set with the [`@module`](../tags/module.md) tag. ## entryPointStrategy @@ -311,7 +311,8 @@ If you are updating documentation for a forked package, you probably want to pas typedoc --disableGit ``` -Prevents TypeDoc from using Git to try to determine if sources can be linked, with this enabled, sources will always be linked, even if not part of a git repo. +Prevents TypeDoc from using Git to try to determine if sources can be linked, with this enabled, sources will always be +linked, even if not part of a git repo. ## readme @@ -319,6 +320,15 @@ Prevents TypeDoc from using Git to try to determine if sources can be linked, wi typedoc --readme ``` -Path to the readme file that should be displayed on the index page. If set to -`none`, or no readme file is automatically discovered, the index page will be -disabled. +Path to the readme file that should be displayed on the index page. If set to `none`, or no readme file is automatically +discovered, the index page will be disabled. + +## basePath + +```bash +typedoc --basePath ./ +``` + +Path to a directory containing asset files which will be checked when resolving relative paths of links and images +within documentation comments and external documents. If specified, this will also be used for the default value of +the [displayBasePath](output.md#displaybasepath) option. diff --git a/site/options/output.md b/site/options/output.md index d01692514..fbd6df90a 100644 --- a/site/options/output.md +++ b/site/options/output.md @@ -318,14 +318,15 @@ export default { }; ``` -## basePath +## displayBasePath ```bash -$ typedoc --basePath ./ --entryPoints src/index.ts +$ typedoc --displayBasePath ./ --entryPoints src/index.ts ``` Specifies the base path to be used when displaying file paths. If not set, TypeDoc will guess by taking the lowest -common directory to all source files. In the above example, TypeDoc would display links to `index.ts` rather than `src/index.ts`. +common directory to all source files. In the above example, TypeDoc would display links to `index.ts` rather than `src/index.ts` +if `displayBasePath` was not specified. Defaults to the value of [basePath](input.md#basepath) > [!note] > This option only affects displayed paths. It _does not_ affect where TypeDoc will create links to. diff --git a/site/options/package-options.md b/site/options/package-options.md index ea055071f..46aa2ea6c 100644 --- a/site/options/package-options.md +++ b/site/options/package-options.md @@ -53,6 +53,7 @@ at the root level. The following tables indicate where an option should be set. | [`gitRemote`](input.md#gitremote) | Package | | | [`disableGit`](input.md#disablegit) | Package | | | [`readme`](input.md#readme) | Both | Root: Site readme, Package: Package readme | +| [`basePath`](input.md#basepath) | Both | Root: Site readme, documents, Package: Package readme, documentation comments, documents | ## Output Options @@ -77,7 +78,7 @@ at the root level. The following tables indicate where an option should be set. | [`customFooterHtmlDisableWrapper`](output.md#customfooterhtmldisablewrapper) | Root | | | [`markdownItOptions`](output.md#markdownitoptions) | Root | | | [`markdownItLoader`](output.md#markdownitloader) | Root | | -| [`basePath`](output.md#basepath) | Both | Used to determine file names of entry points and documents | +| [`displayBasePath`](output.md#displaybasepath) | Both | Used to determine file names of entry points and documents | | [`cname`](output.md#cname) | Root | | | [`favicon`](output.md#favicon) | Root | | | [`sourceLinkExternal`](output.md#sourcelinkexternal) | Root | | diff --git a/src/lib/application.ts b/src/lib/application.ts index d3574b3e5..75b5cd214 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -148,6 +148,10 @@ export class Application extends AbstractComponent< options = new Options(); + /** + * Due for deprecation in 0.29, use the reference to this on {@link ProjectReflection}, + * this was the wrong place for this member to live. + */ files: FileRegistry = new ValidatingFileRegistry(); /** @internal */ @@ -273,6 +277,10 @@ export class Application extends AbstractComponent< this.logger.level = this.options.getValue("logLevel"); } + if (this.files instanceof ValidatingFileRegistry) { + this.files.basePath = this.options.getValue("basePath"); + } + for ( const [lang, locales] of Object.entries( this.options.getValue("locales"), @@ -827,7 +835,7 @@ export class Application extends AbstractComponent< for (const { dir, options } of projectsToConvert) { this.logger.info(i18n.converting_project_at_0(nicePath(dir))); this.options = options; - this.files = new ValidatingFileRegistry(); + this.files = new ValidatingFileRegistry(options.getValue("basePath")); let project = await this.convert(); if (project) { this.validate(project); diff --git a/src/lib/converter/plugins/SourcePlugin.ts b/src/lib/converter/plugins/SourcePlugin.ts index 203e30e84..95d5b2e44 100644 --- a/src/lib/converter/plugins/SourcePlugin.ts +++ b/src/lib/converter/plugins/SourcePlugin.ts @@ -10,7 +10,7 @@ import { SourceReference } from "../../models/index.js"; import { gitIsInstalled, RepositoryManager } from "../utils/repository.js"; import { ConverterEvents } from "../converter-events.js"; import type { Converter } from "../converter.js"; -import { i18n, type NormalizedPath } from "#utils"; +import { i18n } from "#utils"; /** * A handler that attaches source file information to reflections. @@ -31,8 +31,9 @@ export class SourcePlugin extends ConverterComponent { @Option("sourceLinkTemplate") accessor sourceLinkTemplate!: string; - @Option("basePath") - accessor basePath!: NormalizedPath; + get displayBasePath() { + return this.application.options.getValue("displayBasePath") || this.application.options.getValue("basePath"); + } /** * All file names to find the base path from. @@ -157,7 +158,7 @@ export class SourcePlugin extends ConverterComponent { ); } - const basePath = this.basePath || getCommonDirectory([...this.fileNames]); + const basePath = this.displayBasePath || getCommonDirectory([...this.fileNames]); this.repositories ||= new RepositoryManager( basePath, this.gitRevision, diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index db746e7bd..b412c9741 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -311,12 +311,14 @@ export = { "Use the specified remote for linking to GitHub/Bitbucket source files. Has no effect if disableGit or disableSources is set", help_disableGit: "Assume that all can be linked to with the sourceLinkTemplate, sourceLinkTemplate must be set if this is enabled. {path} will be rooted at basePath", - help_basePath: "Specifies the base path to be used when displaying file paths", + help_displayBasePath: + "Specifies the base path to be used when displaying file paths. If not specified, basePath is used.", help_excludeTags: "Remove the listed block/modifier tags from doc comments", help_notRenderedTags: "Tags which will be preserved in doc comments, but not rendered when creating output", help_cascadedModifierTags: "Modifier tags which should be copied to all children of the parent reflection", help_readme: "Path to the readme file that should be displayed on the index page. Pass `none` to disable the index page and start the documentation on the globals page", + help_basePath: "Specifies a path which links may be resolved relative to.", help_cname: "Set the CNAME file text, it's useful for custom domains on GitHub Pages", help_favicon: "Path to favicon to include as the site icon", help_sourceLinkExternal: diff --git a/src/lib/utils/ValidatingFileRegistry.ts b/src/lib/utils/ValidatingFileRegistry.ts index 0a52b52ca..0e26dc72a 100644 --- a/src/lib/utils/ValidatingFileRegistry.ts +++ b/src/lib/utils/ValidatingFileRegistry.ts @@ -4,17 +4,33 @@ import { i18n, type NormalizedPath, NormalizedPathUtils } from "#utils"; import { existsSync } from "fs"; export class ValidatingFileRegistry extends FileRegistry { + basePath: NormalizedPath; + + constructor(basePath: NormalizedPath = "") { + super(); + this.basePath = basePath; + } + override register( sourcePath: NormalizedPath, relativePath: NormalizedPath, ): { target: FileId; anchor: string | undefined } | undefined { - const absolute = NormalizedPathUtils.resolve(NormalizedPathUtils.dirname(sourcePath), relativePath); - const absoluteWithoutAnchor = absolute.replace(/#.*/, ""); + let absolute = NormalizedPathUtils.resolve(NormalizedPathUtils.dirname(sourcePath), relativePath); + let absoluteWithoutAnchor = absolute.replace(/#.*/, ""); // Note: We allow paths to directories to be registered here, but the AssetsPlugin will not // copy them to the output path. This is so that we can link to directories and associate them // with reflections in packages mode. if (!existsSync(absoluteWithoutAnchor)) { - return; + // If the relative path didn't exist normally, also check the path relative to the assetBasePath option + if (this.basePath != "") { + absolute = NormalizedPathUtils.resolve(this.basePath, relativePath); + absoluteWithoutAnchor = absolute.replace(/#.*/, ""); + if (!existsSync(absoluteWithoutAnchor)) { + return; + } + } else { + return; + } } return this.registerAbsolute(absolute); } diff --git a/src/lib/utils/entry-point.ts b/src/lib/utils/entry-point.ts index 38511656c..35f90d8b0 100644 --- a/src/lib/utils/entry-point.ts +++ b/src/lib/utils/entry-point.ts @@ -196,7 +196,7 @@ export function getDocumentEntryPoints( options, supportedFileRegex, ); - const baseDir = options.getValue("basePath") || getCommonDirectory(expanded); + const baseDir = options.getValue("displayBasePath") || options.getValue("basePath") || getCommonDirectory(expanded); return expanded.map((path) => { return { displayName: relative(baseDir, path).replace(/\.[^.]+$/, ""), @@ -293,7 +293,8 @@ function getEntryPointsForPaths( options: Options, programs = getEntryPrograms(inputFiles, logger, options), ): DocumentationEntryPoint[] { - const baseDir = options.getValue("basePath") || getCommonDirectory(inputFiles); + const baseDir = options.getValue("displayBasePath") || options.getValue("basePath") || + getCommonDirectory(inputFiles); const entryPoints: DocumentationEntryPoint[] = []; let expandSuggestion = true; diff --git a/src/lib/utils/options/declaration.ts b/src/lib/utils/options/declaration.ts index ef234c17d..e1bb8a352 100644 --- a/src/lib/utils/options/declaration.ts +++ b/src/lib/utils/options/declaration.ts @@ -222,6 +222,7 @@ export interface TypeDocOptionMap { gitRevision: string; gitRemote: string; readme: string; + basePath: NormalizedPath; // Output outputs: ManuallyValidatedOption>; @@ -261,7 +262,7 @@ export interface TypeDocOptionMap { * strictly typed here. */ markdownItLoader: ManuallyValidatedOption<(parser: any) => void>; - basePath: NormalizedPath; + displayBasePath: NormalizedPath; cname: string; favicon: NormalizedPath; githubPages: boolean; diff --git a/src/lib/utils/options/sources/typedoc.ts b/src/lib/utils/options/sources/typedoc.ts index 6799ee531..80826f26d 100644 --- a/src/lib/utils/options/sources/typedoc.ts +++ b/src/lib/utils/options/sources/typedoc.ts @@ -20,9 +20,7 @@ function makeTagArrayValidator(name: keyof TypeDocOptionMap) { // For convenience, added in the same order as they are documented on the website. export function addTypeDocOptions(options: Pick) { - /////////////////////////// - // Configuration Options // - /////////////////////////// + // MARK: Configuration Options options.addDeclaration({ type: ParameterType.Path, @@ -96,9 +94,7 @@ export function addTypeDocOptions(options: Pick) { }, }); - /////////////////////////// - ////// Input Options ////// - /////////////////////////// + // MARK: Input Options options.addDeclaration({ name: "entryPoints", @@ -232,10 +228,18 @@ export function addTypeDocOptions(options: Pick) { } }, }); + options.addDeclaration({ + name: "readme", + help: () => i18n.help_readme(), + type: ParameterType.Path, + }); + options.addDeclaration({ + name: "basePath", + help: () => i18n.help_basePath(), + type: ParameterType.Path, + }); - /////////////////////////// - ///// Output Options ////// - /////////////////////////// + // MARK: Output Options options.addDeclaration({ name: "outputs", @@ -454,13 +458,8 @@ export function addTypeDocOptions(options: Pick) { type: ParameterType.Boolean, }); options.addDeclaration({ - name: "basePath", - help: () => i18n.help_basePath(), - type: ParameterType.Path, - }); - options.addDeclaration({ - name: "readme", - help: () => i18n.help_readme(), + name: "displayBasePath", + help: () => i18n.help_displayBasePath(), type: ParameterType.Path, }); options.addDeclaration({ @@ -720,9 +719,7 @@ export function addTypeDocOptions(options: Pick) { type: ParameterType.Boolean, }); - /////////////////////////// - ///// Comment Options ///// - /////////////////////////// + // MARK: Comment Options options.addDeclaration({ name: "jsDocCompatibility", @@ -807,9 +804,7 @@ export function addTypeDocOptions(options: Pick) { validate: makeTagArrayValidator("cascadedModifierTags"), }); - /////////////////////////// - // Organization Options /// - /////////////////////////// + // MARK: Organization Options options.addDeclaration({ name: "categorizeByGroup", @@ -884,9 +879,7 @@ export function addTypeDocOptions(options: Pick) { }, }); - /////////////////////////// - ///// General Options ///// - /////////////////////////// + // MARK: General Options options.addDeclaration({ name: "watch", diff --git a/src/test/converter2/issues/gh3009.ts b/src/test/converter2/issues/gh3009.ts new file mode 100644 index 000000000..ac9e243da --- /dev/null +++ b/src/test/converter2/issues/gh3009.ts @@ -0,0 +1,7 @@ +/** + * [link with base path](src/test/converter2/issues/gh3009.ts) + * [link direct](gh3009.ts) + * + * [asset link](CHANGELOG.md) + */ +export const x = 1; diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index c645ff455..cdb558765 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -17,7 +17,9 @@ import type { InlineTagDisplayPart } from "../lib/models/Comment.js"; import { getConverter2App, getConverter2Project } from "./programs.js"; import { TestLogger } from "./TestLogger.js"; import { equalKind, getComment, getLinks, getSigComment, query, querySig, reflToTree } from "./utils.js"; -import { DefaultTheme, KindRouter, PageEvent, ReflectionSymbolId } from "../index.js"; +import { DefaultTheme, type FileId, KindRouter, PageEvent, ReflectionSymbolId } from "../index.js"; +import { normalizePath, TYPEDOC_ROOT } from "#node-utils"; +import { NormalizedPathUtils } from "#utils"; const app = getConverter2App(); @@ -2183,6 +2185,22 @@ describe("Issue Tests", () => { ok(project.files.resolve(x.comment.summary[1].target, project) === doc); }); + it("#3009 supports a base path for resolving relative links", () => { + app.options.setValue("basePath", TYPEDOC_ROOT); + const project = convert(); + const x = query(project, "x"); + const links = x.comment?.summary.filter(part => part.kind === "relative-link"); + equal(links?.length, 3); + equal(links[0].target, 1); + equal(links[1].target, 1); + equal(links[2].target, 2); + ok(app.files.resolve(1 as FileId, project) == project); + equal( + app.files.resolve(2 as FileId, project), + NormalizedPathUtils.resolve(normalizePath(TYPEDOC_ROOT), normalizePath("CHANGELOG.md")), + ); + }); + it("#3012 removes @remarks from inheriting comment", () => { const project = convert(); const nullProto = query(project, "NullProtoObjectSchema"); diff --git a/src/test/programs.ts b/src/test/programs.ts index 68b27b47c..d34b5315a 100644 --- a/src/test/programs.ts +++ b/src/test/programs.ts @@ -173,7 +173,7 @@ export function getConverter2Project(entries: string[], folder: string) { ok(entryPoints.length > 0, "Expected at least one entry point"); app.options.setValue("entryPoints", entryPoints); - app.files = new ValidatingFileRegistry(); + app.files = new ValidatingFileRegistry(app.options.getValue("basePath")); return app.converter.convert( files.map((file, index) => { return { From 33e4eb95ec2db9b5cb2bdf3416142006755e73f3 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 14 Sep 2025 17:41:03 -0600 Subject: [PATCH 34/46] Fix externalSymbolLinkMappings with inherited methods Fixes #3014 --- .gitignore | 1 + CHANGELOG.md | 1 + src/lib/converter/plugins/ImplementsPlugin.ts | 48 ++- src/lib/converter/types.ts | 2 + src/lib/models/types.ts | 6 +- .../themes/default/partials/typeAndParent.tsx | 26 +- src/test/converter/inheritance/specs.json | 6 +- src/test/converter/mixin/specs.json | 30 +- src/test/converter2/renderer/gh3014.ts | 7 + src/test/converter2/renderer/index.ts | 1 + .../node_modules/@typedoc/gh3014/index.d.ts | 3 + .../node_modules/@typedoc/gh3014/package.json | 3 + src/test/converter2/typedoc.json | 4 + src/test/models/types.test.ts | 4 +- src/test/output/formatter.test.ts | 10 +- src/test/renderer/specs/classes/GH3014.json | 286 ++++++++++++++++++ src/test/renderer/specs/modules.json | 32 ++ 17 files changed, 432 insertions(+), 38 deletions(-) create mode 100644 src/test/converter2/renderer/gh3014.ts create mode 100644 src/test/converter2/renderer/node_modules/@typedoc/gh3014/index.d.ts create mode 100644 src/test/converter2/renderer/node_modules/@typedoc/gh3014/package.json create mode 100644 src/test/renderer/specs/classes/GH3014.json diff --git a/.gitignore b/.gitignore index 0ed4251ff..a223dce66 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ yarn-error.log /src/test/renderer/testProject/json.json **/node_modules/ !src/test/converter2/behavior/node_modules/ +!src/test/converter2/renderer/node_modules/ /coverage/ /dist/ /docs diff --git a/CHANGELOG.md b/CHANGELOG.md index f97e2d1b9..c453ce415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ title: Changelog - Fixed bug introduced in 0.28.8 where TypeDoc could not render docs with some mixin classes, #3007. - `@inheritDoc` will now correctly overwrite `@remarks` and `@returns` blocks on the target comment, #3012. +- The `externalSymbolLinkMappings` option now works properly on links pointing to inherited/overwritten signatures, #3014. ## v0.28.12 (2025-09-01) diff --git a/src/lib/converter/plugins/ImplementsPlugin.ts b/src/lib/converter/plugins/ImplementsPlugin.ts index 383a4ac2c..29bb78146 100644 --- a/src/lib/converter/plugins/ImplementsPlugin.ts +++ b/src/lib/converter/plugins/ImplementsPlugin.ts @@ -13,7 +13,7 @@ import { ReferenceType, ReflectionType, type SomeType, type Type } from "../../m import { filterMap, type TranslatedString, zip } from "#utils"; import { ConverterComponent } from "../components.js"; import type { Context } from "../context.js"; -import { getHumanName } from "../../utils/index.js"; +import { findPackageForPath, getHumanName } from "../../utils/index.js"; import { ConverterEvents } from "../converter-events.js"; import type { Converter } from "../converter.js"; @@ -182,18 +182,34 @@ export class ImplementsPlugin extends ConverterComponent { for (const child of reflection.children || []) { if (child.inheritedFrom && !isValidRef(child.inheritedFrom)) { - child.inheritedFrom = ReferenceType.createBrokenReference(child.inheritedFrom.name, project); + child.inheritedFrom = ReferenceType.createBrokenReference( + child.inheritedFrom.name, + project, + child.inheritedFrom.package, + ); } if (child.overwrites && !isValidRef(child.overwrites)) { - child.overwrites = ReferenceType.createBrokenReference(child.overwrites.name, project); + child.overwrites = ReferenceType.createBrokenReference( + child.overwrites.name, + project, + child.overwrites.package, + ); } for (const childSig of child.getAllSignatures()) { if (childSig.inheritedFrom && !isValidRef(childSig.inheritedFrom)) { - childSig.inheritedFrom = ReferenceType.createBrokenReference(childSig.inheritedFrom.name, project); + childSig.inheritedFrom = ReferenceType.createBrokenReference( + childSig.inheritedFrom.name, + project, + childSig.inheritedFrom.package, + ); } if (childSig.overwrites && !isValidRef(childSig.overwrites)) { - childSig.overwrites = ReferenceType.createBrokenReference(childSig.overwrites.name, project); + childSig.overwrites = ReferenceType.createBrokenReference( + childSig.overwrites.name, + project, + childSig.overwrites.package, + ); } } } @@ -522,6 +538,18 @@ export class ImplementsPlugin extends ConverterComponent { } } +function getConstructorPackagePath(context: Context, clause: ts.ExpressionWithTypeArguments): string | undefined { + const symbol = context.getSymbolAtLocation(clause.expression); + if (!symbol) return undefined; + + const resolvedSymbol = context.resolveAliasedSymbol(symbol); + + const symbolPath = resolvedSymbol?.declarations?.[0]?.getSourceFile().fileName; + if (!symbolPath) return undefined; + + return findPackageForPath(symbolPath)?.[0]; +} + function constructorInheritance( context: Context, reflection: DeclarationReflection, @@ -533,17 +561,21 @@ function constructorInheritance( ); if (!extendsClause) return; - const name = `${extendsClause.types[0].getText()}.constructor`; + const extendsType = extendsClause.types[0]; + const refPackage = getConstructorPackagePath(context, extendsType); + + const name = `${extendsType.getText()}.constructor`; const key = constructorDecl ? "overwrites" : "inheritedFrom"; reflection[key] ??= ReferenceType.createBrokenReference( name, context.project, + refPackage, ); for (const sig of reflection.signatures ?? []) { - sig[key] ??= ReferenceType.createBrokenReference(name, context.project); + sig[key] ??= ReferenceType.createBrokenReference(name, context.project, refPackage); } } @@ -576,7 +608,7 @@ function createLink( const rootSymbols = context.checker.getRootSymbols(symbol); const ref = rootSymbols.length && rootSymbols[0] != symbol ? context.createSymbolReference(rootSymbols[0], context, name) - : ReferenceType.createBrokenReference(name, context.project); + : ReferenceType.createBrokenReference(name, context.project, undefined); link(reflection); link(reflection.getSignature); diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index 56a08bafb..8cd71c246 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -705,6 +705,7 @@ const queryConverter: TypeConverter = { ReferenceType.createBrokenReference( node.exprName.getText(), context.project, + undefined, ), ); } @@ -786,6 +787,7 @@ const referenceConverter: TypeConverter< const ref = ReferenceType.createBrokenReference( context.checker.typeToString(type), context.project, + undefined, ); ref.refersToTypeParameter = true; return ref; diff --git a/src/lib/models/types.ts b/src/lib/models/types.ts index a1e99c80e..b7cf99729 100644 --- a/src/lib/models/types.ts +++ b/src/lib/models/types.ts @@ -960,8 +960,10 @@ export class ReferenceType extends Type { * later during conversion. * @internal */ - static createBrokenReference(name: string, project: ProjectReflection) { - return new ReferenceType(name, -1 as ReflectionId, project, name); + static createBrokenReference(name: string, project: ProjectReflection, packageName: string | undefined) { + const ref = new ReferenceType(name, -1 as ReflectionId, project, name); + ref.package = packageName; + return ref; } protected override getTypeString() { diff --git a/src/lib/output/themes/default/partials/typeAndParent.tsx b/src/lib/output/themes/default/partials/typeAndParent.tsx index 3cac22a88..18cfb10d1 100644 --- a/src/lib/output/themes/default/partials/typeAndParent.tsx +++ b/src/lib/output/themes/default/partials/typeAndParent.tsx @@ -1,5 +1,5 @@ import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext.js"; -import { ArrayType, ReferenceType, SignatureReflection, type Type } from "../../../../models/index.js"; +import { ArrayType, ReferenceType, SignatureReflection, type Type } from "#models"; import { JSX } from "#utils"; export const typeAndParent = (context: DefaultThemeRenderContext, props: Type): JSX.Element => { @@ -12,15 +12,23 @@ export const typeAndParent = (context: DefaultThemeRenderContext, props: Type): ); } - if (props instanceof ReferenceType && props.reflection) { - const refl = props.reflection instanceof SignatureReflection ? props.reflection.parent : props.reflection; - const parent = refl.parent!; + if (props instanceof ReferenceType) { + if (props.reflection) { + const refl = props.reflection instanceof SignatureReflection ? props.reflection.parent : props.reflection; + const parent = refl.parent!; - return ( - <> - {{parent.name}}.{{refl.name}} - - ); + return ( + <> + {{parent.name}}.{{refl.name}} + + ); + } else if (props.externalUrl) { + if (props.externalUrl === "#") { + return <>{props.toString()}; + } else { + return {props.name}; + } + } } return <>{props.toString()}; diff --git a/src/test/converter/inheritance/specs.json b/src/test/converter/inheritance/specs.json index 8bb200c3e..74aabc605 100644 --- a/src/test/converter/inheritance/specs.json +++ b/src/test/converter/inheritance/specs.json @@ -671,14 +671,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "My.constructor" + "name": "My.constructor", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "My.constructor" + "name": "My.constructor", + "package": "typedoc" } }, { diff --git a/src/test/converter/mixin/specs.json b/src/test/converter/mixin/specs.json index 146ed2189..9ec8e447f 100644 --- a/src/test/converter/mixin/specs.json +++ b/src/test/converter/mixin/specs.json @@ -426,14 +426,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin2(Mixin1Func(Base)).method1" + "name": "Mixin2(Mixin1Func(Base)).method1", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin2(Mixin1Func(Base)).method1" + "name": "Mixin2(Mixin1Func(Base)).method1", + "package": "typedoc" } }, { @@ -493,14 +495,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin2(Mixin1Func(Base)).method2" + "name": "Mixin2(Mixin1Func(Base)).method2", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin2(Mixin1Func(Base)).method2" + "name": "Mixin2(Mixin1Func(Base)).method2", + "package": "typedoc" } } ], @@ -875,14 +879,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method1" + "name": "Mixin.method1", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method1" + "name": "Mixin.method1", + "package": "typedoc" } } ], @@ -1139,14 +1145,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method1" + "name": "Mixin.method1", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method1" + "name": "Mixin.method1", + "package": "typedoc" } }, { @@ -1206,14 +1214,16 @@ "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method2" + "name": "Mixin.method2", + "package": "typedoc" } } ], "inheritedFrom": { "type": "reference", "target": -1, - "name": "Mixin.method2" + "name": "Mixin.method2", + "package": "typedoc" } } ], diff --git a/src/test/converter2/renderer/gh3014.ts b/src/test/converter2/renderer/gh3014.ts new file mode 100644 index 000000000..acd3ea124 --- /dev/null +++ b/src/test/converter2/renderer/gh3014.ts @@ -0,0 +1,7 @@ +import { GH3014Base } from "@typedoc/gh3014"; + +export class GH3014 extends GH3014Base { + constructor() { + super(); + } +} diff --git a/src/test/converter2/renderer/index.ts b/src/test/converter2/renderer/index.ts index 05a839724..d43e25ccc 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -139,4 +139,5 @@ export * as ExpandType from "./expandType"; export * as GH2982 from "./gh2982"; export { gh2995 } from "./gh2995"; export * as GH3007 from "./gh3007"; +export { GH3014 } from "./gh3014"; export { box as boxAlias }; diff --git a/src/test/converter2/renderer/node_modules/@typedoc/gh3014/index.d.ts b/src/test/converter2/renderer/node_modules/@typedoc/gh3014/index.d.ts new file mode 100644 index 000000000..5eec32d15 --- /dev/null +++ b/src/test/converter2/renderer/node_modules/@typedoc/gh3014/index.d.ts @@ -0,0 +1,3 @@ +export class GH3014Base { + constructor(); +} diff --git a/src/test/converter2/renderer/node_modules/@typedoc/gh3014/package.json b/src/test/converter2/renderer/node_modules/@typedoc/gh3014/package.json new file mode 100644 index 000000000..c204a035b --- /dev/null +++ b/src/test/converter2/renderer/node_modules/@typedoc/gh3014/package.json @@ -0,0 +1,3 @@ +{ + "name": "@typedoc/gh3014" +} diff --git a/src/test/converter2/typedoc.json b/src/test/converter2/typedoc.json index 9e56b27f9..bcdc04f8d 100644 --- a/src/test/converter2/typedoc.json +++ b/src/test/converter2/typedoc.json @@ -27,6 +27,10 @@ // used by {@link !Promise} "global": { "Promise": "#" + }, + "@typedoc/gh3014": { + "GH3014Base": "typedoc://GH3014Base", + "GH3014Base.constructor": "typedoc://GH3014Base.constructor" } } } diff --git a/src/test/models/types.test.ts b/src/test/models/types.test.ts index 966a68c97..d9dd945a5 100644 --- a/src/test/models/types.test.ts +++ b/src/test/models/types.test.ts @@ -266,7 +266,7 @@ describe("Type.toString", () => { const project = new ProjectReflection("test", new FileRegistry()); const type = new T.OptionalType( new T.QueryType( - T.ReferenceType.createBrokenReference("X", project), + T.ReferenceType.createBrokenReference("X", project, undefined), ), ); equal(type.toString(), "typeof X?"); @@ -287,7 +287,7 @@ describe("Type.toString", () => { const project = new ProjectReflection("test", new FileRegistry()); const type = new T.TypeOperatorType( new T.QueryType( - T.ReferenceType.createBrokenReference("X", project), + T.ReferenceType.createBrokenReference("X", project, undefined), ), "keyof", ); diff --git a/src/test/output/formatter.test.ts b/src/test/output/formatter.test.ts index d8b9db60f..cfe2f4a4b 100644 --- a/src/test/output/formatter.test.ts +++ b/src/test/output/formatter.test.ts @@ -228,7 +228,7 @@ describe("Formatter", () => { it("Handles query types", () => { const project = new ProjectReflection("", new FileRegistry()); const type = new QueryType( - ReferenceType.createBrokenReference("x", project), + ReferenceType.createBrokenReference("x", project, undefined), ); const text = renderElementToText(renderType(type)); equal(text, `typeof x`); @@ -236,7 +236,7 @@ describe("Formatter", () => { it("Handles a simple reference type", () => { const project = new ProjectReflection("", new FileRegistry()); - const type = ReferenceType.createBrokenReference("x", project); + const type = ReferenceType.createBrokenReference("x", project, undefined); const text = renderElementToText(renderType(type)); equal(text, `x`); }); @@ -277,7 +277,7 @@ describe("Formatter", () => { it("Handles a reference type pointing to an external url", () => { const project = new ProjectReflection("", new FileRegistry()); - const type = ReferenceType.createBrokenReference("x", project); + const type = ReferenceType.createBrokenReference("x", project, undefined); type.externalUrl = "https://example.com"; const text = renderElementToText(renderType(type)); equal(text, `x`); @@ -285,7 +285,7 @@ describe("Formatter", () => { it("Handles a reference type targeting a type parameter", () => { const project = new ProjectReflection("", new FileRegistry()); - const type = ReferenceType.createBrokenReference("x", project); + const type = ReferenceType.createBrokenReference("x", project, undefined); type.refersToTypeParameter = true; const text = renderElementToText(renderType(type)); equal(text, `x`); @@ -293,7 +293,7 @@ describe("Formatter", () => { it("Handles a reference type with type arguments", () => { const project = new ProjectReflection("", new FileRegistry()); - const type = ReferenceType.createBrokenReference("x", project); + const type = ReferenceType.createBrokenReference("x", project, undefined); type.typeArguments = [ new LiteralType(123), new LiteralType(456), diff --git a/src/test/renderer/specs/classes/GH3014.json b/src/test/renderer/specs/classes/GH3014.json new file mode 100644 index 000000000..f764dc955 --- /dev/null +++ b/src/test/renderer/specs/classes/GH3014.json @@ -0,0 +1,286 @@ +{ + "div.container.container-main": [ + { + "div.col-content": [ + { + "div.tsd-page-title": [ + { + "tag": "ul.tsd-breadcrumb", + "props": { + "aria-label": "Breadcrumb" + }, + "children": { + "li": { + "tag": "a", + "props": { + "href": "", + "aria-current": "page" + }, + "children": "GH3014" + } + } + }, + { + "h1": "Class GH3014" + } + ] + }, + { + "tag": "section.tsd-panel.tsd-hierarchy", + "props": { + "data-refl": "151" + }, + "children": [ + { + "h4": "Hierarchy" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": [ + { + "tag": "a.tsd-signature-type.external", + "props": { + "href": "typedoc://GH3014Base", + "target": "_blank" + }, + "children": "GH3014Base" + }, + { + "ul.tsd-hierarchy": { + "li.tsd-hierarchy-item": { + "span.tsd-hierarchy-target": "GH3014" + } + } + } + ] + } + } + ] + }, + { + "aside.tsd-sources": { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3014.ts" + }, + "children": "gh3014.ts:3" + } + ] + } + } + }, + { + "section.tsd-panel-group.tsd-index-group": { + "section.tsd-panel.tsd-index-panel": { + "tag": "details.tsd-index-content.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary.tsd-index-summary": { + "h5.tsd-index-heading.uppercase": "Index" + } + }, + { + "div.tsd-accordion-details": { + "section.tsd-index-section": [ + { + "h3.tsd-index-heading": "Constructors" + }, + { + "div.tsd-index-list": [ + { + "tag": "a.tsd-index-link", + "props": { + "href": "#constructor" + }, + "children": { + "span": "constructor" + } + }, + "\n" + ] + } + ] + } + } + ] + } + } + }, + { + "tag": "details.tsd-panel-group.tsd-member-group.tsd-accordion", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Constructors" + }, + "children": { + "h2": "Constructors" + } + }, + { + "section": { + "section.tsd-panel.tsd-member": [ + { + "h3.tsd-anchor-link#constructor": [ + { + "span": "constructor" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#constructor", + "aria-label": "Permalink" + } + } + ] + }, + { + "ul.tsd-signatures": { + "li.": [ + { + "div.tsd-signature.tsd-anchor-link#constructorgh3014": [ + { + "span.tsd-signature-keyword": "new" + }, + " ", + { + "span.tsd-kind-constructor-signature": "GH3014" + }, + { + "span.tsd-signature-symbol": "()" + }, + { + "span.tsd-signature-symbol": ":" + }, + " ", + { + "tag": "a.tsd-signature-type.tsd-kind-class", + "props": { + "href": "" + }, + "children": "GH3014" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#constructorgh3014", + "aria-label": "Permalink" + } + } + ] + }, + { + "div.tsd-description": [ + { + "h4.tsd-returns-title": [ + "Returns ", + { + "tag": "a.tsd-signature-type.tsd-kind-class", + "props": { + "href": "" + }, + "children": "GH3014" + } + ] + }, + { + "aside.tsd-sources": [ + { + "p": [ + "Overrides ", + { + "tag": "a.external", + "props": { + "href": "typedoc://GH3014Base.constructor", + "target": "_blank" + }, + "children": "GH3014Base.constructor" + } + ] + }, + { + "ul": { + "li": [ + "Defined in ", + { + "tag": "a", + "props": { + "href": "gh3014.ts" + }, + "children": "gh3014.ts:4" + } + ] + } + } + ] + } + ] + } + ] + } + } + ] + } + } + ] + } + ] + }, + { + "div.col-sidebar": { + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "details.tsd-accordion.tsd-page-navigation-section", + "props": { + "open": true + }, + "children": [ + { + "tag": "summary.tsd-accordion-summary", + "props": { + "data-key": "section-Constructors" + }, + "children": "Constructors" + }, + { + "div": { + "tag": "a", + "props": { + "href": "#constructor" + }, + "children": { + "span": "constructor" + } + } + } + ] + } + } + ] + } + } + } + ] +} diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index a11456c96..2c201b7c5 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -261,6 +261,29 @@ { "dd.tsd-member-summary": [] }, + { + "dt.tsd-member-summary#gh3014": { + "span.tsd-member-summary-name": [ + { + "tag": "a", + "props": { + "href": "classes/GH3014.json" + }, + "children": "GH3014" + }, + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#gh3014", + "aria-label": "Permalink" + } + } + ] + } + }, + { + "dd.tsd-member-summary": [] + }, { "dt.tsd-member-summary#modifiersclass": { "span.tsd-member-summary-name": [ @@ -774,6 +797,15 @@ ] } }, + { + "tag": "a", + "props": { + "href": "#gh3014" + }, + "children": { + "span": "GH3014" + } + }, { "tag": "a", "props": { From a57c48e3aa5232f87051874a197b65177672a946 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 14 Sep 2025 17:47:09 -0600 Subject: [PATCH 35/46] Bump version to 0.28.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a10ecdb0a..6d8ff462d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.12", + "version": "0.28.13", "homepage": "https://typedoc.org", "type": "module", "exports": { From 724090664126797f9ada54a1bdeaf5dc3db77385 Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Sun, 14 Sep 2025 23:48:03 +0000 Subject: [PATCH 36/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c453ce415..13d8a23db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.13 (2025-09-14) + ### Features - The `basePath` option now also affects relative link resolution, TypeDoc will also check for From bd7888a189352bfaed88793aff6f051a0b6a7ea7 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 14 Sep 2025 19:39:08 -0600 Subject: [PATCH 37/46] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d6c7ab481..16c72ff2d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -38,7 +38,7 @@ If this is not possible, include at least: ## Environment -- Typedoc version: +- TypeDoc version: - TypeScript version: - Node.js version: - OS: From 54af135a17af1a5595166c7cc12650ac014b6028 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 27 Sep 2025 20:52:23 -0600 Subject: [PATCH 38/46] Introduce preservedTypeAnnotationTags option Resolves #3020 Total time spent: 32 minutes --- CHANGELOG.md | 6 +++++ site/options/comments.md | 16 ++++++++++-- site/options/package-options.md | 1 + src/lib/converter/comments/index.ts | 1 + src/lib/converter/comments/parser.ts | 23 +++++++++++++++-- src/lib/converter/converter.ts | 9 +++---- src/lib/internationalization/locales/en.cts | 1 + src/lib/models/Comment.ts | 11 ++++++++ .../themes/default/partials/comment.tsx | 1 + src/lib/serialization/schema.ts | 2 +- src/lib/utils/options/declaration.ts | 1 + src/lib/utils/options/defaults.ts | 2 ++ src/lib/utils/options/sources/typedoc.ts | 7 ++++++ src/test/comments.test.ts | 2 ++ src/test/converter/comment/comment.ts | 2 ++ src/test/converter/comment/specs.json | 25 +++++++++++-------- src/test/converter2/issues/gh3020.ts | 7 ++++++ src/test/issues.c2.test.ts | 11 ++++++++ src/test/programs.ts | 4 ++- 19 files changed, 110 insertions(+), 22 deletions(-) create mode 100644 src/test/converter2/issues/gh3020.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d8a23db..f55f1ee13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ title: Changelog ## Unreleased +### Features + +- Introduced the `preservedTypeAnnotationTags` option to specify tags whose type annotations should + be copied to the output documentation, #3020. + API: Introduced `typeAnnotation` on `CommentTag` + ## v0.28.13 (2025-09-14) ### Features diff --git a/site/options/comments.md b/site/options/comments.md index 4e7caea52..c90abd7f2 100644 --- a/site/options/comments.md +++ b/site/options/comments.md @@ -190,7 +190,7 @@ Note that `@deprecated` is a block tag, not a modifier tag, so should not be spe ## excludeTags ```bash -$ typedoc --excludeTags apidefine +$ typedoc --excludeTags @apidefine ``` Specify tags that should be removed from doc comments when parsing. @@ -199,7 +199,7 @@ Useful if your project uses [apiDoc](https://apidocjs.com/) for documenting REST ## notRenderedTags ```bash -$ typedoc --notRenderedTags beta +$ typedoc --notRenderedTags @beta ``` Specify tags which should be preserved in the doc comments, but not rendered @@ -207,6 +207,18 @@ when creating output. This is intended to support tags which carry some meaning about how to render a member or instructions for TypeDoc to do something after a package has been deserialized from JSON in packages mode. +## preservedTypeAnnotationTags + +```json +// typedoc.json +{ + "preservedTypeAnnotationTags": ["@fires"] +} +``` + +Specify block tags whose type annotations should be preserved by TypeDoc's parser, +leading to their content being included in the rendered documentation. + ## externalSymbolLinkMappings ```json diff --git a/site/options/package-options.md b/site/options/package-options.md index 46aa2ea6c..047552aee 100644 --- a/site/options/package-options.md +++ b/site/options/package-options.md @@ -121,6 +121,7 @@ at the root level. The following tables indicate where an option should be set. | [`cascadedModifierTags`](comments.md#cascadedmodifiertags) | Package | | | [`excludeTags`](comments.md#excludetags) | Package | | | [`notRenderedTags`](comments.md#notrenderedtags) | Root | | +| [`preservedTypeAnnotationTags`](comments.md#preservedtypeannotationtags) | Package | | | [`externalSymbolLinkMappings`](comments.md#externalsymbollinkmappings) | Both | Unresolved links are checked both when converting and when merging projects | ## Organization Options diff --git a/src/lib/converter/comments/index.ts b/src/lib/converter/comments/index.ts index 7b2b69db7..faf890547 100644 --- a/src/lib/converter/comments/index.ts +++ b/src/lib/converter/comments/index.ts @@ -19,6 +19,7 @@ export interface CommentParserConfig { blockTags: Set; inlineTags: Set; modifierTags: Set; + preservedTypeAnnotationTags: Set; jsDocCompatibility: JsDocCompatibility; suppressCommentWarningsInDeclarationFiles: boolean; useTsLinkResolution: boolean; diff --git a/src/lib/converter/comments/parser.ts b/src/lib/converter/comments/parser.ts index 5d2adeb49..4453666c6 100644 --- a/src/lib/converter/comments/parser.ts +++ b/src/lib/converter/comments/parser.ts @@ -380,7 +380,22 @@ function blockTag( let content: CommentDisplayPart[]; if (tagName === "@example") { return exampleBlock(comment, lexer, config, i18n, warning, files); - } else if ( + } + + let typeAnnotation: string | undefined; + if ( + !lexer.done() && + config.preservedTypeAnnotationTags.has(tagName) + ) { + if (lexer.peek().kind === TokenSyntaxKind.Text && /^\s+$/.test(lexer.peek().text)) { + lexer.take(); + } + if (lexer.peek().kind === TokenSyntaxKind.TypeAnnotation) { + typeAnnotation = lexer.take().text; + } + } + + if ( ["@default", "@defaultValue"].includes(tagName) && config.jsDocCompatibility.defaultTag ) { @@ -396,7 +411,11 @@ function blockTag( content = blockContent(comment, lexer, config, i18n, warning, files); } - return new CommentTag(tagName as TagString, content); + const tag = new CommentTag(tagName as TagString, content); + if (typeAnnotation) { + tag.typeAnnotation = typeAnnotation; + } + return tag; } /** diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 296d2c0cb..9efdab032 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -785,12 +785,9 @@ export class Converter extends AbstractComponent { private _buildCommentParserConfig() { this._config = { blockTags: new Set(this.application.options.getValue("blockTags")), - inlineTags: new Set( - this.application.options.getValue("inlineTags"), - ), - modifierTags: new Set( - this.application.options.getValue("modifierTags"), - ), + inlineTags: new Set(this.application.options.getValue("inlineTags")), + modifierTags: new Set(this.application.options.getValue("modifierTags")), + preservedTypeAnnotationTags: new Set(this.application.options.getValue("preservedTypeAnnotationTags")), jsDocCompatibility: this.application.options.getValue("jsDocCompatibility"), suppressCommentWarningsInDeclarationFiles: this.application.options.getValue( "suppressCommentWarningsInDeclarationFiles", diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index b412c9741..ee7c4f032 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -316,6 +316,7 @@ export = { help_excludeTags: "Remove the listed block/modifier tags from doc comments", help_notRenderedTags: "Tags which will be preserved in doc comments, but not rendered when creating output", help_cascadedModifierTags: "Modifier tags which should be copied to all children of the parent reflection", + help_preservedTypeAnnotationTags: "Block tags whose type annotations should be preserved in the output.", help_readme: "Path to the readme file that should be displayed on the index page. Pass `none` to disable the index page and start the documentation on the globals page", help_basePath: "Specifies a path which links may be resolved relative to.", diff --git a/src/lib/models/Comment.ts b/src/lib/models/Comment.ts index 70316f50b..dea38cbf3 100644 --- a/src/lib/models/Comment.ts +++ b/src/lib/models/Comment.ts @@ -88,6 +88,12 @@ export class CommentTag { */ name?: string; + /** + * Optional type annotation associated with this tag. TypeDoc will remove type annotations unless explicitly + * requested by the user with the `preservedTypeAnnotationTags` option. + */ + typeAnnotation?: string; + /** * The actual body text of this tag. */ @@ -130,6 +136,9 @@ export class CommentTag { if (this.name) { tag.name = this.name; } + if (this.typeAnnotation) { + tag.typeAnnotation = this.typeAnnotation; + } return tag; } @@ -138,12 +147,14 @@ export class CommentTag { tag: this.tag, name: this.name, content: Comment.serializeDisplayParts(this.content), + typeAnnotation: this.typeAnnotation, }; } fromObject(de: Deserializer, obj: JSONOutput.CommentTag) { // tag already set by Comment.fromObject this.name = obj.name; + this.typeAnnotation = obj.typeAnnotation; this.content = Comment.deserializeDisplayParts(de, obj.content); } } diff --git a/src/lib/output/themes/default/partials/comment.tsx b/src/lib/output/themes/default/partials/comment.tsx index 46731e511..dc7a4d128 100644 --- a/src/lib/output/themes/default/partials/comment.tsx +++ b/src/lib/output/themes/default/partials/comment.tsx @@ -83,6 +83,7 @@ export function commentTags(context: DefaultThemeRenderContext, props: Reflectio {name} {anchorIcon(context, anchor)}
    + {item.typeAnnotation && {item.typeAnnotation}}
  • diff --git a/src/lib/serialization/schema.ts b/src/lib/serialization/schema.ts index d55900d71..f1fe07a74 100644 --- a/src/lib/serialization/schema.ts +++ b/src/lib/serialization/schema.ts @@ -369,7 +369,7 @@ export interface Comment extends Partial> { } /** @category Comments */ -export interface CommentTag extends S { +export interface CommentTag extends S { content: CommentDisplayPart[]; } diff --git a/src/lib/utils/options/declaration.ts b/src/lib/utils/options/declaration.ts index e1bb8a352..8a8337fb3 100644 --- a/src/lib/utils/options/declaration.ts +++ b/src/lib/utils/options/declaration.ts @@ -320,6 +320,7 @@ export interface TypeDocOptionMap { Record> >; cascadedModifierTags: TagString[]; + preservedTypeAnnotationTags: TagString[]; // Organization categorizeByGroup: boolean; diff --git a/src/lib/utils/options/defaults.ts b/src/lib/utils/options/defaults.ts index 277f0e035..3751c3183 100644 --- a/src/lib/utils/options/defaults.ts +++ b/src/lib/utils/options/defaults.ts @@ -51,6 +51,8 @@ export const cascadedModifierTags: readonly TagString[] = [ "@experimental", ]; +export const preservedTypeAnnotationTags: readonly TagString[] = []; + export const notRenderedTags: readonly TagString[] = [ "@showCategories", "@showGroups", diff --git a/src/lib/utils/options/sources/typedoc.ts b/src/lib/utils/options/sources/typedoc.ts index 80826f26d..1ef0e7821 100644 --- a/src/lib/utils/options/sources/typedoc.ts +++ b/src/lib/utils/options/sources/typedoc.ts @@ -803,6 +803,13 @@ export function addTypeDocOptions(options: Pick) { defaultValue: OptionDefaults.cascadedModifierTags, validate: makeTagArrayValidator("cascadedModifierTags"), }); + options.addDeclaration({ + name: "preservedTypeAnnotationTags", + help: () => i18n.help_preservedTypeAnnotationTags(), + type: ParameterType.Array, + defaultValue: OptionDefaults.preservedTypeAnnotationTags, + validate: makeTagArrayValidator("preservedTypeAnnotationTags"), + }); // MARK: Organization Options diff --git a/src/test/comments.test.ts b/src/test/comments.test.ts index 352cdba30..8a95a98c0 100644 --- a/src/test/comments.test.ts +++ b/src/test/comments.test.ts @@ -1145,6 +1145,7 @@ describe("Comment Parser", () => { "@event", "@packageDocumentation", ]), + preservedTypeAnnotationTags: new Set(["@fires"]), jsDocCompatibility: { defaultTag: true, exampleTag: true, @@ -1877,6 +1878,7 @@ describe("Raw Comment Parser", () => { "@event", "@packageDocumentation", ]), + preservedTypeAnnotationTags: new Set(["@fires"]), jsDocCompatibility: { defaultTag: true, exampleTag: true, diff --git a/src/test/converter/comment/comment.ts b/src/test/converter/comment/comment.ts index 919d7ac50..785827ab1 100644 --- a/src/test/converter/comment/comment.ts +++ b/src/test/converter/comment/comment.ts @@ -32,6 +32,8 @@ import "./comment2"; * * @groupDescription Methods * Methods description! + * + * @gh3020 {type annotation} */ export class CommentedClass { /** diff --git a/src/test/converter/comment/specs.json b/src/test/converter/comment/specs.json index 711f06806..509d4b241 100644 --- a/src/test/converter/comment/specs.json +++ b/src/test/converter/comment/specs.json @@ -66,6 +66,11 @@ "text": "Methods\nMethods description!" } ] + }, + { + "tag": "@gh3020", + "content": [], + "typeAnnotation": "{type annotation}" } ] }, @@ -109,9 +114,9 @@ "sources": [ { "fileName": "comment.ts", - "line": 40, + "line": 42, "character": 4, - "url": "typedoc://comment.ts#L40" + "url": "typedoc://comment.ts#L42" } ], "type": { @@ -128,9 +133,9 @@ "sources": [ { "fileName": "comment.ts", - "line": 80, + "line": 82, "character": 4, - "url": "typedoc://comment.ts#L80" + "url": "typedoc://comment.ts#L82" } ], "signatures": [ @@ -151,9 +156,9 @@ "sources": [ { "fileName": "comment.ts", - "line": 80, + "line": 82, "character": 4, - "url": "typedoc://comment.ts#L80" + "url": "typedoc://comment.ts#L82" } ], "parameters": [ @@ -217,9 +222,9 @@ "sources": [ { "fileName": "comment.ts", - "line": 36, + "line": 38, "character": 13, - "url": "typedoc://comment.ts#L36" + "url": "typedoc://comment.ts#L38" } ] }, @@ -232,9 +237,9 @@ "sources": [ { "fileName": "comment.ts", - "line": 89, + "line": 91, "character": 12, - "url": "typedoc://comment.ts#L89" + "url": "typedoc://comment.ts#L91" } ], "type": { diff --git a/src/test/converter2/issues/gh3020.ts b/src/test/converter2/issues/gh3020.ts new file mode 100644 index 000000000..e27024db3 --- /dev/null +++ b/src/test/converter2/issues/gh3020.ts @@ -0,0 +1,7 @@ +/** + * Component demo. + * + * @fires {CustomEvent<{id: string, source: Element}>} item-click - event when item is clicked. + */ +export class ButtonControlElement extends Object { +} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index cdb558765..4b8ce14a4 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2209,4 +2209,15 @@ describe("Issue Tests", () => { logger.expectMessage("warn: Content in the @remarks block will be overwritten*"); }); + + it("#3020 permits preserving type annotations", () => { + app.options.setValue("blockTags", ["@fires"]); + app.options.setValue("preservedTypeAnnotationTags", ["@fires"]); + const project = convert(); + const btn = query(project, "ButtonControlElement"); + + equal(btn.comment?.blockTags.length, 1); + equal(btn.comment.blockTags[0].tag, "@fires"); + equal(btn.comment.blockTags[0].typeAnnotation, "{CustomEvent<{id: string, source: Element}>}"); + }); }); diff --git a/src/test/programs.ts b/src/test/programs.ts index d34b5315a..bff126163 100644 --- a/src/test/programs.ts +++ b/src/test/programs.ts @@ -14,7 +14,7 @@ import type { ModelToObject } from "../lib/serialization/schema.js"; import { createAppForTesting } from "../lib/application.js"; import { existsSync } from "fs"; import { diagnostics } from "../lib/utils/loggers.js"; -import { normalizePath, readFile, ValidatingFileRegistry } from "#node-utils"; +import { normalizePath, OptionDefaults, readFile, ValidatingFileRegistry } from "#node-utils"; let converterApp: Application | undefined; let converterProgram: ts.Program | undefined; @@ -42,6 +42,8 @@ export function getConverterApp() { gitRevision: "fake", readme: "none", skipErrorChecking: true, + preservedTypeAnnotationTags: ["@gh3020"], + blockTags: [...OptionDefaults.blockTags, "@gh3020"], } satisfies TypeDocOptions, ) ) { From efd06b1d657bba21f75154321407273a6e790925 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 27 Sep 2025 21:12:57 -0600 Subject: [PATCH 39/46] Fix conversion of auto accessor types Resolves #3019 Total time spent: 20 minutes --- CHANGELOG.md | 4 ++++ scripts/testcase.js | 14 ++++++++------ src/lib/converter/symbols.ts | 14 ++++++++++++++ .../class/specs-with-lump-categories.json | 6 +++++- src/test/converter/class/specs.json | 6 +++++- src/test/converter2/issues/gh3019.ts | 4 ++++ src/test/issues.c2.test.ts | 6 ++++++ 7 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 src/test/converter2/issues/gh3019.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f55f1ee13..7815092d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ title: Changelog be copied to the output documentation, #3020. API: Introduced `typeAnnotation` on `CommentTag` +## Bug Fixes + +- Fixed conversion of auto-accessor types on properties with the `accessor` keyword, #3019. + ## v0.28.13 (2025-09-14) ### Features diff --git a/scripts/testcase.js b/scripts/testcase.js index 0756dae45..8239e71cc 100755 --- a/scripts/testcase.js +++ b/scripts/testcase.js @@ -56,16 +56,18 @@ async function main() { ["ts", "tsx", "js", "jsx"].includes(tok.info || ""), ) || tokens.find((tok) => tok.tag === "code"); + /** @type {string} */ + let file; if (!code) { console.log("No codeblock found"); - const file = `src/test/converter2/issues/gh${issue}.ts`; - await exec(`code ${file} src/test/issues.c2.test.ts`); - return; + file = `src/test/converter2/issues/gh${issue}.ts`; + await writeFile(file, ""); + } else { + const ext = process.argv[3] ? `.${process.argv[3]}` : guessExtension(code); + file = `src/test/converter2/issues/gh${issue}${ext}`; + await writeFile(file, code.content); } - const ext = process.argv[3] ? `.${process.argv[3]}` : guessExtension(code); - const file = `src/test/converter2/issues/gh${issue}${ext}`; - await writeFile(file, code.content); console.log(file); console.log("src/test/issues.c2.test.ts"); } diff --git a/src/lib/converter/symbols.ts b/src/lib/converter/symbols.ts index 7358e3e45..8835d6535 100644 --- a/src/lib/converter/symbols.ts +++ b/src/lib/converter/symbols.ts @@ -1378,6 +1378,20 @@ function convertAccessor( const declaration = symbol.getDeclarations()?.[0]; if (declaration) { setModifiers(symbol, declaration, reflection); + + // #3019, auto accessors `accessor x: string` get the symbol flag for + // an accessor, but they don't have get/set accessors, so the need a type + // set on the accessor reflection structure. + if ( + ts.isPropertyDeclaration(declaration) && + declaration.modifiers?.some(n => n.kind === ts.SyntaxKind.AccessorKeyword) + ) { + reflection.type = context.converter.convertType( + context.withScope(reflection), + context.checker.getTypeOfSymbol(symbol), + declaration.type, + ); + } } context.finalizeDeclarationReflection(reflection); diff --git a/src/test/converter/class/specs-with-lump-categories.json b/src/test/converter/class/specs-with-lump-categories.json index 386ab2fe6..e63c9b6a6 100644 --- a/src/test/converter/class/specs-with-lump-categories.json +++ b/src/test/converter/class/specs-with-lump-categories.json @@ -4824,7 +4824,11 @@ "character": 13, "url": "typedoc://getter-setter.ts#L22" } - ] + ], + "type": { + "type": "intrinsic", + "name": "string" + } }, { "id": 190, diff --git a/src/test/converter/class/specs.json b/src/test/converter/class/specs.json index 386ab2fe6..e63c9b6a6 100644 --- a/src/test/converter/class/specs.json +++ b/src/test/converter/class/specs.json @@ -4824,7 +4824,11 @@ "character": 13, "url": "typedoc://getter-setter.ts#L22" } - ] + ], + "type": { + "type": "intrinsic", + "name": "string" + } }, { "id": 190, diff --git a/src/test/converter2/issues/gh3019.ts b/src/test/converter2/issues/gh3019.ts new file mode 100644 index 000000000..0dc0ee36c --- /dev/null +++ b/src/test/converter2/issues/gh3019.ts @@ -0,0 +1,4 @@ +class GH3019 { + accessor x: string = ""; + accessor y: number = 123; +} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 4b8ce14a4..00af3d70b 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2210,6 +2210,12 @@ describe("Issue Tests", () => { logger.expectMessage("warn: Content in the @remarks block will be overwritten*"); }); + it("#3019 correctly parses accessor types", () => { + const project = convert(); + equal(query(project, "GH3019.x").type?.toString(), "string"); + equal(query(project, "GH3019.y").type?.toString(), "number"); + }); + it("#3020 permits preserving type annotations", () => { app.options.setValue("blockTags", ["@fires"]); app.options.setValue("preservedTypeAnnotationTags", ["@fires"]); From fdd83699ff5bfc38ea53f6ee0ac4cfd61ed5046c Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 27 Sep 2025 22:43:46 -0600 Subject: [PATCH 40/46] Improve slugger for headers containing HTML Resolves #3023 --- .gitignore | 2 +- CHANGELOG.md | 1 + scripts/rebuild_specs.js | 2 +- src/lib/output/themes/MarkedPlugin.tsx | 11 +- src/lib/output/themes/default/Slugger.ts | 18 ++- src/lib/utils-common/general.ts | 1 + .../converter2/renderer/renderer-readme.md | 3 + src/test/output/Slugger.test.ts | 11 ++ .../renderer/specs/classes/BaseClass.json | 4 +- .../renderer/specs/classes/GenericClass.json | 4 +- .../specs/classes/ModifiersClass.json | 15 ++- .../renderer/specs/classes/RenderClass.json | 28 +++- src/test/renderer/specs/documents/doc.json | 44 ++++++- .../renderer/specs/enums/Enumeration.json | 25 +++- src/test/renderer/specs/functions/box.json | 8 +- src/test/renderer/specs/index.json | 48 ++++++- .../specs/interfaces/BaseInterface.json | 4 +- .../specs/interfaces/DisabledGroups.json | 10 +- .../ExpandType.ExpandedByDefault.json | 4 +- src/test/renderer/specs/modules.json | 4 +- .../specs/types/ExpandType.AExpanded.json | 4 +- .../specs/types/ExpandType.BExpanded.json | 4 +- .../specs/types/ExpandType.Expandable.json | 4 +- .../specs/types/ExpandType.Expandable2.json | 4 +- .../ExpandType.NestedBehavior1.AExpanded.json | 4 +- ...xpandType.NestedBehavior1.AllExpanded.json | 12 +- src/test/renderer/specs/types/Nested.json | 16 ++- .../renderer/specs/types/UnionComments.json | 8 +- src/test/renderer/testRendererUtils.ts | 121 +++++++++++++++++- 29 files changed, 376 insertions(+), 48 deletions(-) create mode 100644 src/test/converter2/renderer/renderer-readme.md diff --git a/.gitignore b/.gitignore index a223dce66..fbbe7596d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,8 +17,8 @@ yarn-error.log /coverage/ /dist/ /docs -/docs-site /docs2 +/docs-* /td*.json typedoc*.tgz diff --git a/CHANGELOG.md b/CHANGELOG.md index 7815092d4..a8d93e661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ title: Changelog ## Bug Fixes - Fixed conversion of auto-accessor types on properties with the `accessor` keyword, #3019. +- Improved handling of HTML tags within headers for anchor generation, #3023. ## v0.28.13 (2025-09-14) diff --git a/scripts/rebuild_specs.js b/scripts/rebuild_specs.js index dd333c4a7..a0a00cd99 100755 --- a/scripts/rebuild_specs.js +++ b/scripts/rebuild_specs.js @@ -81,7 +81,7 @@ const conversions = [ */ function rebuildConverterTests(dirs) { const program = ts.createProgram(app.options.getFileNames(), { - ...app.options.getCompilerOptions(), + ...app.options.getCompilerOptions(app.logger), noEmit: true, }); diff --git a/src/lib/output/themes/MarkedPlugin.tsx b/src/lib/output/themes/MarkedPlugin.tsx index 924b28ca9..d1b636206 100644 --- a/src/lib/output/themes/MarkedPlugin.tsx +++ b/src/lib/output/themes/MarkedPlugin.tsx @@ -409,10 +409,19 @@ export class MarkedPlugin extends ContextAwareRendererComponent { } function getTokenTextContent(token: md.Token): string { + // If there are children, we want their text content, not the full text content if (token.children) { return token.children.map(getTokenTextContent).join(""); } - return token.content; + + // If this is a simple text fragment, use its content + if (token.type === "text") { + return token.content; + } + + // Otherwise this is some type of metadata token (e.g. header_open) + // or a HTML tag token. Don't include it in the text content. + return ""; } const kindNames = ["note", "tip", "important", "warning", "caution"]; diff --git a/src/lib/output/themes/default/Slugger.ts b/src/lib/output/themes/default/Slugger.ts index 65632cd28..2198ae58e 100644 --- a/src/lib/output/themes/default/Slugger.ts +++ b/src/lib/output/themes/default/Slugger.ts @@ -1,5 +1,5 @@ import { getSimilarValues } from "#utils"; -import type { TypeDocOptionMap } from "../../../utils/index.js"; +import type { TypeDocOptionMap } from "#node-utils"; /** * Responsible for getting a unique anchor for elements within a page. @@ -8,20 +8,28 @@ export class Slugger { private seen = new Map(); private serialize(value: string) { - // Notes: - // There are quite a few trade-offs here. + // There are quite a few trade-offs here. We used to remove HTML tags here, + // but TypeDoc now removes the HTML tags before passing text into the slug + // method, which allows us to skip doing that here. This improves the slugger + // generation for headers which look like the following: + // (html allowed in markdown) + // # test <t> + // (html disallowed in markdown) + // # test + // both of the above should slug to test-t return ( value .trim() - // remove html tags - .replace(/<[!/a-z].*?>/gi, "") // remove unwanted chars .replace( /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, "", ) + // change whitespace to dash .replace(/\s/g, "-") + // combine adjacent dashes + .replace(/--+/, "-") ); } diff --git a/src/lib/utils-common/general.ts b/src/lib/utils-common/general.ts index 1fcab7f2c..d22e76497 100644 --- a/src/lib/utils-common/general.ts +++ b/src/lib/utils-common/general.ts @@ -45,6 +45,7 @@ export function assertNever(x: never): never { export function assert(x: unknown, message = "Assertion failed"): asserts x { if (!x) { + debugger; throw new Error(message); } } diff --git a/src/test/converter2/renderer/renderer-readme.md b/src/test/converter2/renderer/renderer-readme.md new file mode 100644 index 000000000..e6cd8f720 --- /dev/null +++ b/src/test/converter2/renderer/renderer-readme.md @@ -0,0 +1,3 @@ +# gh3023 <test> + +Anchor for above heading should be `gh3023-test` diff --git a/src/test/output/Slugger.test.ts b/src/test/output/Slugger.test.ts index f11f9c1b6..f0c839a22 100644 --- a/src/test/output/Slugger.test.ts +++ b/src/test/output/Slugger.test.ts @@ -13,4 +13,15 @@ describe("Slugger", () => { equal(slugger.slug("model"), "model"); equal(slugger.slug("Model"), "Model-1"); }); + + it("Handles embedded html characters", () => { + const slugger = new Slugger({ lowercase: true }); + equal(slugger.slug("test "), "test-t"); + equal(slugger.slug("test "), "test-t-1"); + }); + + it("Handles adjacent whitespace", () => { + const slugger = new Slugger({ lowercase: true }); + equal(slugger.slug("test test2"), "test-test2"); + }); }); diff --git a/src/test/renderer/specs/classes/BaseClass.json b/src/test/renderer/specs/classes/BaseClass.json index 9aa168302..47bf55a43 100644 --- a/src/test/renderer/specs/classes/BaseClass.json +++ b/src/test/renderer/specs/classes/BaseClass.json @@ -401,7 +401,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Base class method

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Base class method" + } }, { "div.tsd-parameters": [ diff --git a/src/test/renderer/specs/classes/GenericClass.json b/src/test/renderer/specs/classes/GenericClass.json index 8e8824309..38529a94c 100644 --- a/src/test/renderer/specs/classes/GenericClass.json +++ b/src/test/renderer/specs/classes/GenericClass.json @@ -27,7 +27,9 @@ }, { "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": "

    Generic class

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Generic class" + } } }, { diff --git a/src/test/renderer/specs/classes/ModifiersClass.json b/src/test/renderer/specs/classes/ModifiersClass.json index 5d76ca4b9..e4650c528 100644 --- a/src/test/renderer/specs/classes/ModifiersClass.json +++ b/src/test/renderer/specs/classes/ModifiersClass.json @@ -204,7 +204,20 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    #2934 same page link ModifiersClass

    \n" + "div.tsd-comment.tsd-typography": { + "p": [ + "#2934 same page link", + { + "tag": "a.tsd-kind-class", + "props": { + "href": "#" + }, + "children": { + "code": "ModifiersClass" + } + } + ] + } }, { "h4.tsd-returns-title": [ diff --git a/src/test/renderer/specs/classes/RenderClass.json b/src/test/renderer/specs/classes/RenderClass.json index 05fb799e2..47a7ca9ee 100644 --- a/src/test/renderer/specs/classes/RenderClass.json +++ b/src/test/renderer/specs/classes/RenderClass.json @@ -27,7 +27,9 @@ }, { "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": "

    Renderer class

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Renderer class" + } } }, { @@ -101,7 +103,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Index signature

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Index signature" + } } ] } @@ -348,7 +352,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Ctor comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Ctor comment" + } }, { "div.tsd-parameters": [ @@ -482,7 +488,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Property

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Property" + } }, { "aside.tsd-sources": { @@ -942,7 +950,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Method comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Method comment" + } }, { "div.tsd-parameters": [ @@ -1066,7 +1076,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Sig 1 comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Sig 1 comment" + } }, { "h4.tsd-returns-title": [ @@ -1138,7 +1150,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Sig 2 comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Sig 2 comment" + } }, { "div.tsd-parameters": [ diff --git a/src/test/renderer/specs/documents/doc.json b/src/test/renderer/specs/documents/doc.json index e0a58f254..decb74ce4 100644 --- a/src/test/renderer/specs/documents/doc.json +++ b/src/test/renderer/specs/documents/doc.json @@ -21,7 +21,49 @@ } }, { - "div.tsd-panel.tsd-typography": "

    Rendered document

    \n

    Link to this doc: link

    \n
    test();\n
    \n\n
    Note

    \nThis is an alert

    \n
    \n" + "div.tsd-panel.tsd-typography": [ + { + "p": "Rendered document" + }, + { + "p": [ + "Link to this doc:", + { + "tag": "a", + "props": { + "href": "" + }, + "children": "link" + } + ] + }, + { + "pre": [ + { + "code.ts": "test();" + }, + { + "tag": "button", + "props": { + "type": "button" + }, + "children": "Copy" + } + ] + }, + { + "div.tsd-alert.tsd-alert-note": [ + { + "div.tsd-alert-title": { + "span": "Note" + } + }, + { + "p": "This is an alert" + } + ] + } + ] } ] }, diff --git a/src/test/renderer/specs/enums/Enumeration.json b/src/test/renderer/specs/enums/Enumeration.json index 35b35df3c..966a9f2d8 100644 --- a/src/test/renderer/specs/enums/Enumeration.json +++ b/src/test/renderer/specs/enums/Enumeration.json @@ -28,7 +28,18 @@ { "section.tsd-panel.tsd-comment": [ { - "div.tsd-comment.tsd-typography": "

    Enum comment Value1

    \n" + "div.tsd-comment.tsd-typography": { + "p": [ + "Enum comment", + { + "tag": "a.tsd-kind-enum-member", + "props": { + "href": "#value1" + }, + "children": "Value1" + } + ] + } }, { "div.tsd-comment.tsd-typography": { @@ -45,7 +56,9 @@ } ] }, - "

    Block tag

    \n" + { + "p": "Block tag" + } ] } } @@ -165,7 +178,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Value1 comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Value1 comment" + } }, { "aside.tsd-sources": { @@ -216,7 +231,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Value2 comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Value2 comment" + } }, { "aside.tsd-sources": { diff --git a/src/test/renderer/specs/functions/box.json b/src/test/renderer/specs/functions/box.json index 7d317b856..473fcb350 100644 --- a/src/test/renderer/specs/functions/box.json +++ b/src/test/renderer/specs/functions/box.json @@ -105,7 +105,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Signature comment\n#2921 !Promise

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Signature comment\n#2921 !Promise" + } }, { "section.tsd-panel": [ @@ -147,7 +149,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Item comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Item comment" + } } ] } diff --git a/src/test/renderer/specs/index.json b/src/test/renderer/specs/index.json index 358074286..68faaaf24 100644 --- a/src/test/renderer/specs/index.json +++ b/src/test/renderer/specs/index.json @@ -16,13 +16,57 @@ ] }, { - "div.tsd-panel.tsd-typography": "

    Readme text

    \n" + "div.tsd-panel.tsd-typography": [ + { + "h1#gh3023-test.tsd-anchor-link": [ + "gh3023 <test>", + { + "tag": "a.tsd-anchor-icon", + "props": { + "href": "#gh3023-test", + "aria-label": "Permalink" + } + } + ] + }, + { + "p": [ + "Anchor for above heading should be", + { + "code": "gh3023-test" + } + ] + } + ] } ] }, { "div.col-sidebar": { - "div.page-menu": [] + "div.page-menu": { + "tag": "details.tsd-accordion.tsd-page-navigation", + "props": { + "open": true + }, + "children": [ + { + "summary.tsd-accordion-summary": { + "h3": "On This Page" + } + }, + { + "div.tsd-accordion-details": { + "tag": "a", + "props": { + "href": "#gh3023-test" + }, + "children": { + "span": "gh3023 " + } + } + } + ] + } } } ] diff --git a/src/test/renderer/specs/interfaces/BaseInterface.json b/src/test/renderer/specs/interfaces/BaseInterface.json index 0097acc1b..984a18ba0 100644 --- a/src/test/renderer/specs/interfaces/BaseInterface.json +++ b/src/test/renderer/specs/interfaces/BaseInterface.json @@ -325,7 +325,9 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    Interface method

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Interface method" + } }, { "div.tsd-parameters": [ diff --git a/src/test/renderer/specs/interfaces/DisabledGroups.json b/src/test/renderer/specs/interfaces/DisabledGroups.json index 81ddbd754..4d7363857 100644 --- a/src/test/renderer/specs/interfaces/DisabledGroups.json +++ b/src/test/renderer/specs/interfaces/DisabledGroups.json @@ -248,7 +248,15 @@ { "div.tsd-description": [ { - "div.tsd-comment.tsd-typography": "

    link to readme #3006

    \n" + "div.tsd-comment.tsd-typography": { + "p": { + "tag": "a", + "props": { + "href": "../" + }, + "children": "link to readme #3006" + } + } }, { "h4.tsd-returns-title": [ diff --git a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json index 9ee09478a..dd0a91628 100644 --- a/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json +++ b/src/test/renderer/specs/interfaces/ExpandType.ExpandedByDefault.json @@ -181,7 +181,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    B

    \n" + "div.tsd-comment.tsd-typography": { + "p": "B" + } }, { "aside.tsd-sources": { diff --git a/src/test/renderer/specs/modules.json b/src/test/renderer/specs/modules.json index 2c201b7c5..c8247517c 100644 --- a/src/test/renderer/specs/modules.json +++ b/src/test/renderer/specs/modules.json @@ -17,7 +17,9 @@ }, { "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": "

    Module comment

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Module comment" + } } }, { diff --git a/src/test/renderer/specs/types/ExpandType.AExpanded.json b/src/test/renderer/specs/types/ExpandType.AExpanded.json index 948d80e77..054638787 100644 --- a/src/test/renderer/specs/types/ExpandType.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.AExpanded.json @@ -285,7 +285,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    A

    \n" + "div.tsd-comment.tsd-typography": { + "p": "A" + } } ] } diff --git a/src/test/renderer/specs/types/ExpandType.BExpanded.json b/src/test/renderer/specs/types/ExpandType.BExpanded.json index 5ff4ad414..146e2c691 100644 --- a/src/test/renderer/specs/types/ExpandType.BExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.BExpanded.json @@ -337,7 +337,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    B

    \n" + "div.tsd-comment.tsd-typography": { + "p": "B" + } } ] } diff --git a/src/test/renderer/specs/types/ExpandType.Expandable.json b/src/test/renderer/specs/types/ExpandType.Expandable.json index 3415947d4..9a12bb136 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable.json @@ -185,7 +185,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    A

    \n" + "div.tsd-comment.tsd-typography": { + "p": "A" + } }, { "aside.tsd-sources": { diff --git a/src/test/renderer/specs/types/ExpandType.Expandable2.json b/src/test/renderer/specs/types/ExpandType.Expandable2.json index 4352329a9..5adbf8dbe 100644 --- a/src/test/renderer/specs/types/ExpandType.Expandable2.json +++ b/src/test/renderer/specs/types/ExpandType.Expandable2.json @@ -185,7 +185,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    C

    \n" + "div.tsd-comment.tsd-typography": { + "p": "C" + } }, { "aside.tsd-sources": { diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json index dc8d54c08..95b96b709 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AExpanded.json @@ -346,7 +346,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    B

    \n" + "div.tsd-comment.tsd-typography": { + "p": "B" + } } ] } diff --git a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json index 6d9e9baa2..df4424c35 100644 --- a/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json +++ b/src/test/renderer/specs/types/ExpandType.NestedBehavior1.AllExpanded.json @@ -294,7 +294,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    A

    \n" + "div.tsd-comment.tsd-typography": { + "p": "A" + } } ] } @@ -375,7 +377,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    B

    \n" + "div.tsd-comment.tsd-typography": { + "p": "B" + } } ] } @@ -456,7 +460,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    C

    \n" + "div.tsd-comment.tsd-typography": { + "p": "C" + } } ] } diff --git a/src/test/renderer/specs/types/Nested.json b/src/test/renderer/specs/types/Nested.json index 1e79630df..18f04453c 100644 --- a/src/test/renderer/specs/types/Nested.json +++ b/src/test/renderer/specs/types/Nested.json @@ -27,7 +27,9 @@ }, { "section.tsd-panel.tsd-comment": { - "div.tsd-comment.tsd-typography": "

    Type alias with nested properties

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Type alias with nested properties" + } } }, { @@ -383,7 +385,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Another value

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Another value" + } } ] }, @@ -436,7 +440,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    More options

    \n" + "div.tsd-comment.tsd-typography": { + "p": "More options" + } } ] }, @@ -459,7 +465,9 @@ ] }, { - "div.tsd-comment.tsd-typography": "

    Value

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Value" + } } ] } diff --git a/src/test/renderer/specs/types/UnionComments.json b/src/test/renderer/specs/types/UnionComments.json index 06e4ab4f0..aabbcc333 100644 --- a/src/test/renderer/specs/types/UnionComments.json +++ b/src/test/renderer/specs/types/UnionComments.json @@ -60,7 +60,9 @@ "span.tsd-signature-type": "\"abc\"" }, { - "div.tsd-comment.tsd-typography": "

    Commentary on abc

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Commentary on abc" + } } ] }, @@ -70,7 +72,9 @@ "span.tsd-signature-type": "\"def\"" }, { - "div.tsd-comment.tsd-typography": "

    Commentary on def

    \n" + "div.tsd-comment.tsd-typography": { + "p": "Commentary on def" + } } ] } diff --git a/src/test/renderer/testRendererUtils.ts b/src/test/renderer/testRendererUtils.ts index 544e441a7..14632fd4b 100644 --- a/src/test/renderer/testRendererUtils.ts +++ b/src/test/renderer/testRendererUtils.ts @@ -1,10 +1,11 @@ import { type Reflection, resetReflectionID } from "#models"; -import { loadTestHighlighter } from "#node-utils"; +import { HtmlAttributeParser, loadTestHighlighter, ParserState } from "#node-utils"; import { rm } from "node:fs/promises"; import { DefaultTheme, KindRouter, PageEvent, PageKind, type RenderTemplate } from "../../lib/output/index.js"; import { type JsxChildren, type JsxElement, JsxFragment } from "../../lib/utils-common/jsx.elements.js"; import { Raw } from "../../lib/utils-common/jsx.js"; import { getConverter2App, getConverter2Project } from "../programs.js"; +import { assert } from "#utils"; function shouldIgnoreElement(el: JsxElement) { switch (el.tag) { @@ -46,6 +47,120 @@ function collapseStrings(data: any[]): unknown { return data; } +// This is a very hacky html parser only intended to handle output from markdown-it +// for inclusion in the renderer specs. Don't use it for anything that requires actual +// security. +function parseHtmlToJsxElement(html: string): JsxChildren[] { + const stack: JsxElement[] = []; + const output: JsxChildren[] = []; + let pos = 0; + let last = 0; + + function currentChildList() { + if (stack.length) { + return stack[stack.length - 1].children; + } + return output; + } + + function skipWs() { + while (pos < html.length && /\s/.test(html[pos])) ++pos; + } + + function takeWord() { + const start = pos; + while (pos < html.length && /[a-z0-9-]/i.test(html[pos])) ++pos; + return html.slice(start, pos); + } + + function startTag() { + assert(html[pos] === "<"); + + ++pos; + skipWs(); + + const tag = takeWord(); + + const parser = new HtmlAttributeParser(html, pos); + const props: Record = {}; + + while (parser.state !== ParserState.END) { + if (parser.state === ParserState.BeforeAttributeValue) { + parser.step(); + props[parser.currentAttributeName] = parser.currentAttributeValue; + } else { + parser.step(); + } + } + + pos = parser.pos - 1; + + const element = { + tag, + props, + children: [], + }; + + if (html[pos] === "/") { + // self closing tag + currentChildList().push(element); + ++pos; + skipWs(); + } else { + currentChildList().push(element); + stack.push(element); + } + + assert(html[pos] === ">"); + ++pos; + last = pos; + } + + function endTag() { + assert(html[pos] === "<" && html[pos + 1] === "/"); + pos += 2; + skipWs(); + + const tag = takeWord(); + if (stack.length === 0 || stack[stack.length - 1].tag !== tag) { + throw new Error(`Invalid HTML, failed to match end tag: ${tag}`); + } + stack.pop(); + + skipWs(); + assert(html[pos] === ">"); + ++pos; + last = pos; + } + + function saveContent() { + if (pos !== last) { + const content = html.slice(last, pos); + currentChildList().push(content.trim()); + } + last = pos; + } + + while (pos < html.length) { + switch (html[pos]) { + case "<": + saveContent(); + if (html[pos + 1] == "/") { + endTag(); + } else { + startTag(); + } + break; + default: + ++pos; + break; + } + } + + saveContent(); + return output; +} + function renderElementToSnapshot(element: JsxChildren): unknown { if (typeof element === "string" || typeof element === "number" || typeof element === "bigint") { return element.toString().replaceAll("\u00a0", " "); @@ -67,7 +182,7 @@ function renderElementToSnapshot(element: JsxChildren): unknown { if (typeof tag === "function") { if (tag === Raw) { - return String((props as any).html); + return renderElementToSnapshot(parseHtmlToJsxElement(String((props as any).html))); } if (tag === JsxFragment) { return collapseStrings(children.flatMap(renderElementToSnapshot).filter(Boolean)); @@ -155,10 +270,10 @@ export async function buildRendererSpecs(specPath: string) { // Unfortunate not to set this in typedoc.json for converter2, but plenty // of tests expect to test the default option, not this. app2.options.setValue("categorizeByGroup", true); + app2.options.setValue("readme", "src/test/converter2/renderer/renderer-readme.md"); resetReflectionID(); const project = getConverter2Project(["renderer"], "."); - project.readme = [{ kind: "text", text: "Readme text" }]; await app2.generateDocs(project, specPath); await rm(`${specPath}/assets`, { recursive: true }); await rm(`${specPath}/.nojekyll`); From 8ff7d27bb43adb4c9bf42485edbdd59f504428ba Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 27 Sep 2025 22:50:07 -0600 Subject: [PATCH 41/46] Fix lint --- src/lib/utils-common/general.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/utils-common/general.ts b/src/lib/utils-common/general.ts index d22e76497..73f06bcad 100644 --- a/src/lib/utils-common/general.ts +++ b/src/lib/utils-common/general.ts @@ -45,6 +45,7 @@ export function assertNever(x: never): never { export function assert(x: unknown, message = "Assertion failed"): asserts x { if (!x) { + // eslint-disable-next-line no-debugger debugger; throw new Error(message); } From a85a65b145421cf8078720e893a97fa1c2b1b4db Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 4 Oct 2025 09:38:22 -0600 Subject: [PATCH 42/46] Sort `null` and `undefined` last in union types Resolves #3024 --- src/lib/converter/types.ts | 28 +++++++++++++++------- src/test/converter/function/specs.json | 32 +++++++++++++------------- src/test/converter2/issues/gh3024.ts | 5 ++++ src/test/issues.c2.test.ts | 14 ++++++++++- 4 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 src/test/converter2/issues/gh3024.ts diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index 8cd71c246..34314f130 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -1132,7 +1132,7 @@ const unionConverter: TypeConverter = { convertType(context, type) { const types = type.types.map((type) => convertType(context, type)); normalizeUnion(types); - sortLiteralUnion(types); + sortUnion(types); return new UnionType(types); }, @@ -1220,18 +1220,30 @@ function kindToModifier( } } -function sortLiteralUnion(types: SomeType[]) { - if ( - types.some((t) => t.type !== "literal" || typeof t.value !== "number") - ) { +function sortUnion(types: SomeType[]) { + // If every member of the union is a literal numeric type, sort in ascending order + if (types.every(t => t.type === "literal" && typeof t.value === "number")) { + types.sort((a, b) => { + const aLit = a as LiteralType; + const bLit = b as LiteralType; + + return (aLit.value as number) - (bLit.value as number); + }); return; } + // #3024 Otherwise, leave the union in the converted order with the exception of null + // and undefined, which should be sorted last, with null before undefined. types.sort((a, b) => { - const aLit = a as LiteralType; - const bLit = b as LiteralType; + const aIsNull = a.type === "literal" && a.value === null; + const aIsUndef = a.type === "intrinsic" && a.name === "undefined"; + const bIsNull = b.type === "literal" && b.value === null; + const bIsUndef = b.type === "intrinsic" && b.name === "undefined"; + + const aWeight = aIsNull ? 1 : aIsUndef ? 2 : 0; + const bWeight = bIsNull ? 1 : bIsUndef ? 2 : 0; - return (aLit.value as number) - (bLit.value as number); + return aWeight - bWeight; }); } diff --git a/src/test/converter/function/specs.json b/src/test/converter/function/specs.json index 8b391258c..6c66ee7ef 100644 --- a/src/test/converter/function/specs.json +++ b/src/test/converter/function/specs.json @@ -841,19 +841,19 @@ "type": "union", "types": [ { - "type": "intrinsic", - "name": "undefined" + "type": "reference", + "target": 47, + "name": "T", + "package": "typedoc", + "refersToTypeParameter": true }, { "type": "literal", "value": null }, { - "type": "reference", - "target": 47, - "name": "T", - "package": "typedoc", - "refersToTypeParameter": true + "type": "intrinsic", + "name": "undefined" } ] } @@ -921,11 +921,11 @@ "types": [ { "type": "intrinsic", - "name": "undefined" + "name": "boolean" }, { "type": "intrinsic", - "name": "boolean" + "name": "undefined" } ] } @@ -1543,19 +1543,19 @@ "type": "union", "types": [ { - "type": "intrinsic", - "name": "undefined" + "type": "reference", + "target": 51, + "name": "T", + "package": "typedoc", + "refersToTypeParameter": true }, { "type": "literal", "value": null }, { - "type": "reference", - "target": 51, - "name": "T", - "package": "typedoc", - "refersToTypeParameter": true + "type": "intrinsic", + "name": "undefined" } ] } diff --git a/src/test/converter2/issues/gh3024.ts b/src/test/converter2/issues/gh3024.ts new file mode 100644 index 000000000..7d45c6c4f --- /dev/null +++ b/src/test/converter2/issues/gh3024.ts @@ -0,0 +1,5 @@ +export class GH3024 { + method(x: string | undefined) {} + method2(x: string | null) {} + method3(x: string | null | undefined) {} +} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 00af3d70b..17e521b84 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -282,7 +282,7 @@ describe("Issue Tests", () => { const project = convert(); const nullableParam = query(project, "nullable").signatures?.[0] ?.parameters?.[0]; - equal(nullableParam?.type?.toString(), "null | string"); + equal(nullableParam?.type?.toString(), "string | null"); const nonNullableParam = query(project, "nonNullable").signatures?.[0] ?.parameters?.[0]; @@ -2226,4 +2226,16 @@ describe("Issue Tests", () => { equal(btn.comment.blockTags[0].tag, "@fires"); equal(btn.comment.blockTags[0].typeAnnotation, "{CustomEvent<{id: string, source: Element}>}"); }); + + it("#3024 places null and undefined last in unions converted from types", () => { + const project = convert(); + const method = querySig(project, "GH3024.method"); + equal(method.parameters?.[0].type?.toString(), "string | undefined"); + + const method2 = querySig(project, "GH3024.method2"); + equal(method2.parameters?.[0].type?.toString(), "string | null"); + + const method3 = querySig(project, "GH3024.method3"); + equal(method3.parameters?.[0].type?.toString(), "string | null | undefined"); + }); }); From 10092065d08970f1b8bddd0301fee1b1922cb1d4 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 10 Oct 2025 20:46:22 -0600 Subject: [PATCH 43/46] Implement excludePrivateClassFields resolves #3017 --- CHANGELOG.md | 1 + site/options/input.md | 11 ++++++++++- site/options/package-options.md | 1 + src/lib/converter/plugins/CommentPlugin.ts | 16 +++++++++++++++ src/lib/internationalization/locales/de.cts | 1 - src/lib/internationalization/locales/en.cts | 3 ++- src/lib/internationalization/locales/ja.cts | 1 - src/lib/internationalization/locales/ko.cts | 1 - src/lib/internationalization/locales/zh.cts | 1 - src/lib/utils/options/declaration.ts | 1 + src/lib/utils/options/sources/typedoc.ts | 6 ++++++ src/test/converter2/issues/gh3017.ts | 8 ++++++++ src/test/issues.c2.test.ts | 22 +++++++++++++++++++++ src/test/programs.ts | 1 + 14 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/test/converter2/issues/gh3017.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d93e661..87f3e19d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ title: Changelog - Introduced the `preservedTypeAnnotationTags` option to specify tags whose type annotations should be copied to the output documentation, #3020. API: Introduced `typeAnnotation` on `CommentTag` +- Added `excludePrivateClassFields` option to hide `#private` members while allowing `private` members, #3017. ## Bug Fixes diff --git a/site/options/input.md b/site/options/input.md index fbfdbf9a3..cc470cc49 100644 --- a/site/options/input.md +++ b/site/options/input.md @@ -215,7 +215,16 @@ Removes symbols annotated with the `@internal` doc tag. Defaults to true if the typedoc --excludePrivate ``` -Removes private class members from the generated documentation. Defaults to true. +Removes members marked with `private` and `#private` class fields from the generated documentation. Defaults to true. +To include `#private` class fields both this option and [excludePrivateClassFields](#excludeprivateclassfields) must be set to `false`. + +## excludePrivateClassFields + +```bash +typedoc --excludePrivateClassFields +``` + +Removes `#private` class fields from the generated documentation. Defaults to true. ## excludeProtected diff --git a/site/options/package-options.md b/site/options/package-options.md index 047552aee..1f90f4c0f 100644 --- a/site/options/package-options.md +++ b/site/options/package-options.md @@ -41,6 +41,7 @@ at the root level. The following tables indicate where an option should be set. | [`excludeNotDocumentedKinds`](input.md#excludenotdocumentedkinds) | Package | | | [`excludeInternal`](input.md#excludeinternal) | Package | | | [`excludePrivate`](input.md#excludeprivate) | Package | | +| [`excludePrivateClassFields`](input.md#excludeprivateclassfields) | Package | | | [`excludeProtected`](input.md#excludeprotected) | Package | | | [`excludeReferences`](input.md#excludereferences) | Package | | | [`excludeCategories`](input.md#excludecategories) | Package | | diff --git a/src/lib/converter/plugins/CommentPlugin.ts b/src/lib/converter/plugins/CommentPlugin.ts index 67c013b69..abe81d402 100644 --- a/src/lib/converter/plugins/CommentPlugin.ts +++ b/src/lib/converter/plugins/CommentPlugin.ts @@ -134,6 +134,9 @@ export class CommentPlugin extends ConverterComponent { @Option("excludePrivate") accessor excludePrivate!: boolean; + @Option("excludePrivateClassFields") + accessor excludePrivateClassFields!: boolean; + @Option("excludeProtected") accessor excludeProtected!: boolean; @@ -567,6 +570,19 @@ export class CommentPlugin extends ConverterComponent { return true; } + // #3017 this isn't quite right as it may incorrectly detect + // private members named with a hash which aren't actually private + // class fields (e.g. class Foo { "#hash" = 1 }) + // We can't fix this without storing more information about the name, + // which I'm going to put off until #3015 is done. + if ( + reflection.flags.hasFlag(ReflectionFlag.Private) && + reflection.name.startsWith("#") && + this.excludePrivateClassFields + ) { + return true; + } + if ( reflection.flags.hasFlag(ReflectionFlag.Protected) && this.excludeProtected diff --git a/src/lib/internationalization/locales/de.cts b/src/lib/internationalization/locales/de.cts index 3da33fda3..1138d57b9 100644 --- a/src/lib/internationalization/locales/de.cts +++ b/src/lib/internationalization/locales/de.cts @@ -284,7 +284,6 @@ export = localeUtils.buildIncompleteTranslation({ help_excludeNotDocumentedKinds: "Arten von Reflections, die von excludeNotDocumented entfernt werden können", help_excludeInternal: "Verhindert, dass Symbole in der Dokumentation erscheinen, die mit @internal markiert sind", help_excludeCategories: "Schließt Symbole aus dieser Kategorie von der Dokumentation aus", - help_excludePrivate: "Ignoriert private Variablen und Methoden, Standardwert ist true.", help_excludeProtected: "Ignoriert geschützte Variablen und Methoden", help_excludeReferences: "Wird ein Symbol mehrfach exportiert, ignoriere alle außer dem ersten Export", help_externalSymbolLinkMappings: diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index ee7c4f032..2244fe346 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -276,7 +276,8 @@ export = { help_excludeNotDocumentedKinds: "Specify the type of reflections that can be removed by excludeNotDocumented", help_excludeInternal: "Prevent symbols that are marked with @internal from being documented", help_excludeCategories: "Exclude symbols within this category from the documentation", - help_excludePrivate: "Ignore private variables and methods, defaults to true.", + help_excludePrivate: "Ignore members marked with the private keyword and #private class fields, defaults to true.", + help_excludePrivateClassFields: "Ignore #private class fields, defaults to true.", help_excludeProtected: "Ignore protected variables and methods", help_excludeReferences: "If a symbol is exported multiple times, ignore all but the first export", help_externalSymbolLinkMappings: "Define custom links for symbols not included in the documentation", diff --git a/src/lib/internationalization/locales/ja.cts b/src/lib/internationalization/locales/ja.cts index 40c7edf08..95667d273 100644 --- a/src/lib/internationalization/locales/ja.cts +++ b/src/lib/internationalization/locales/ja.cts @@ -194,7 +194,6 @@ export = localeUtils.buildIncompleteTranslation({ help_excludeNotDocumentedKinds: "excludeNotDocumented によって削除できる反射の種類を指定します", help_excludeInternal: "@internal でマークされたシンボルがドキュメント化されないようにする", help_excludeCategories: "このカテゴリ内のシンボルをドキュメントから除外する", - help_excludePrivate: "プライベート変数とメソッドを無視します。デフォルトは true です。", help_excludeProtected: "保護された変数とメソッドを無視する", help_excludeReferences: "シンボルが複数回エクスポートされた場合、最初のエクスポート以外はすべて無視されます。", help_externalSymbolLinkMappings: "ドキュメントに含まれていないシンボルのカスタムリンクを定義する", diff --git a/src/lib/internationalization/locales/ko.cts b/src/lib/internationalization/locales/ko.cts index 904ac25c2..4c62465b8 100644 --- a/src/lib/internationalization/locales/ko.cts +++ b/src/lib/internationalization/locales/ko.cts @@ -62,7 +62,6 @@ export = localeUtils.buildIncompleteTranslation({ help_excludeNotDocumentedKinds: "excludeNotDocumented로 제거될 리플렉션 유형을 지정합니다", help_excludeInternal: "@internal로 표시된 심볼이 문서화되지 않도록 방지합니다", help_excludeCategories: "문서에서 제외할 카테고리 내의 심볼을 제외합니다", - help_excludePrivate: "비공개 변수와 메서드를 무시합니다. 기본값은 true입니다.", help_excludeProtected: "보호된 변수와 메서드를 무시합니다", help_excludeReferences: "심볼이 여러 번 내보내진 경우 첫 번째 내보내기를 제외하고 모두 무시합니다", help_externalSymbolLinkMappings: "문서에 포함되지 않은 심볼에 대한 사용자 정의 링크를 정의합니다", diff --git a/src/lib/internationalization/locales/zh.cts b/src/lib/internationalization/locales/zh.cts index 5a0293423..729577b9c 100644 --- a/src/lib/internationalization/locales/zh.cts +++ b/src/lib/internationalization/locales/zh.cts @@ -233,7 +233,6 @@ export = localeUtils.buildIncompleteTranslation({ help_excludeNotDocumentedKinds: "指定可以通过 excludeNotDocumented 删除的反射类型", help_excludeInternal: "防止标有 @internal 的符号被记录", help_excludeCategories: "从文档中排除此类别中的符号", - help_excludePrivate: "忽略私有变量和方法,默认为 true。", help_excludeProtected: "忽略受保护的变量和方法", help_excludeReferences: "如果一个符号被导出多次,则忽略除第一次导出之外的所有导出", help_externalSymbolLinkMappings: "为文档中未包含的符号定义自定义链接", diff --git a/src/lib/utils/options/declaration.ts b/src/lib/utils/options/declaration.ts index 8a8337fb3..ef5613ca8 100644 --- a/src/lib/utils/options/declaration.ts +++ b/src/lib/utils/options/declaration.ts @@ -207,6 +207,7 @@ export interface TypeDocOptionMap { excludeNotDocumented: boolean; excludeNotDocumentedKinds: ReflectionKind.KindString[]; excludeInternal: boolean; + excludePrivateClassFields: boolean; excludePrivate: boolean; excludeProtected: boolean; excludeReferences: boolean; diff --git a/src/lib/utils/options/sources/typedoc.ts b/src/lib/utils/options/sources/typedoc.ts index 1ef0e7821..f572bfd33 100644 --- a/src/lib/utils/options/sources/typedoc.ts +++ b/src/lib/utils/options/sources/typedoc.ts @@ -189,6 +189,12 @@ export function addTypeDocOptions(options: Pick) { type: ParameterType.Boolean, defaultValue: true, }); + options.addDeclaration({ + name: "excludePrivateClassFields", + help: () => i18n.help_excludePrivateClassFields(), + type: ParameterType.Boolean, + defaultValue: true, + }); options.addDeclaration({ name: "excludeProtected", help: () => i18n.help_excludeProtected(), diff --git a/src/test/converter2/issues/gh3017.ts b/src/test/converter2/issues/gh3017.ts new file mode 100644 index 000000000..83627d4ac --- /dev/null +++ b/src/test/converter2/issues/gh3017.ts @@ -0,0 +1,8 @@ +export class GH3017 { + /** @hidden */ + constructor() {} + #hashPriv = 1; + private priv = 2; + protected prot = 3; + public pub = 4; +} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 17e521b84..835475153 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2210,6 +2210,28 @@ describe("Issue Tests", () => { logger.expectMessage("warn: Content in the @remarks block will be overwritten*"); }); + it("#3017 supports excluding #private fields only", () => { + app.options.setValue("excludePrivate", false); + app.options.setValue("excludePrivateClassFields", false); + let project = convert(); + equal(query(project, "GH3017").children?.map(c => c.name), ["#hashPriv", "priv", "prot", "pub"]); + + app.options.setValue("excludePrivate", false); + app.options.setValue("excludePrivateClassFields", true); + project = convert(); + equal(query(project, "GH3017").children?.map(c => c.name), ["priv", "prot", "pub"]); + + app.options.setValue("excludePrivate", true); + app.options.setValue("excludePrivateClassFields", false); + project = convert(); + equal(query(project, "GH3017").children?.map(c => c.name), ["prot", "pub"]); + + app.options.setValue("excludePrivate", true); + app.options.setValue("excludePrivateClassFields", true); + project = convert(); + equal(query(project, "GH3017").children?.map(c => c.name), ["prot", "pub"]); + }); + it("#3019 correctly parses accessor types", () => { const project = convert(); equal(query(project, "GH3019.x").type?.toString(), "string"); diff --git a/src/test/programs.ts b/src/test/programs.ts index bff126163..1074a8cbd 100644 --- a/src/test/programs.ts +++ b/src/test/programs.ts @@ -35,6 +35,7 @@ export function getConverterApp() { excludeExternals: true, disableSources: false, excludePrivate: false, + excludePrivateClassFields: false, tsconfig: join(getConverterBase(), "tsconfig.json"), externalPattern: ["**/node_modules/**"], plugin: [], From 4ca04c14d676e0dadc1cc63e05a060283e242ea6 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 10 Oct 2025 22:22:00 -0600 Subject: [PATCH 44/46] Handle `@this` tag, improved destructured parameters Resolves #3026 --- CHANGELOG.md | 2 + package.json | 4 +- site/tags.md | 2 +- site/tags/param.md | 17 ++- src/lib/converter/factories/signature.ts | 13 +-- src/lib/converter/plugins/CommentPlugin.ts | 37 ++++--- src/lib/utils/options/tsdoc-defaults.ts | 1 + src/test/TestLogger.ts | 6 +- src/test/behavior.c2.test.ts | 37 ++----- .../behavior/destructuredParamRenames.ts | 101 ++++-------------- src/test/converter2/issues/gh3026.js | 7 ++ src/test/issues.c2.test.ts | 12 +++ tsdoc.json | 5 + 13 files changed, 104 insertions(+), 140 deletions(-) create mode 100644 src/test/converter2/issues/gh3026.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f3e19d5..dbba2ccb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,13 @@ title: Changelog be copied to the output documentation, #3020. API: Introduced `typeAnnotation` on `CommentTag` - Added `excludePrivateClassFields` option to hide `#private` members while allowing `private` members, #3017. +- Added support for TypeScript's `@this` tag for JS files which describe `this` parameters, #3026. ## Bug Fixes - Fixed conversion of auto-accessor types on properties with the `accessor` keyword, #3019. - Improved handling of HTML tags within headers for anchor generation, #3023. +- Improved support for detecting destructured parameters and renaming them to the name used in the doc comment, #3026. ## v0.28.13 (2025-09-14) diff --git a/package.json b/package.json index 6d8ff462d..2c382287d 100644 --- a/package.json +++ b/package.json @@ -73,9 +73,9 @@ "test": "mocha --config .config/mocha.fast.json", "test:cov": "c8 -r lcov mocha --config .config/mocha.fast.json", "doc:c": "node bin/typedoc --tsconfig src/test/converter/tsconfig.json", - "doc:cd": "node --inspect-brk bin/typedoc --tsconfig src/test/converter/tsconfig.json", + "doc:cd": "node --inspect-brk dist/lib/cli.js --tsconfig src/test/converter/tsconfig.json", "doc:c2": "node bin/typedoc --options src/test/converter2 --tsconfig src/test/converter2/tsconfig.json", - "doc:c2d": "node --inspect-brk bin/typedoc --options src/test/converter2 --tsconfig src/test/converter2/tsconfig.json", + "doc:c2d": "node --inspect-brk dist/lib/cli.js --options src/test/converter2 --tsconfig src/test/converter2/tsconfig.json", "example": "cd example && node ../bin/typedoc", "test:full": "c8 -r lcov -r text-summary mocha --config .config/mocha.full.json", "rebuild_specs": "node scripts/rebuild_specs.js", diff --git a/site/tags.md b/site/tags.md index 66787ce67..db8e485fb 100644 --- a/site/tags.md +++ b/site/tags.md @@ -122,7 +122,7 @@ examples for how to use the export ([`@example`](./tags/example.md)). - [`@license`](./tags/license.md) - [`@mergeModuleWith`](./tags/mergeModuleWith.md) - [`@module`](./tags/module.md) -- [`@param`](./tags/param.md) +- [`@param`, `@this`](./tags/param.md) - [`@preventExpand`](./tags/expand.md#preventexpand) - [`@preventInline`](./tags/inline.md#preventinline) - [`@privateRemarks`](./tags/privateRemarks.md) diff --git a/site/tags/param.md b/site/tags/param.md index 1a074f162..d98216e9b 100644 --- a/site/tags/param.md +++ b/site/tags/param.md @@ -2,7 +2,7 @@ title: "@param" --- -# @param +# @param and @this **Tag Kind:** [Block](../tags.md#block-tags)
    **TSDoc Reference:** [@param](https://tsdoc.org/pages/tags/param/) @@ -54,6 +54,21 @@ export function configure({ value }: { value: string }) {} export function configure(options: { value: string }) {} ``` +## `this` Parameters + +Functions which use `this` in JavaScript files may use TypeScript's `@this` tag to define the type of their `this` +parameter. TypeDoc will check for `@this` tags and use their content in the description of the `this` parameter. + +```js +/** + * @this {Request} parameter description for `this` + * @param {Response} response parameter description for `response` + */ +export function hello(response) { + response.write(`Hello ${this.query.name || "world!"}`); +} +``` + ## TSDoc Compatibility The TSDoc standard requires that the `@param` tag _not_ include types and that diff --git a/src/lib/converter/factories/signature.ts b/src/lib/converter/factories/signature.ts index f3dc84e0a..9e5f43587 100644 --- a/src/lib/converter/factories/signature.ts +++ b/src/lib/converter/factories/signature.ts @@ -163,7 +163,7 @@ export function createConstructSignatureWithType( } } - const parameterSymbols: Array = signature.thisParameter + const parameterSymbols = signature.thisParameter ? [signature.thisParameter, ...signature.parameters] : [...signature.parameters]; @@ -207,7 +207,7 @@ export function createConstructSignatureWithType( function convertParameters( context: Context, sigRef: SignatureReflection, - parameters: readonly (ts.Symbol & { type?: ts.Type })[], + parameters: readonly ts.Symbol[], parameterNodes: | readonly ts.ParameterDeclaration[] | readonly ts.JSDocParameterTag[] @@ -226,7 +226,7 @@ function convertParameters( ts.isJSDocParameterTag(declaration), ); const paramRefl = new ParameterReflection( - /__\d+/.test(param.name) ? "__namedParameters" : param.name, + /^__\d+$/.test(param.name) ? "__namedParameters" : param.name, ReflectionKind.Parameter, sigRef, ); @@ -256,7 +256,7 @@ function convertParameters( typeNode = declaration.typeExpression?.type; } } else { - type = param.type; + type = context.checker.getTypeOfSymbol(param); } if ( @@ -295,8 +295,9 @@ function convertParameters( paramRefl.setFlag(ReflectionFlag.Optional, isOptional); // If we have no declaration, then this is an implicitly defined parameter in JS land - // because the method body uses `arguments`... which is always a rest argument - let isRest = true; + // because the method body uses `arguments`... which is always a rest argument, + // unless it is a this parameter defined with @this in JSDoc. + let isRest = param.name !== "this"; if (declaration) { isRest = ts.isParameter(declaration) ? !!declaration.dotDotDotToken diff --git a/src/lib/converter/plugins/CommentPlugin.ts b/src/lib/converter/plugins/CommentPlugin.ts index abe81d402..56f77f15c 100644 --- a/src/lib/converter/plugins/CommentPlugin.ts +++ b/src/lib/converter/plugins/CommentPlugin.ts @@ -37,9 +37,9 @@ import { CategoryPlugin } from "./CategoryPlugin.js"; * (for JS users) will be consumed by TypeScript and need not be preserved * in the comment. * - * Note that param/arg/argument/return/returns are not present. + * Note that param/arg/argument/return/returns/this are not present. * These tags will have their type information stripped when parsing, but still - * provide useful information for documentation. + * may provide useful information for documentation. */ const NEVER_RENDERED = [ "@augments", @@ -48,7 +48,6 @@ const NEVER_RENDERED = [ "@constructor", "@enum", "@extends", - "@this", "@type", "@typedef", "@jsx", @@ -479,26 +478,29 @@ export class CommentPlugin extends ConverterComponent { ) { if (!comment) return; - signature.parameters?.forEach((parameter, index) => { - if (parameter.name === "__namedParameters") { - const commentParams = comment.blockTags.filter( - (tag) => tag.tag === "@param" && !tag.name?.includes("."), - ); - if ( - signature.parameters?.length === commentParams.length && - commentParams[index].name - ) { - parameter.name = commentParams[index].name!; - } + const unusedCommentParams = comment.blockTags.filter( + (tag) => + tag.tag === "@param" && tag.name && !tag.name.includes(".") && + !signature.parameters?.some(p => p.name === tag.name), + ); + + signature.parameters?.forEach((parameter) => { + if (parameter.name === "__namedParameters" && unusedCommentParams.length) { + parameter.name = unusedCommentParams[0].name!; + unusedCommentParams.splice(0, 1); } const tag = comment.getIdentifiedTag(parameter.name, "@param"); if (tag) { - parameter.comment = new Comment( - Comment.cloneDisplayParts(tag.content), - ); + parameter.comment = new Comment(Comment.cloneDisplayParts(tag.content)); parameter.comment.sourcePath = comment.sourcePath; + } else if (parameter.name === "this") { + const thisTag = comment.getTag("@this"); + if (thisTag) { + parameter.comment = new Comment(Comment.cloneDisplayParts(thisTag.content)); + parameter.comment.sourcePath = comment.sourcePath; + } } }); @@ -516,6 +518,7 @@ export class CommentPlugin extends ConverterComponent { this.validateParamTags(signature, comment, signature.parameters || []); + comment.removeTags("@this"); comment.removeTags("@param"); comment.removeTags("@typeParam"); comment.removeTags("@template"); diff --git a/src/lib/utils/options/tsdoc-defaults.ts b/src/lib/utils/options/tsdoc-defaults.ts index 92e19f7c9..1aeabc65a 100644 --- a/src/lib/utils/options/tsdoc-defaults.ts +++ b/src/lib/utils/options/tsdoc-defaults.ts @@ -39,6 +39,7 @@ export const blockTags = [ "@since", "@sortStrategy", "@template", // Alias for @typeParam + "@this", "@type", "@typedef", "@summary", diff --git a/src/test/TestLogger.ts b/src/test/TestLogger.ts index f94670d1b..0975b1692 100644 --- a/src/test/TestLogger.ts +++ b/src/test/TestLogger.ts @@ -41,10 +41,8 @@ export class TestLogger extends Logger { } } - expectNoOtherMessages({ ignoreDebug } = { ignoreDebug: true }) { - const messages = ignoreDebug - ? this.messages.filter((msg) => !msg.startsWith("debug")) - : this.messages; + expectNoOtherMessages() { + const messages = this.messages.filter((msg) => !msg.startsWith("debug")); ok( messages.length === 0, diff --git a/src/test/behavior.c2.test.ts b/src/test/behavior.c2.test.ts index d1b18e0a7..c35d2e91a 100644 --- a/src/test/behavior.c2.test.ts +++ b/src/test/behavior.c2.test.ts @@ -1118,36 +1118,17 @@ describe("Behavior Tests", () => { const params = (name: string) => querySig(project, name).parameters?.map((p) => p.name); - equal(params("functionWithADestructuredParameter"), [ - "destructuredParam", - ]); + equal(params("singleParam"), ["params"]); - equal(params("functionWithADestructuredParameterAndExtraParameters"), [ - "__namedParameters", - "extraParameter", - ]); + equal(params("extraParam"), ["params", "extraParameter"]); - equal( - params( - "functionWithADestructuredParameterAndAnExtraParamDirective", - ), - ["__namedParameters"], - ); - - const logs = [ - 'warn: The signature functionWithADestructuredParameterAndExtraParameters has an @param with name "destructuredParam", which was not used', - 'warn: The signature functionWithADestructuredParameterAndExtraParameters has an @param with name "destructuredParam.paramZ", which was not used', - 'warn: The signature functionWithADestructuredParameterAndExtraParameters has an @param with name "destructuredParam.paramG", which was not used', - 'warn: The signature functionWithADestructuredParameterAndExtraParameters has an @param with name "destructuredParam.paramA", which was not used', - 'warn: The signature functionWithADestructuredParameterAndAnExtraParamDirective has an @param with name "fakeParameter", which was not used', - 'warn: The signature functionWithADestructuredParameterAndAnExtraParamDirective has an @param with name "destructuredParam", which was not used', - 'warn: The signature functionWithADestructuredParameterAndAnExtraParamDirective has an @param with name "destructuredParam.paramZ", which was not used', - 'warn: The signature functionWithADestructuredParameterAndAnExtraParamDirective has an @param with name "destructuredParam.paramG", which was not used', - 'warn: The signature functionWithADestructuredParameterAndAnExtraParamDirective has an @param with name "destructuredParam.paramA", which was not used', - ]; - for (const log of logs) { - logger.expectMessage(log); - } + equal(params("extraParamComment"), ["params"]); + + equal(params("multiParam"), ["params", "params2", "__namedParameters"]); + + logger.expectMessage( + 'warn: The signature extraParamComment has an @param with name "fakeParameter", which was not used', + ); logger.expectNoOtherMessages(); }); diff --git a/src/test/converter2/behavior/destructuredParamRenames.ts b/src/test/converter2/behavior/destructuredParamRenames.ts index 437090c80..83fdd1600 100644 --- a/src/test/converter2/behavior/destructuredParamRenames.ts +++ b/src/test/converter2/behavior/destructuredParamRenames.ts @@ -1,95 +1,34 @@ /** - * This is a function with a destructured parameter. - * - * @param destructuredParam - This is the parameter that is destructured. - * @param destructuredParam.paramZ - This is a string parameter. - * @param destructuredParam.paramG - This is a parameter flagged with any. - * This sentence is placed in the next line. - * - * @param destructuredParam.paramA - * This is a **parameter** pointing to an interface. - * - * ``` - * const value:BaseClass = new BaseClass('test'); - * functionWithArguments('arg', 0, value); - * ``` - * - * @returns This is the return value of the function. + * @param params - desc + * @param params.a - paramZ desc */ -export function functionWithADestructuredParameter({ - paramZ, - paramG, - paramA, -}: { - paramZ: string; - paramG: any; - paramA: Object; -}): number { +export function singleParam({ a }: { a: string }) { return 0; } /** - * This is a function with a destructured parameter and additional undocumented parameters. - * The `@param` directives are ignored because we cannot be certain which parameter they refer to. - * - * @param destructuredParam - This is the parameter that is destructured. - * @param destructuredParam.paramZ - This is a string parameter. - * @param destructuredParam.paramG - This is a parameter flagged with any. - * This sentence is placed in the next line. - * - * @param destructuredParam.paramA - * This is a **parameter** pointing to an interface. - * - * ``` - * const value:BaseClass = new BaseClass('test'); - * functionWithArguments('arg', 0, value); - * ``` - * - * @returns This is the return value of the function. + * @param params - desc */ -export function functionWithADestructuredParameterAndExtraParameters( - { - paramZ, - paramG, - paramA, - }: { - paramZ: string; - paramG: any; - paramA: Object; - }, - extraParameter: string, -): number { +export function extraParam({ a }: { a: string }, extraParameter: string) { return 0; } /** - * This is a function with a destructured parameter and an extra `@param` directive with no corresponding parameter. - * The `@param` directives are ignored because we cannot be certain which corresponds to the real parameter. - * - * @param fakeParameter - This directive does not have a corresponding parameter. - * @param destructuredParam - This is the parameter that is destructured. - * @param destructuredParam.paramZ - This is a string parameter. - * @param destructuredParam.paramG - This is a parameter flagged with any. - * This sentence is placed in the next line. - * - * @param destructuredParam.paramA - * This is a **parameter** pointing to an interface. - * - * ``` - * const value:BaseClass = new BaseClass('test'); - * functionWithArguments('arg', 0, value); - * ``` - * - * @returns This is the return value of the function. + * @param params param + * @param fakeParameter param2 */ -export function functionWithADestructuredParameterAndAnExtraParamDirective({ - paramZ, - paramG, - paramA, -}: { - paramZ: string; - paramG: any; - paramA: Object; -}): number { +export function extraParamComment({ a }: { a: string }) { + return 0; +} + +/** + * @param params params + * @param params2 params2 + */ +export function multiParam( + { a }: { a: string }, + { b }: { b: number }, + { c }: { c: boolean }, +) { return 0; } diff --git a/src/test/converter2/issues/gh3026.js b/src/test/converter2/issues/gh3026.js new file mode 100644 index 000000000..ecd21a98b --- /dev/null +++ b/src/test/converter2/issues/gh3026.js @@ -0,0 +1,7 @@ +/** + * @param {object} params params + * @param {string} params.y y + * @returns {Promise} + * @this {{ x: string }} this param + */ +export async function extendedResponse({ y }) {} diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 835475153..858bda67b 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2260,4 +2260,16 @@ describe("Issue Tests", () => { const method3 = querySig(project, "GH3024.method3"); equal(method3.parameters?.[0].type?.toString(), "string | null | undefined"); }); + + it("#3026 handles @this parameter comments and destructured parameter renames with this parameters", () => { + const project = convert(); + const sig = querySig(project, "extendedResponse"); + equal(sig.parameters?.map(p => p.name), ["this", "params"]); + + const comments = sig.parameters.map(p => Comment.combineDisplayParts(p.comment?.summary)); + equal(comments, ["this param", "params"]); + + const types = sig.parameters.map(p => p.type?.toString()); + equal(types, ["{ x: string }", "{ y: string }"]); + }); }); diff --git a/tsdoc.json b/tsdoc.json index 44391fd71..07d3e835c 100644 --- a/tsdoc.json +++ b/tsdoc.json @@ -146,6 +146,11 @@ "syntaxKind": "block", "allowMultiple": true }, + { + "tagName": "@this", + "syntaxKind": "block", + "allowMultiple": false + }, { "tagName": "@linkcode", "syntaxKind": "inline", From a79f8d5e12c755b78f103f8c8732c4dcd870ca77 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Fri, 10 Oct 2025 22:25:50 -0600 Subject: [PATCH 45/46] Bump version to 0.28.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c382287d..24524f3d9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.13", + "version": "0.28.14", "homepage": "https://typedoc.org", "type": "module", "exports": { From 15f0f2a4058b179e266da3e94cfa7f82b55e3bc1 Mon Sep 17 00:00:00 2001 From: TypeDoc Bot Date: Sat, 11 Oct 2025 04:26:46 +0000 Subject: [PATCH 46/46] Update changelog for release --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbba2ccb9..e769444be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ title: Changelog ## Unreleased +## v0.28.14 (2025-10-11) + ### Features - Introduced the `preservedTypeAnnotationTags` option to specify tags whose type annotations should