diff --git a/.vscode/settings.json b/.vscode/settings.json index f2c994728..b305aa521 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ }, "typescript.tsdk": "./node_modules/typescript/lib", + "dprint.path": "./node_modules/dprint/dprint", // Automatically run the formatter when certain files are saved. "[javascript]": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e4432d04..5d93ff70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,44 @@ title: Changelog ## Unreleased +## v0.28.10 (2025-08-10) + +### 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) + +### Features + +- Add support for TypeScript 5.9, #2989. + +### 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. + +## v0.28.8 (2025-07-28) + +### Features + +- If using JS config files, the `plugin` function can now be given plugin functions to load. +- Permit `-` within tag names to support `typescript-json-schema`'s `@TJS-type` tag, #2972. +- Exposed `Context.createSymbolId` for use by plugins. + +### Bug Fixes + +- Relative links in `` will now be discovered by TypeDoc, #2975. +- Relative links in `` and `` elements will now be discovered by TypeDoc, #2975. +- Improved inherited from/overwrites link discovery to point to parent properties in more cases, #2978 + +### Thanks! + +- @jonathanhefner +- @laymonage + ## v0.28.7 (2025-06-30) ### Features 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/eslint.config.mjs b/eslint.config.mjs index 9544f7862..a72f396c1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -244,6 +244,12 @@ export default tslint.config( eslint.configs.recommended, ...tslint.configs.strictTypeChecked, config, + { + files: ["src/test/**/*"], + rules: { + "@typescript-eslint/no-deprecated": "off", + }, + }, { ignores: [ "eslint.config.mjs", diff --git a/index.html b/index.html new file mode 100644 index 000000000..cf7ca8870 --- /dev/null +++ b/index.html @@ -0,0 +1,6 @@ + + + + Wagtail + + diff --git a/package.json b/package.json index d2bcf6d45..2725280d5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "typedoc", "description": "Create api documentation for TypeScript projects.", - "version": "0.28.7", + "version": "0.28.10", "homepage": "https://typedoc.org", "type": "module", "exports": { @@ -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: {} diff --git a/scripts/build_site.sh b/scripts/build_site.sh index 6c8276895..11622b4d9 100755 --- a/scripts/build_site.sh +++ b/scripts/build_site.sh @@ -14,6 +14,10 @@ fi if [[ -n "$CI" || ! -d example/docs ]]; then cd example pnpm i + # Ignoring warnings here because we inherit from Array, which results in + # a few warnings because the docs in the .d.ts have bad @param comments + # We might want to change TypeDoc's validation logic to make this not a + # warning at some point if the relevant comments show up on both signatures. pnpm run typedoc --logLevel Error cd .. fi @@ -22,7 +26,7 @@ fi git show $(git describe --tags --abbrev=0):CHANGELOG.md | sed 's/#* Unreleased//' > site/generated/CHANGELOG.md # Build the actual site, references the API docs -node bin/typedoc --options site/typedoc.config.jsonc +node bin/typedoc --options site/typedoc.config.jsonc --treatWarningsAsErrors # Create/copy static files node scripts/generate_options_schema.js docs-site/schema.json diff --git a/scripts/clone_api_users.js b/scripts/clone_api_users.js index 3a77f5e6e..d38c890db 100755 --- a/scripts/clone_api_users.js +++ b/scripts/clone_api_users.js @@ -93,6 +93,7 @@ if (import.meta.url.endsWith(process.argv[1])) { } console.log(`Cloning/updating took ${(Date.now() - start) / 1000} seconds`); + console.log(`Output is in ${args.values.output}`); // Check for repos listed in the wrong list const currentMinor = semver.parse(JSON.parse(readFileSync("package.json", "utf-8")).version)?.minor; diff --git a/scripts/generate_options_schema.js b/scripts/generate_options_schema.js index 333444196..8c8375f3f 100644 --- a/scripts/generate_options_schema.js +++ b/scripts/generate_options_schema.js @@ -36,6 +36,7 @@ addTypeDocOptions({ case ParameterType.GlobArray: case ParameterType.PathArray: case ParameterType.ModuleArray: + case ParameterType.PluginArray: data.type = "array"; data.items = { type: "string" }; data.default = /** @type {import("../dist/index.js").ArrayDeclarationOption} */ ( diff --git a/scripts/generate_site_plugins.js b/scripts/generate_site_plugins.js index e7889a8f3..7e0fde228 100644 --- a/scripts/generate_site_plugins.js +++ b/scripts/generate_site_plugins.js @@ -8,7 +8,6 @@ const NEXT_BREAKING_TYPEDOC_VERSION = semver.parse(TYPEDOC_VERSION)?.inc("minor" if (!NEXT_BREAKING_TYPEDOC_VERSION) { throw new Error("Failed to determine next TypeDoc version"); } -console.log(NEXT_BREAKING_TYPEDOC_VERSION); const CACHE_ROOT = "tmp/site-cache"; mkdirSync(CACHE_ROOT, { recursive: true }); 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/scripts/testcase.js b/scripts/testcase.js old mode 100644 new mode 100755 index 365bbe84d..2a5c0d744 --- a/scripts/testcase.js +++ b/scripts/testcase.js @@ -1,3 +1,4 @@ +#!/usr/bin/env node // @ts-check import md from "markdown-it"; import cp from "child_process"; diff --git a/site/options/configuration.md b/site/options/configuration.md index 74c5da8fa..a96aa0859 100644 --- a/site/options/configuration.md +++ b/site/options/configuration.md @@ -106,3 +106,6 @@ typedoc --plugin ./custom-plugin.js Specifies the plugins that should be loaded. By default, no plugins are loaded. See [Plugins](../plugins.md) for a list of available plugins. + +If using a JavaScript configuration file, the `plugin` option may be given +a function which will be called to load a plugin. diff --git a/site/tags/sortStrategy.md b/site/tags/sortStrategy.md index d68e1afcc..c795c08e0 100644 --- a/site/tags/sortStrategy.md +++ b/site/tags/sortStrategy.md @@ -4,7 +4,7 @@ title: "@sortStrategy" # @sortStrategy -**Tag Kind:** [Block](../tags.md#Block-tags)
+**Tag Kind:** [Block](../tags.md#block-tags)
This tag can be used to override the [sort](../options/organization.md#sort) locally for a module, namespace, class, or interface. The override will be applied to direct diff --git a/site/typedoc.config.jsonc b/site/typedoc.config.jsonc index 48f0b91ae..ab9eca333 100644 --- a/site/typedoc.config.jsonc +++ b/site/typedoc.config.jsonc @@ -1,6 +1,7 @@ { "$schema": "https://typedoc.org/schema.json", "logLevel": "Verbose", + "treatWarningsAsErrors": true, "entryPointStrategy": "merge", "entryPoints": [], diff --git a/src/index.ts b/src/index.ts index 88fb52d87..166802605 100644 --- a/src/index.ts +++ b/src/index.ts @@ -139,6 +139,7 @@ export { MinimalSourceFile, type NormalizedPath, type NormalizedPathOrModule, + type NormalizedPathOrModuleOrFunction, type SymbolReference, type TranslatedString, translateTagName, 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/comments/blockLexer.ts b/src/lib/converter/comments/blockLexer.ts index 7bd0bb5af..dae38840f 100644 --- a/src/lib/converter/comments/blockLexer.ts +++ b/src/lib/converter/comments/blockLexer.ts @@ -1,12 +1,15 @@ import ts from "typescript"; import { type Token, TokenSyntaxKind } from "./lexer.js"; import { resolveAliasedSymbol } from "../utils/symbols.js"; -import { createSymbolId } from "../factories/symbol-id.js"; +import type { Context } from "../context.js"; export function* lexBlockComment( file: string, pos = 0, end = file.length, + createSymbolId: Context["createSymbolId"] = () => { + throw new Error("unreachable"); + }, jsDoc: ts.JSDoc | undefined = undefined, checker: ts.TypeChecker | undefined = undefined, ): Generator { @@ -19,6 +22,7 @@ export function* lexBlockComment( end, getLinkTags(jsDoc), checker, + createSymbolId, ) ) { if (token.kind === TokenSyntaxKind.Text) { @@ -82,6 +86,7 @@ function* lexBlockComment2( ts.JSDocLink | ts.JSDocLinkCode | ts.JSDocLinkPlain >, checker: ts.TypeChecker | undefined, + createSymbolId: Context["createSymbolId"], ): Generator { pos += 2; // Leading '/*' end -= 2; // Trailing '*/' @@ -263,7 +268,7 @@ function* lexBlockComment2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/converter/comments/index.ts b/src/lib/converter/comments/index.ts index 5828e711a..7b2b69db7 100644 --- a/src/lib/converter/comments/index.ts +++ b/src/lib/converter/comments/index.ts @@ -13,6 +13,7 @@ import { lexLineComments } from "./lineLexer.js"; import { parseComment } from "./parser.js"; import type { FileRegistry } from "../../models/FileRegistry.js"; import { assertNever, i18n, type Logger } from "#utils"; +import type { Context } from "../context.js"; export interface CommentParserConfig { blockTags: Set; @@ -24,6 +25,22 @@ export interface CommentParserConfig { commentStyle: CommentStyle; } +export interface CommentContext { + config: CommentParserConfig; + logger: Logger; + checker: ts.TypeChecker; + files: FileRegistry; + createSymbolId: Context["createSymbolId"]; +} + +export interface CommentContextOptionalChecker { + config: CommentParserConfig; + logger: Logger; + checker?: ts.TypeChecker | undefined; + files: FileRegistry; + createSymbolId: Context["createSymbolId"]; +} + const jsDocCommentKinds = [ ts.SyntaxKind.JSDocPropertyTag, ts.SyntaxKind.JSDocCallbackTag, @@ -45,10 +62,7 @@ export function clearCommentCache() { function getCommentWithCache( discovered: DiscoveredComment | undefined, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker | undefined, - files: FileRegistry, + context: CommentContextOptionalChecker, ) { if (!discovered) return; @@ -68,22 +82,19 @@ function getCommentWithCache( file.text, ranges[0].pos, ranges[0].end, + context.createSymbolId, jsDoc, - checker, + context.checker, ), - config, file, - logger, - files, + context, ); break; case ts.SyntaxKind.SingleLineCommentTrivia: comment = parseComment( lexLineComments(file.text, ranges), - config, file, - logger, - files, + context, ); break; default: @@ -100,18 +111,15 @@ function getCommentWithCache( function getCommentImpl( commentSource: DiscoveredComment | undefined, - config: CommentParserConfig, - logger: Logger, moduleComment: boolean, - checker: ts.TypeChecker | undefined, - files: FileRegistry, + context: CommentContext, ) { const comment = getCommentWithCache( commentSource, - config, - logger, - config.useTsLinkResolution ? checker : undefined, - files, + { + ...context, + checker: context.config.useTsLinkResolution ? context.checker : undefined, + }, ); if (comment?.getTag("@import") || comment?.getTag("@license")) { @@ -145,10 +153,7 @@ function getCommentImpl( export function getComment( symbol: ts.Symbol, kind: ReflectionKind, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker, - files: FileRegistry, + context: CommentContext, ): Comment | undefined { const declarations = symbol.declarations || []; @@ -158,16 +163,13 @@ export function getComment( ) { return getJsDocComment( declarations[0] as ts.JSDocPropertyLikeTag, - config, - logger, - checker, - files, + context, ); } const sf = declarations.find(ts.isSourceFile); if (sf) { - return getFileComment(sf, config, logger, checker, files); + return getFileComment(sf, context); } const isModule = declarations.some((decl) => { @@ -181,25 +183,19 @@ export function getComment( discoverComment( symbol, kind, - logger, - config.commentStyle, - checker, - !config.suppressCommentWarningsInDeclarationFiles, + context.logger, + context.config.commentStyle, + context.checker, + !context.config.suppressCommentWarningsInDeclarationFiles, ), - config, - logger, isModule, - checker, - files, + context, ); if (!comment && kind === ReflectionKind.Property) { return getConstructorParamPropertyComment( symbol, - config, - logger, - checker, - files, + context, ); } @@ -209,40 +205,28 @@ export function getComment( export function getNodeComment( node: ts.Node, moduleComment: boolean, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker | undefined, - files: FileRegistry, + context: CommentContext, ) { return getCommentImpl( - discoverNodeComment(node, config.commentStyle), - config, - logger, + discoverNodeComment(node, context.config.commentStyle), moduleComment, - checker, - files, + context, ); } export function getFileComment( file: ts.SourceFile, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker | undefined, - files: FileRegistry, + context: CommentContext, ): Comment | undefined { for ( const commentSource of discoverFileComments( file, - config.commentStyle, + context.config.commentStyle, ) ) { const comment = getCommentWithCache( commentSource, - config, - logger, - config.useTsLinkResolution ? checker : undefined, - files, + context, ); if (comment?.getTag("@license") || comment?.getTag("@import")) { @@ -261,16 +245,13 @@ export function getFileComment( function getConstructorParamPropertyComment( symbol: ts.Symbol, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker, - files: FileRegistry, + context: CommentContext, ): Comment | undefined { const decl = symbol.declarations?.find(ts.isParameter); if (!decl) return; const ctor = decl.parent; - const comment = getSignatureComment(ctor, config, logger, checker, files); + const comment = getSignatureComment(ctor, context); const paramTag = comment?.getIdentifiedTag(symbol.name, "@param"); if (paramTag) { @@ -282,18 +263,12 @@ function getConstructorParamPropertyComment( export function getSignatureComment( declaration: ts.SignatureDeclaration | ts.JSDocSignature, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker, - files: FileRegistry, + context: CommentContext, ): Comment | undefined { return getCommentImpl( - discoverSignatureComment(declaration, checker, config.commentStyle), - config, - logger, + discoverSignatureComment(declaration, context.checker, context.config.commentStyle), false, - checker, - files, + context, ); } @@ -304,10 +279,7 @@ export function getJsDocComment( | ts.JSDocTypedefTag | ts.JSDocTemplateTag | ts.JSDocEnumTag, - config: CommentParserConfig, - logger: Logger, - checker: ts.TypeChecker | undefined, - files: FileRegistry, + context: CommentContext, ): Comment | undefined { const file = declaration.getSourceFile(); @@ -331,10 +303,7 @@ export function getJsDocComment( jsDoc: parent, inheritedFromParentDeclaration: false, }, - config, - logger, - config.useTsLinkResolution ? checker : undefined, - files, + context, )!; // And pull out the tag we actually care about. @@ -352,7 +321,7 @@ export function getJsDocComment( // We could just put the same comment on everything, but due to how comment parsing works, // we'd have to search for any @template with a name starting with the first type parameter's name // which feels horribly hacky. - logger.warn( + context.logger.warn( i18n.multiple_type_parameters_on_template_tag_unsupported(), declaration, ); @@ -378,7 +347,7 @@ export function getJsDocComment( // was a comment attached. If there wasn't, then don't error about failing to find // a tag because this is unsupported. if (!ts.isJSDocTemplateTag(declaration)) { - logger.error( + context.logger.error( i18n.failed_to_find_jsdoc_tag_for_name_0(name), declaration, ); diff --git a/src/lib/converter/comments/lineLexer.ts b/src/lib/converter/comments/lineLexer.ts index b7312f433..876494d77 100644 --- a/src/lib/converter/comments/lineLexer.ts +++ b/src/lib/converter/comments/lineLexer.ts @@ -179,7 +179,7 @@ function* lexLineComments2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/converter/comments/parser.ts b/src/lib/converter/comments/parser.ts index b95210555..cc016ab2b 100644 --- a/src/lib/converter/comments/parser.ts +++ b/src/lib/converter/comments/parser.ts @@ -1,6 +1,6 @@ import assert, { ok } from "assert"; import { parseDocument as parseYamlDoc } from "yaml"; -import type { CommentParserConfig } from "./index.js"; +import type { CommentContextOptionalChecker, CommentParserConfig } from "./index.js"; import { Comment, type CommentDisplayPart, CommentTag, type InlineTagDisplayPart } from "../../models/index.js"; import type { MinimalSourceFile } from "#utils"; import { nicePath } from "../../utils/paths.js"; @@ -62,10 +62,8 @@ function makeLookaheadGenerator( export function parseComment( tokens: Generator, - config: CommentParserConfig, file: MinimalSourceFile, - logger: Logger, - files: FileRegistry, + context: CommentContextOptionalChecker, ): Comment { const lexer = makeLookaheadGenerator(tokens); const tok = lexer.done() || lexer.peek(); @@ -75,15 +73,15 @@ export function parseComment( comment.summary = blockContent( comment, lexer, - config, + context.config, i18n, warningImpl, - files, + context.files, ); while (!lexer.done()) { comment.blockTags.push( - blockTag(comment, lexer, config, i18n, warningImpl, files), + blockTag(comment, lexer, context.config, i18n, warningImpl, context.files), ); } @@ -93,19 +91,19 @@ export function parseComment( comment, i18n, () => `${nicePath(file.fileName)}:${file.getLineAndCharacterOfPosition(tok2.pos).line + 1}`, - (message) => logger.warn(message), + (message) => context.logger.warn(message), ); return comment; function warningImpl(message: TranslatedString, token: Token) { if ( - config.suppressCommentWarningsInDeclarationFiles && + context.config.suppressCommentWarningsInDeclarationFiles && hasDeclarationFileExtension(file.fileName) ) { return; } - logger.warn(message, token.pos, file); + context.logger.warn(message, token.pos, file); } } diff --git a/src/lib/converter/comments/rawLexer.ts b/src/lib/converter/comments/rawLexer.ts index e8bc8d6bc..ff063dc11 100644 --- a/src/lib/converter/comments/rawLexer.ts +++ b/src/lib/converter/comments/rawLexer.ts @@ -176,7 +176,7 @@ function* lexCommentString2( if (lookahead !== pos + 1) { while ( lookahead < end && - /[a-z0-9]/i.test(file[lookahead]) + /[a-z0-9-]/i.test(file[lookahead]) ) { lookahead++; } diff --git a/src/lib/converter/comments/textParser.ts b/src/lib/converter/comments/textParser.ts index 6277e9aa2..4078b7aef 100644 --- a/src/lib/converter/comments/textParser.ts +++ b/src/lib/converter/comments/textParser.ts @@ -136,9 +136,11 @@ export function textContent( continue; } - const tagLink = checkTagLink(data); - if (tagLink) { - addRef(tagLink); + const tagLinks = checkTagLink(data); + if (tagLinks.length) { + for (const tagLink of tagLinks) { + addRef(tagLink); + } continue; } @@ -256,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]) @@ -297,52 +305,152 @@ function checkReference(data: TextParserData): RelativeLink | undefined { } /** - * Looks for `` and `` + * Looks for ``, ``, and `` */ -function checkTagLink(data: TextParserData): RelativeLink | undefined { +function checkTagLink(data: TextParserData): RelativeLink[] { const { pos, token } = data; if (token.text.startsWith(" RelativeLink[] + >, +): RelativeLink[] { + const links: RelativeLink[] = []; const parser = new HtmlAttributeParser(data.token.text, data.pos); while (parser.state !== ParserState.END) { if ( parser.state === ParserState.BeforeAttributeValue && - parser.currentAttributeName === attr + Object.prototype.hasOwnProperty.call(attributes, parser.currentAttributeName) ) { parser.step(); - if (isRelativePath(parser.currentAttributeValue)) { - data.pos = parser.pos; - const { target, anchor } = data.files.register( - data.sourcePath, - parser.currentAttributeValue as NormalizedPath, - ) || { target: undefined, anchor: undefined }; - return { - pos: parser.currentAttributeValueStart, - end: parser.currentAttributeValueEnd, - target, - targetAnchor: anchor, - }; - } - return; + links.push(...attributes[parser.currentAttributeName]( + data, + parser.currentAttributeValue, + parser.currentAttributeValueStart, + parser.currentAttributeValueEnd, + )); } parser.step(); } + + return links; +} + +function checkAttributeDirectPath( + data: TextParserData, + text: string, + pos: number, + end: number, +): RelativeLink[] { + if (isRelativePath(text.trim())) { + const { target, anchor } = data.files.register( + data.sourcePath, + text.trim() as NormalizedPath, + ) || { target: undefined, anchor: undefined }; + return [{ + pos, + end, + target, + targetAnchor: anchor, + }]; + } + + return []; +} + +// See https://html.spec.whatwg.org/multipage/images.html#srcset-attribute +function checkAttributeSrcSet(data: TextParserData, text: string, pos: number, _end: number): RelativeLink[] { + const result: RelativeLink[] = []; + + let textPos = 0; + parseImageCandidate(); + while (textPos < text.length && text[textPos] == ",") { + ++textPos; + parseImageCandidate(); + } + + return result; + + function parseImageCandidate() { + // 1. Zero or more ASCII whitespace + while (textPos < text.length && /[\t\r\f\n ]/.test(text[textPos])) ++textPos; + // 2. A valid non-empty URL that does not start or end with a comma + // 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 ,]+/); + + if (url && isRelativePath(url[0])) { + const { target, anchor } = data.files.register( + data.sourcePath, + url[0] as NormalizedPath, + ) || { target: undefined, anchor: undefined }; + result.push({ + pos: pos + textPos, + end: pos + textPos + url[0].length, + target, + targetAnchor: anchor, + }); + } + textPos += url ? url[0].length : 0; + + // 3. Zero or more ASCII whitespace + while (textPos < text.length && /[\t\r\f\n ]/.test(text[textPos])) ++textPos; + + // 4. Zero or one of the following: + { + // A width descriptor, consisting of: ASCII whitespace, a valid non-negative integer giving + // a number greater than zero representing the width descriptor value, and a U+0077 LATIN + // SMALL LETTER W character. + const w = text.slice(textPos).match(/^\+?\d+\s*w/); + textPos += w ? w[0].length : 0; + + // A pixel density descriptor, consisting of: ASCII whitespace, a valid floating-point number + // giving a number greater than zero representing the pixel density descriptor value, and a + // U+0078 LATIN SMALL LETTER X character. + if (!w) { + const x = text.slice(textPos).match(/^\+?\d+(\.\d+)?([eE][+-]\d+)?\s*x/); + textPos += x ? x[0].length : 0; + } + } + + // 5. Zero or more ASCII whitespace + while (textPos < text.length && /[\t\r\f\n ]/.test(text[textPos])) ++textPos; + } } function isRelativePath(link: string) { diff --git a/src/lib/converter/context.ts b/src/lib/converter/context.ts index f2df66df1..7f5697164 100644 --- a/src/lib/converter/context.ts +++ b/src/lib/converter/context.ts @@ -17,10 +17,17 @@ import type { Converter } from "./converter.js"; import { isNamedNode } from "./utils/nodes.js"; import { ConverterEvents } from "./converter-events.js"; import { resolveAliasedSymbol } from "./utils/symbols.js"; -import { getComment, getFileComment, getJsDocComment, getNodeComment, getSignatureComment } from "./comments/index.js"; +import { + type CommentContext, + getComment, + getFileComment, + getJsDocComment, + getNodeComment, + getSignatureComment, +} from "./comments/index.js"; import { getHumanName, getQualifiedName } from "../utils/tsutils.js"; import { findPackageForPath, normalizePath } from "#node-utils"; -import { createSymbolId } from "./factories/symbol-id.js"; +import { createSymbolIdImpl } from "./factories/symbol-id.js"; import { type NormalizedPath, removeIf } from "#utils"; /** @@ -267,7 +274,7 @@ export class Context { ): ReferenceType { const ref = ReferenceType.createUnresolvedReference( name ?? symbol.name, - createSymbolId(symbol), + this.createSymbolId(symbol), context.project, getQualifiedName(symbol, name ?? symbol.name), ); @@ -282,6 +289,18 @@ export class Context { return ref; } + /** + * Create a stable {@link ReflectionSymbolId} for the provided symbol, + * optionally targeting a specific declaration. + * + * @privateRemarks + * This is available on Context so that it can be monkey-patched by typedoc-plugin-missing-exports + * It might also turn out to be generally useful for other plugin users. + */ + createSymbolId(symbol: ts.Symbol, declaration?: ts.Declaration) { + return createSymbolIdImpl(symbol, declaration); + } + addChild(reflection: DeclarationReflection | DocumentReflection) { if (this.scope instanceof ContainerReflection) { this.scope.addChild(reflection); @@ -302,7 +321,7 @@ export class Context { registerReflection(reflection: Reflection, symbol: ts.Symbol | undefined, filePath?: NormalizedPath) { if (symbol) { this.reflectionIdToSymbolMap.set(reflection.id, symbol); - const id = createSymbolId(symbol); + const id = this.createSymbolId(symbol); // #2466 // If we just registered a member of a class or interface, then we need to check if @@ -339,7 +358,7 @@ export class Context { } getReflectionFromSymbol(symbol: ts.Symbol) { - return this.project.getReflectionFromSymbolId(createSymbolId(symbol)); + return this.project.getReflectionFromSymbolId(this.createSymbolId(symbol)); } getSymbolFromReflection(reflection: Reflection) { @@ -351,14 +370,21 @@ export class Context { this._program = program; } + private createCommentContext(): CommentContext { + return { + config: this.converter.config, + logger: this.logger, + checker: this.checker, + files: this.project.files, + createSymbolId: (s, d) => this.createSymbolId(s, d), + }; + } + getComment(symbol: ts.Symbol, kind: ReflectionKind) { return getComment( symbol, kind, - this.converter.config, - this.logger, - this.checker, - this.project.files, + this.createCommentContext(), ); } @@ -366,20 +392,14 @@ export class Context { return getNodeComment( node, moduleComment, - this.converter.config, - this.logger, - this.checker, - this.project.files, + this.createCommentContext(), ); } getFileComment(node: ts.SourceFile) { return getFileComment( node, - this.converter.config, - this.logger, - this.checker, - this.project.files, + this.createCommentContext(), ); } @@ -393,10 +413,7 @@ export class Context { ) { return getJsDocComment( declaration, - this.converter.config, - this.logger, - this.checker, - this.project.files, + this.createCommentContext(), ); } @@ -405,10 +422,7 @@ export class Context { ) { return getSignatureComment( declaration, - this.converter.config, - this.logger, - this.checker, - this.project.files, + this.createCommentContext(), ); } 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/converter/factories/signature.ts b/src/lib/converter/factories/signature.ts index 8bc9727bc..f3dc84e0a 100644 --- a/src/lib/converter/factories/signature.ts +++ b/src/lib/converter/factories/signature.ts @@ -17,7 +17,6 @@ import type { Context } from "../context.js"; import { ConverterEvents } from "../converter-events.js"; import { convertDefaultValue } from "../convert-expression.js"; import { removeUndefined } from "../utils/reflections.js"; -import { createSymbolId } from "./symbol-id.js"; export function createSignature( context: Context, @@ -51,7 +50,7 @@ export function createSignature( if (symbol && declaration) { context.project.registerSymbolId( sigRef, - createSymbolId(symbol, declaration), + context.createSymbolId(symbol, declaration), ); } diff --git a/src/lib/converter/factories/symbol-id.ts b/src/lib/converter/factories/symbol-id.ts index d74964250..75c45cdfe 100644 --- a/src/lib/converter/factories/symbol-id.ts +++ b/src/lib/converter/factories/symbol-id.ts @@ -1,16 +1,14 @@ 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(); -export function createSymbolId(symbol: ts.Symbol, declaration?: ts.Declaration) { +// Don't use this directly, use Context.createSymbolId instead. +export function createSymbolIdImpl(symbol: ts.Symbol, declaration?: ts.Declaration) { declaration ??= symbol.declarations?.[0]; const tsSource = declaration?.getSourceFile().fileName ?? ""; const sourceFileName = resolveDeclarationMaps(tsSource); @@ -50,66 +48,3 @@ export function createSymbolId(symbol: ts.Symbol, declaration?: ts.Declaration) 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/converter/jsdoc.ts b/src/lib/converter/jsdoc.ts index 53836f906..ca9be368e 100644 --- a/src/lib/converter/jsdoc.ts +++ b/src/lib/converter/jsdoc.ts @@ -14,7 +14,6 @@ import { import type { Context } from "./context.js"; import { ConverterEvents } from "./converter-events.js"; import { convertParameterNodes, convertTemplateParameterNodes } from "./factories/signature.js"; -import { createSymbolId } from "./factories/symbol-id.js"; export function convertJsDocAlias( context: Context, @@ -134,7 +133,7 @@ function convertJsDocSignature(context: Context, node: ts.JSDocSignature) { ); context.project.registerSymbolId( signature, - createSymbolId(symbol, node), + context.createSymbolId(symbol, node), ); context.registerReflection(signature, void 0); const signatureCtx = rc.withScope(signature); diff --git a/src/lib/converter/plugins/ImplementsPlugin.ts b/src/lib/converter/plugins/ImplementsPlugin.ts index c79215ed9..cab484371 100644 --- a/src/lib/converter/plugins/ImplementsPlugin.ts +++ b/src/lib/converter/plugins/ImplementsPlugin.ts @@ -110,8 +110,10 @@ export class ImplementsPlugin extends ConverterComponent { project: ProjectReflection, reflection: DeclarationReflection, ) { + if (!reflection.extendedTypes) return; + const extendedTypes = filterMap( - reflection.extendedTypes ?? [], + reflection.extendedTypes, (type) => { return type instanceof ReferenceType && type.reflection instanceof DeclarationReflection @@ -139,23 +141,59 @@ export class ImplementsPlugin extends ConverterComponent { parentMember.signatures ?? [], ) ) { - childSig[key] = ReferenceType.createResolvedReference( + // If we're already pointing at something because TS said we should reference + // it, then don't overwrite the reference. + if (!childSig[key]?.reflection) { + childSig[key] = ReferenceType.createResolvedReference( + `${parent.name}.${parentMember.name}`, + parentSig, + project, + ); + } + } + + if (!child[key]?.reflection) { + child[key] = ReferenceType.createResolvedReference( `${parent.name}.${parentMember.name}`, - parentSig, + parentMember, project, ); } - child[key] = ReferenceType.createResolvedReference( - `${parent.name}.${parentMember.name}`, - parentMember, - project, - ); - this.handleInheritedComments(child, parentMember); } } } + + // #2978, this is very unfortunate. If a child's parent links are broken at this point, + // we replace them with an intentionally broken link so that they won't ever be resolved. + // This is done because if we don't do it then we run into issues where we have a link which + // points to some ReflectionSymbolId which might not exist now, but once we've gone through + // 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 && !isValidRef(child.inheritedFrom)) { + child.inheritedFrom = ReferenceType.createBrokenReference(child.inheritedFrom.name, project); + } + if (child.overwrites && !isValidRef(child.overwrites)) { + child.overwrites = ReferenceType.createBrokenReference(child.overwrites.name, project); + } + + for (const childSig of child.getAllSignatures()) { + if (childSig.inheritedFrom && !isValidRef(childSig.inheritedFrom)) { + childSig.inheritedFrom = ReferenceType.createBrokenReference(childSig.inheritedFrom.name, project); + } + if (childSig.overwrites && !isValidRef(childSig.overwrites)) { + childSig.overwrites = ReferenceType.createBrokenReference(childSig.overwrites.name, project); + } + } + } } private onResolveEnd(context: Context) { @@ -522,9 +560,21 @@ function createLink( symbol: ts.Symbol, isInherit: boolean, ) { - const project = context.project; const name = `${expr.expression.getText()}.${getHumanName(symbol.name)}`; + // We should always have rootSymbols, but check just in case. We use the first + // symbol here as TypeDoc's models don't have multiple symbols for the parent + // reference. This is technically wrong because symbols might be declared in + // multiple locations (interface declaration merging), but that's an uncommon + // enough use case that it doesn't seem worthwhile to complicate the rest of the + // world to deal with it. + // Note that we also need to check that the root symbol isn't this symbol. + // This seems to happen sometimes when dealing with interface inheritance. + const rootSymbols = context.checker.getRootSymbols(symbol); + const ref = rootSymbols.length && rootSymbols[0] != symbol + ? context.createSymbolReference(rootSymbols[0], context, name) + : ReferenceType.createBrokenReference(name, context.project); + link(reflection); link(reflection.getSignature); link(reflection.setSignature); @@ -535,34 +585,21 @@ function createLink( link(sig); } - // Intentionally create broken links here. These will be replaced with real links during - // resolution if we can do so. We create broken links rather than real links because in the - // case of an inherited symbol, we'll end up referencing a single symbol ID rather than one - // for each class. function link( target: DeclarationReflection | SignatureReflection | undefined, ) { if (!target) return; if (clause.token === ts.SyntaxKind.ImplementsKeyword) { - target.implementationOf ??= ReferenceType.createBrokenReference( - name, - project, - ); + target.implementationOf ??= ref; return; } if (isInherit) { target.setFlag(ReflectionFlag.Inherited); - target.inheritedFrom ??= ReferenceType.createBrokenReference( - name, - project, - ); + target.inheritedFrom ??= ref; } else { - target.overwrites ??= ReferenceType.createBrokenReference( - name, - project, - ); + target.overwrites ??= ref; } } } 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)}`, diff --git a/src/lib/converter/types.ts b/src/lib/converter/types.ts index f8b8764ab..56a08bafb 100644 --- a/src/lib/converter/types.ts +++ b/src/lib/converter/types.ts @@ -35,7 +35,6 @@ import { convertParameterNodes, convertTypeParameterNodes, createSignature } fro import { convertSymbol } from "./symbols.js"; import { isObjectType, isTypeReference } from "./utils/nodes.js"; import { removeUndefined } from "./utils/reflections.js"; -import { createSymbolId } from "./factories/symbol-id.js"; export interface TypeConverter< TNode extends ts.TypeNode = ts.TypeNode, @@ -277,7 +276,7 @@ const constructorConverter: TypeConverter = { } context.project.registerSymbolId( signature, - createSymbolId(symbol, node), + context.createSymbolId(symbol, node), ); context.registerReflection(signature, void 0); const signatureCtx = rc.withScope(signature); @@ -380,7 +379,7 @@ const functionTypeConverter: TypeConverter = { ); context.project.registerSymbolId( signature, - createSymbolId(symbol, node), + context.createSymbolId(symbol, node), ); context.registerReflection(signature, undefined); const signatureCtx = rc.withScope(signature); diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index 3c0a45ade..703f37664 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -414,6 +414,7 @@ export = { favicon_must_have_one_of_the_following_extensions_0: "Favicon must have one of the following extensions: {0}", option_0_must_be_an_object: "The '{0}' option must be a non-array object", option_0_must_be_an_array_of_string: "The '{0}' option must be set to an array of strings", + option_0_must_be_an_array_of_string_or_functions: "The '{0}' option must be set to an array of strings/functions", option_0_must_be_a_function: "The '{0}' option must be a function", option_0_must_be_object_with_urls: `{0} must be an object with string labels as keys and URL values`, visibility_filters_only_include_0: `visibilityFilters can only include the following non-@ keys: {0}`, 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: "展开", 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/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/lib/serialization/schema.ts b/src/lib/serialization/schema.ts index 1db8459f5..34debec86 100644 --- a/src/lib/serialization/schema.ts +++ b/src/lib/serialization/schema.ts @@ -58,6 +58,7 @@ type _ModelToObject = T extends M.CommentDisplayPart ? CommentDisplayPart : T extends M.SourceReference ? SourceReference : T extends M.FileRegistry ? FileRegistry : + T extends M.ReflectionSymbolId ? ReflectionSymbolId : never; type Primitive = string | number | undefined | null | boolean; diff --git a/src/lib/utils-common/path.ts b/src/lib/utils-common/path.ts index 507846a51..feec89110 100644 --- a/src/lib/utils-common/path.ts +++ b/src/lib/utils-common/path.ts @@ -1,5 +1,9 @@ import { assert } from "./general.js"; +// Type only import is permitted +// eslint-disable-next-line no-restricted-imports +import type { Application } from "../application.js"; + /** * Represents a normalized path with path separators being `/` * On Windows, drives are represented like `C:/Users` for consistency @@ -15,6 +19,12 @@ export type NormalizedPath = "" | "/" | string & { readonly __normPath: unique s */ export type NormalizedPathOrModule = NormalizedPath | string & { readonly __normPathOrModule: unique symbol }; +/** + * Represents either a {@link NormalizedPath} or a Node module name + * (e.g. `typedoc-plugin-mdn-links` or `@gerrit0/typedoc-plugin`) + */ +export type NormalizedPathOrModuleOrFunction = NormalizedPathOrModule | ((app: Application) => Promise | void); + /** * Represents a glob path configured by a user. */ diff --git a/src/lib/utils-common/validation.ts b/src/lib/utils-common/validation.ts index 8febb48d6..eca8886d9 100644 --- a/src/lib/utils-common/validation.ts +++ b/src/lib/utils-common/validation.ts @@ -120,5 +120,5 @@ export function optional(x: T): Optional { } export function isTagString(x: unknown): x is `@${string}` { - return typeof x === "string" && /^@[a-zA-Z][a-zA-Z0-9]*$/.test(x); + return typeof x === "string" && /^@[a-z][a-z0-9-]*$/i.test(x); } 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"; diff --git a/src/lib/utils/options/declaration.ts b/src/lib/utils/options/declaration.ts index a18c094c2..61ca04387 100644 --- a/src/lib/utils/options/declaration.ts +++ b/src/lib/utils/options/declaration.ts @@ -10,10 +10,12 @@ import { type NeverIfInternal, type NormalizedPath, type NormalizedPathOrModule, + type NormalizedPathOrModuleOrFunction, type TranslatedString, } from "#utils"; import type { TranslationProxy } from "../../internationalization/internationalization.js"; import { createGlobString, normalizePath } from "../paths.js"; +import type { Application } from "../../application.js"; /** @enum */ export const EmitStrategy = { @@ -122,7 +124,8 @@ export type TypeDocOptions = { TypeDocOptionMap[K] extends ManuallyValidatedOption< infer ManuallyValidated > ? ManuallyValidated : - TypeDocOptionMap[K] extends NormalizedPath[] | NormalizedPathOrModule[] | GlobString[] ? string[] : + TypeDocOptionMap[K] extends + NormalizedPath[] | NormalizedPathOrModule[] | NormalizedPathOrModuleOrFunction[] | GlobString[] ? string[] : TypeDocOptionMap[K] extends NormalizedPath ? string : TypeDocOptionMap[K] extends | string @@ -150,6 +153,8 @@ export type TypeDocOptionValues = { | string | string[] | GlobString[] + | NormalizedPathOrModule[] + | NormalizedPathOrModuleOrFunction[] | number | boolean | Record ? TypeDocOptionMap[K] : @@ -183,7 +188,7 @@ export interface TypeDocOptionMap { options: NormalizedPath; tsconfig: NormalizedPath; compilerOptions: unknown; - plugin: NormalizedPathOrModule[]; + plugin: NormalizedPathOrModuleOrFunction[]; lang: string; locales: ManuallyValidatedOption>>; packageOptions: ManuallyValidatedOption< @@ -404,7 +409,9 @@ export type KeyToDeclaration = TypeDocOptionMa TypeDocOptionMap[K] extends string | NormalizedPath ? StringDeclarationOption : TypeDocOptionMap[K] extends number ? NumberDeclarationOption : TypeDocOptionMap[K] extends GlobString[] ? GlobArrayDeclarationOption : - TypeDocOptionMap[K] extends string[] | NormalizedPath[] | NormalizedPathOrModule[] ? ArrayDeclarationOption : + TypeDocOptionMap[K] extends + string[] | NormalizedPath[] | NormalizedPathOrModule[] | NormalizedPathOrModuleOrFunction[] ? + ArrayDeclarationOption : unknown extends TypeDocOptionMap[K] ? MixedDeclarationOption | ObjectDeclarationOption : TypeDocOptionMap[K] extends ManuallyValidatedOption ? | (MixedDeclarationOption & { @@ -452,8 +459,14 @@ export enum ParameterType { PathArray, /** * Resolved according to the config directory if it starts with `.` + * @deprecated since 0.28.8, will be removed in 0.29 */ ModuleArray, + /** + * Resolved according to the config directory if it starts with `.` + * @internal - only intended for use with the plugin option + */ + PluginArray, /** * Relative to the config directory. */ @@ -567,7 +580,9 @@ export interface ArrayDeclarationOption extends DeclarationOptionBase { type: | ParameterType.Array | ParameterType.PathArray - | ParameterType.ModuleArray; + // eslint-disable-next-line @typescript-eslint/no-deprecated + | ParameterType.ModuleArray + | ParameterType.PluginArray; /** * If not specified defaults to an empty array. @@ -673,7 +688,9 @@ export interface ParameterTypeToOptionTypeMap { [ParameterType.Object]: unknown; [ParameterType.Array]: string[]; [ParameterType.PathArray]: NormalizedPath[]; + // eslint-disable-next-line @typescript-eslint/no-deprecated [ParameterType.ModuleArray]: NormalizedPathOrModule[]; + [ParameterType.PluginArray]: Array void | Promise)>; [ParameterType.GlobArray]: GlobString[]; [ParameterType.Flags]: Record; @@ -685,7 +702,7 @@ export type DeclarationOptionToOptionType = T exten T extends FlagsDeclarationOption ? U : ParameterTypeToOptionTypeMap[Exclude]; -function toStringArray(value: unknown, option: DeclarationOption) { +function toStringArray(value: unknown, option: DeclarationOption): string[] { if (Array.isArray(value) && value.every(v => typeof v === "string")) { return value; } else if (typeof value === "string") { @@ -695,6 +712,19 @@ function toStringArray(value: unknown, option: DeclarationOption) { throw new Error(i18n.option_0_must_be_an_array_of_string(option.name)); } +function toStringOrFunctionArray( + value: unknown, + option: DeclarationOption, +): Array void | Promise)> { + if (Array.isArray(value) && value.every(v => typeof v === "string" || typeof v === "function")) { + return value; + } else if (typeof value === "string") { + return [value]; + } + + throw new Error(i18n.option_0_must_be_an_array_of_string_or_functions(option.name)); +} + const converters: { [K in ParameterType]: ( value: unknown, @@ -757,12 +787,20 @@ const converters: { option.validate?.(normalized); return normalized; }, + // eslint-disable-next-line @typescript-eslint/no-deprecated [ParameterType.ModuleArray](value, option, configPath) { const strArrValue = toStringArray(value, option); const resolved = resolveModulePaths(strArrValue, configPath); option.validate?.(resolved); return resolved; }, + [ParameterType.PluginArray](value, option, configPath) { + const arrayValue = toStringOrFunctionArray(value, option); + const resolved = arrayValue.map(plugin => + typeof plugin === "function" ? plugin : resolveModulePath(plugin, configPath) + ); + return resolved; + }, [ParameterType.GlobArray](value, option, configPath) { const toGlobString = (v: unknown) => { const s = String(v); @@ -936,12 +974,19 @@ const defaultGetters: { option.defaultValue?.map((value) => normalizePath(resolve(process.cwd(), value))) ?? [] ); }, + // eslint-disable-next-line @typescript-eslint/no-deprecated [ParameterType.ModuleArray](option) { if (option.defaultValue) { return resolveModulePaths(option.defaultValue, process.cwd()); } return []; }, + [ParameterType.PluginArray](option) { + if (option.defaultValue) { + return resolveModulePaths(option.defaultValue, process.cwd()); + } + return []; + }, [ParameterType.GlobArray](option) { return (option.defaultValue ?? []).map(g => createGlobString(normalizePath(process.cwd()), g)); }, @@ -959,12 +1004,14 @@ export function getDefaultValue(option: DeclarationOption) { } function resolveModulePaths(modules: readonly string[], configPath: string): NormalizedPathOrModule[] { - return modules.map((path) => { - if (path.startsWith(".")) { - return normalizePath(resolve(configPath, path)); - } - return normalizePath(path); - }); + return modules.map(path => resolveModulePath(path, configPath)); +} + +function resolveModulePath(path: string, configPath: string): NormalizedPathOrModule { + if (path.startsWith(".")) { + return normalizePath(resolve(configPath, path)); + } + return normalizePath(path); } function isTsNumericEnum(map: Record) { diff --git a/src/lib/utils/options/readers/arguments.ts b/src/lib/utils/options/readers/arguments.ts index e7a30c73f..9b277d526 100644 --- a/src/lib/utils/options/readers/arguments.ts +++ b/src/lib/utils/options/readers/arguments.ts @@ -6,7 +6,9 @@ import { i18n, type Logger, type TranslatedString } from "#utils"; const ARRAY_OPTION_TYPES = new Set([ ParameterType.Array, ParameterType.PathArray, + // eslint-disable-next-line @typescript-eslint/no-deprecated ParameterType.ModuleArray, + ParameterType.PluginArray, ParameterType.GlobArray, ]); diff --git a/src/lib/utils/options/sources/typedoc.ts b/src/lib/utils/options/sources/typedoc.ts index c04289f8c..c1658768c 100644 --- a/src/lib/utils/options/sources/typedoc.ts +++ b/src/lib/utils/options/sources/typedoc.ts @@ -923,7 +923,7 @@ export function addTypeDocOptions(options: Pick) { options.addDeclaration({ name: "plugin", help: () => i18n.help_plugin(), - type: ParameterType.ModuleArray, + type: ParameterType.PluginArray, }); options.addDeclaration({ name: "logLevel", diff --git a/src/lib/utils/plugins.ts b/src/lib/utils/plugins.ts index 99f726639..591a9cceb 100644 --- a/src/lib/utils/plugins.ts +++ b/src/lib/utils/plugins.ts @@ -3,35 +3,42 @@ import { pathToFileURL } from "url"; import type { Application } from "../application.js"; import { nicePath } from "./paths.js"; -import { i18n, type TranslatedString } from "#utils"; +import { i18n, type NormalizedPathOrModuleOrFunction, type TranslatedString } from "#utils"; export async function loadPlugins( app: Application, - plugins: readonly string[], + plugins: readonly NormalizedPathOrModuleOrFunction[], ) { for (const plugin of plugins) { const pluginDisplay = getPluginDisplayName(plugin); try { - let instance: any; - // Try importing first to avoid warnings about requiring ESM being experimental. - // If that fails due to importing a directory, fall back to require. - try { - // On Windows, we need to ensure this path is a file path. - // Or we'll get ERR_UNSUPPORTED_ESM_URL_SCHEME - const esmPath = isAbsolute(plugin) - ? pathToFileURL(plugin).toString() - : plugin; - instance = await import(esmPath); - } catch (error: any) { - if (error.code === "ERR_UNSUPPORTED_DIR_IMPORT") { - // eslint-disable-next-line @typescript-eslint/no-require-imports - instance = require(plugin); - } else { - throw error; + let initFunction: any; + + if (typeof plugin === "function") { + initFunction = plugin; + } else { + let instance: any; + + // Try importing first to avoid warnings about requiring ESM being experimental. + // If that fails due to importing a directory, fall back to require. + try { + // On Windows, we need to ensure this path is a file path. + // Or we'll get ERR_UNSUPPORTED_ESM_URL_SCHEME + const esmPath = isAbsolute(plugin) + ? pathToFileURL(plugin).toString() + : plugin; + instance = await import(esmPath); + } catch (error: any) { + if (error.code === "ERR_UNSUPPORTED_DIR_IMPORT") { + // eslint-disable-next-line @typescript-eslint/no-require-imports + instance = require(plugin); + } else { + throw error; + } } + initFunction = instance.load; } - const initFunction = instance.load; if (typeof initFunction === "function") { await initFunction(app); @@ -54,7 +61,11 @@ export async function loadPlugins( } } -function getPluginDisplayName(plugin: string) { +function getPluginDisplayName(plugin: NormalizedPathOrModuleOrFunction) { + if (typeof plugin === "function") { + return plugin.name || "function"; + } + const path = nicePath(plugin); if (path.startsWith("./node_modules/")) { return path.substring("./node_modules/".length); diff --git a/src/test/comments.test.ts b/src/test/comments.test.ts index 0d2d77405..352cdba30 100644 --- a/src/test/comments.test.ts +++ b/src/test/comments.test.ts @@ -13,6 +13,10 @@ import { extractTagName } from "../lib/converter/comments/tagName.js"; import { type FileId, FileRegistry } from "../lib/models/FileRegistry.js"; import { dedent, MinimalSourceFile, type NormalizedPath } from "#utils"; +const neverCalled = () => { + throw new Error("Should not be called"); +}; + describe("Block Comment Lexer", () => { function lex(text: string): Token[] { return Array.from(lexBlockComment(text)); @@ -186,7 +190,7 @@ describe("Block Comment Lexer", () => { }); it("Should recognize tags", () => { - const tokens = lex("/* @tag @a @abc234 */"); + const tokens = lex("/* @tag @a @abc234 @abc-234 */"); equal(tokens, [ { kind: TokenSyntaxKind.Tag, text: "@tag", pos: 3 }, @@ -194,6 +198,8 @@ describe("Block Comment Lexer", () => { { kind: TokenSyntaxKind.Tag, text: "@a", pos: 8 }, { kind: TokenSyntaxKind.Text, text: " ", pos: 10 }, { kind: TokenSyntaxKind.Tag, text: "@abc234", pos: 11 }, + { kind: TokenSyntaxKind.Text, text: " ", pos: 18 }, + { kind: TokenSyntaxKind.Tag, text: "@abc-234", pos: 19 }, ]); }); @@ -641,7 +647,7 @@ describe("Line Comment Lexer", () => { }); it("Should recognize tags", () => { - const tokens = lex("// @tag @a @abc234"); + const tokens = lex("// @tag @a @abc234 @abc-234"); equal(tokens, [ { kind: TokenSyntaxKind.Tag, text: "@tag", pos: 3 }, @@ -649,6 +655,8 @@ describe("Line Comment Lexer", () => { { kind: TokenSyntaxKind.Tag, text: "@a", pos: 8 }, { kind: TokenSyntaxKind.Text, text: " ", pos: 10 }, { kind: TokenSyntaxKind.Tag, text: "@abc234", pos: 11 }, + { kind: TokenSyntaxKind.Text, text: " ", pos: 18 }, + { kind: TokenSyntaxKind.Tag, text: "@abc-234", pos: 19 }, ]); }); @@ -993,12 +1001,12 @@ describe("Raw Lexer", () => { }); it("Should not recognize tags", () => { - const tokens = lex("@123 @@ @ @tag @a @abc234"); + const tokens = lex("@123 @@ @ @tag @a @abc234 @abc-234"); equal(tokens, [ { kind: TokenSyntaxKind.Text, - text: "@123 @@ @ @tag @a @abc234", + text: "@123 @@ @ @tag @a @abc234 @abc-234", pos: 0, }, ]); @@ -1155,10 +1163,8 @@ describe("Comment Parser", () => { const content = lexBlockComment(file); const comment = parseComment( content, - config, new MinimalSourceFile(file, "/dev/zero" as NormalizedPath), - logger, - files, + { logger, files, config, createSymbolId: neverCalled }, ); equal( @@ -1182,10 +1188,8 @@ describe("Comment Parser", () => { const content = lexBlockComment(file); const comment = parseComment( content, - config, new MinimalSourceFile(file, "/dev/zero" as NormalizedPath), - logger, - files, + { logger, files, config, createSymbolId: neverCalled }, ); equal( @@ -1210,10 +1214,8 @@ describe("Comment Parser", () => { const content = lexBlockComment(file); const comment = parseComment( content, - config, new MinimalSourceFile(file, "/dev/zero" as NormalizedPath), - logger, - files, + { logger, files, config, createSymbolId: neverCalled }, ); equal( @@ -1238,10 +1240,8 @@ describe("Comment Parser", () => { const content = lexBlockComment(file); const comment = parseComment( content, - config, new MinimalSourceFile(file, "/dev/zero" as NormalizedPath), - logger, - files, + { logger, files, config, createSymbolId: neverCalled }, ); logger.expectMessage( @@ -1258,10 +1258,8 @@ describe("Comment Parser", () => { const content = lexBlockComment(text); const comment = parseComment( content, - config, new MinimalSourceFile(text, "/dev/zero" as NormalizedPath), - logger, - files, + { logger, files, config, createSymbolId: neverCalled }, ); logger.expectNoOtherMessages(); return comment; @@ -1560,6 +1558,7 @@ describe("Comment Parser", () => { * [2]:<./example with space> * [3]: https://example.com * [4]: #hash + * [^footnote]: ./example.md */`); equal( @@ -1581,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[], ); @@ -1632,6 +1631,148 @@ describe("Comment Parser", () => { ); }); + it("Recognizes HTML picture source srcset links", () => { + const comment = getComment(`/** + * + * + * + * + */`); + + equal( + comment.summary, + [ + { kind: "text", text: '\n\n\n', + }, + ] satisfies CommentDisplayPart[], + ); + }); + + it("Recognizes links", () => { + const comment = getComment(`/** + * + */`); + + equal( + comment.summary, + [ + { kind: "text", text: '' }, + ] satisfies CommentDisplayPart[], + ); + }); + + it("Recognizes HTML audio and video src links", () => { + const comment = getComment(`/** + * + * + * + */`); + + equal( + comment.summary, + [ + { kind: "text", text: '\n\n', + }, + ] satisfies CommentDisplayPart[], + ); + }); + + it("Recognizes img tag with both src and srcset", () => { + const comment = getComment(`/** + * + */`); + + equal( + comment.summary, + [ + { kind: "text", text: '', + }, + ] satisfies CommentDisplayPart[], + ); + }); + it("Recognizes HTML anchor links", () => { const comment = getComment(`/** * 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 b629a2d17..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" } ] @@ -2546,8 +2546,8 @@ }, "inheritedFrom": { "type": "reference", - "target": 106, - "name": "Base.base" + "target": 112, + "name": "Child.base" } }, { diff --git a/src/test/converter2/issues/gh2978.ts b/src/test/converter2/issues/gh2978.ts new file mode 100644 index 000000000..9dd8876aa --- /dev/null +++ b/src/test/converter2/issues/gh2978.ts @@ -0,0 +1,15 @@ +export interface Parent { + prop: string; +} + +export interface Child extends Partial {} + +export type Tricky = Omit & { x: number }; + +export interface HasX { + x: string; +} + +export interface InheritsX extends Tricky { + // InheritsX.x should *not* be linked to HasX.x +} 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..2dbb7e53d 100644 --- a/src/test/converter2/renderer/index.ts +++ b/src/test/converter2/renderer/index.ts @@ -135,3 +135,5 @@ export interface DisabledGroups { } export * as ExpandType from "./expandType"; +export * as GH2982 from "./gh2982"; +export { box as boxAlias }; diff --git a/src/test/issues.c2.test.ts b/src/test/issues.c2.test.ts index 94a1b6e76..4aaf6b6f0 100644 --- a/src/test/issues.c2.test.ts +++ b/src/test/issues.c2.test.ts @@ -2135,4 +2135,13 @@ describe("Issue Tests", () => { ["Var", "Comment"], ]); }); + + it("#2978 handles parent properties through mapped types", () => { + const project = convert(); + const prop = query(project, "Child.prop"); + equal(prop.inheritedFrom?.reflection?.getFullName(), "Parent.prop"); + const x = query(project, "InheritsX.x"); + equal(x.inheritedFrom?.reflection?.getFullName(), undefined); + equal(x.inheritedFrom?.name, "Tricky.x"); + }); }); 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 { 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 new file mode 100644 index 000000000..4a14d5c79 --- /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": "123" + }, + "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/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 21b6084dd..cc6e97839 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": [] } @@ -493,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": [] + } + ] + } + ] } ] }, @@ -551,21 +624,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" + } } - } + ] } ] }, @@ -821,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" + ] + } + } + } + ] } ] } 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/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/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": [] + } + } + ] +} 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") { diff --git a/src/test/utils/options/declaration.test.ts b/src/test/utils/options/declaration.test.ts index cd943ab53..ef0252fab 100644 --- a/src/test/utils/options/declaration.test.ts +++ b/src/test/utils/options/declaration.test.ts @@ -239,6 +239,32 @@ describe("Options - conversions", () => { new Error("The 'test' option must be set to an array of strings"), ); + equal( + convert("a,b", optionWithType(ParameterType.PluginArray), ""), + ["a,b"], + ); + equal( + convert( + ["a,b"], + optionWithType(ParameterType.PluginArray), + "", + ), + ["a,b"], + ); + const fn = () => {}; + equal( + convert( + ["a", fn], + optionWithType(ParameterType.PluginArray), + "", + ), + ["a", fn], + ); + throws( + () => convert(true, optionWithType(ParameterType.PluginArray), ""), + new Error("The 'test' option must be set to an array of strings/functions"), + ); + throws( () => convert(true, optionWithType(ParameterType.GlobArray), ""), new Error("The 'test' option must be set to an array of strings"), @@ -256,6 +282,17 @@ describe("Options - conversions", () => { ); }); + it("PluginArray is resolved if relative", () => { + equal( + convert( + ["./foo"], + optionWithType(ParameterType.PluginArray), + "", + ), + [normalizePath(join(process.cwd(), "foo"))], + ); + }); + it("Validates array options", () => { const declaration: ArrayDeclarationOption = { name: "test", @@ -519,6 +556,21 @@ describe("Options - default values", () => { ); }); + it("PluginArray", () => { + equal( + getDefaultValue(getDeclaration(ParameterType.PluginArray, void 0)), + [], + ); + equal( + getDefaultValue(getDeclaration(ParameterType.PluginArray, ["a"])), + ["a"], + ); + equal( + getDefaultValue(getDeclaration(ParameterType.PluginArray, ["./a"])), + [normalizePath(resolve("./a"))], + ); + }); + it("GlobArray", () => { equal( getDefaultValue(getDeclaration(ParameterType.GlobArray, void 0)), diff --git a/src/test/utils/options/default-options.test.ts b/src/test/utils/options/default-options.test.ts index 5975bd99c..8b9ab552c 100644 --- a/src/test/utils/options/default-options.test.ts +++ b/src/test/utils/options/default-options.test.ts @@ -161,11 +161,15 @@ describe("Default Options", () => { describe("blockTags", () => { it("Should disallow non-tags", () => { - throws(() => opts.setValue("blockTags", ["@bad-non-tag"])); + throws(() => opts.setValue("blockTags", ["@bad_tag"])); + throws(() => opts.setValue("blockTags", ["@2bad"])); }); it("Should allow tags", () => { doesNotThrow(() => opts.setValue("blockTags", ["@good"])); + doesNotThrow(() => opts.setValue("blockTags", ["@good2"])); + doesNotThrow(() => opts.setValue("blockTags", ["@Good"])); + doesNotThrow(() => opts.setValue("blockTags", ["@good-tag"])); }); }); diff --git a/src/test/utils/plugins.test.ts b/src/test/utils/plugins.test.ts index 31f5962ba..0199d5ab6 100644 --- a/src/test/utils/plugins.test.ts +++ b/src/test/utils/plugins.test.ts @@ -1,8 +1,9 @@ import { tempdirProject } from "@typestrong/fs-fixture-builder"; -import type { Application } from "../../index.js"; +import { type Application, normalizePath } from "../../index.js"; import { loadPlugins } from "../../lib/utils/plugins.js"; import { TestLogger } from "../TestLogger.js"; import { join, resolve } from "path"; +import { deepStrictEqual as equal } from "assert/strict"; describe("loadPlugins", () => { let logger: TestLogger; @@ -20,7 +21,7 @@ describe("loadPlugins", () => { project.addFile("index.js", "exports.load = function load() {}"); project.write(); - const plugin = resolve(project.cwd, "index.js"); + const plugin = normalizePath(resolve(project.cwd, "index.js")); await loadPlugins(fakeApp, [plugin]); logger.expectMessage(`info: Loaded plugin ${plugin}`); }); @@ -31,10 +32,12 @@ describe("loadPlugins", () => { type: "commonjs", main: "index.js", }); - const plugin = project.addFile( - "index.js", - "exports.load = function load() {}", - ).path; + const plugin = normalizePath( + project.addFile( + "index.js", + "exports.load = function load() {}", + ).path, + ); project.write(); await loadPlugins(fakeApp, [plugin]); @@ -50,11 +53,21 @@ describe("loadPlugins", () => { project.addFile("index.js", "export function load() {}"); project.write(); - const plugin = join(resolve(project.cwd), "index.js"); + const plugin = normalizePath(join(resolve(project.cwd), "index.js")); await loadPlugins(fakeApp, [plugin]); logger.expectMessage(`info: Loaded plugin ${plugin}`); }); + it("Should support loading a function plugin", async () => { + let called = false as boolean; + function testFn() { + called = true; + } + await loadPlugins(fakeApp, [testFn]); + logger.expectMessage(`info: Loaded plugin testFn`); + equal(called, true); + }); + it("Should handle errors when requiring plugins", async () => { using project = tempdirProject(); project.addJsonFile("package.json", { @@ -64,7 +77,7 @@ describe("loadPlugins", () => { project.addFile("index.js", "throw Error('bad')"); project.write(); - const plugin = join(resolve(project.cwd), "index.js"); + const plugin = normalizePath(join(resolve(project.cwd), "index.js")); await loadPlugins(fakeApp, [plugin]); logger.expectMessage(`error: The plugin ${plugin} could not be loaded`); }); @@ -81,7 +94,7 @@ describe("loadPlugins", () => { ); project.write(); - const plugin = join(resolve(project.cwd), "index.js"); + const plugin = normalizePath(join(resolve(project.cwd), "index.js")); await loadPlugins(fakeApp, [plugin]); logger.expectMessage(`error: The plugin ${plugin} could not be loaded`); }); @@ -95,7 +108,7 @@ describe("loadPlugins", () => { project.addFile("index.js", ""); project.write(); - const plugin = join(resolve(project.cwd), "index.js"); + const plugin = normalizePath(join(resolve(project.cwd), "index.js")); await loadPlugins(fakeApp, [plugin]); logger.expectMessage( `error: Invalid structure in plugin ${plugin}, no load function found`,