From 6d323a1a7cd641747ce4ac2f818b0fd53fea24d5 Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sun, 8 Sep 2024 10:39:30 -0600 Subject: [PATCH] Add support for automatic entry points If a package uses a "typedoc" conditional export, then TypeDoc will use that. If not provided, TypeDoc will use the "import" and "node" import conditions Resolves #1937 --- .config/typedoc.json | 2 - CHANGELOG.md | 1 + package-lock.json | 82 ++++++++------- package.json | 3 +- site/index.md | 11 ++- site/options/input.md | 10 ++ src/lib/application.ts | 14 ++- src/lib/converter/converter.ts | 11 --- src/lib/internationalization/locales/en.cts | 3 +- src/lib/internationalization/locales/jp.cts | 3 +- src/lib/internationalization/locales/ko.cts | 3 +- src/lib/internationalization/locales/zh.cts | 2 +- .../models/reflections/ReflectionSymbolId.ts | 1 + src/lib/utils/entry-point.ts | 99 ++++++++++++++++++- src/test/slow/entry-point.test.ts | 6 +- 15 files changed, 184 insertions(+), 67 deletions(-) diff --git a/.config/typedoc.json b/.config/typedoc.json index ca8f116c3..c80327ff2 100644 --- a/.config/typedoc.json +++ b/.config/typedoc.json @@ -14,8 +14,6 @@ "alphabetical-ignoring-documents" ], "name": "TypeDoc API", - "entryPointStrategy": "resolve", - "entryPoints": ["../src/index.ts"], "excludeExternals": true, "excludeInternal": false, diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b6d5023a..31bad7cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ title: Changelog # Beta +- TypeDoc will now discover entry points from `package.json` exports if they are not provided manually, #1937. - Fixed an issue where properties were not properly marked optional in some cases. This primarily affected destructured parameters. - Constructor signatures now use the parent class name as their name (e.g. `X`, not `new X`) - Removed the `hideParameterTypesInTitle` option, this was originally added as a workaround for many signatures overflowing diff --git a/package-lock.json b/package-lock.json index 564291185..06c063694 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", + "resolve-import": "^1.4.6", "shiki": "^1.9.1", "yaml": "^2.4.5" }, @@ -727,7 +728,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -745,7 +745,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -758,7 +757,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -771,14 +769,12 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -796,7 +792,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -812,7 +807,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -890,7 +884,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -1264,7 +1257,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1273,7 +1265,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1634,7 +1625,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1645,8 +1635,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -1691,7 +1680,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1794,14 +1782,12 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/end-of-stream": { "version": "1.4.4", @@ -2305,7 +2291,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -2652,7 +2637,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2712,8 +2696,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", @@ -2755,7 +2738,6 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -3010,7 +2992,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -3255,7 +3236,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -3303,7 +3283,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -3312,7 +3291,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -3329,7 +3307,6 @@ "version": "10.2.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", - "dev": true, "license": "ISC", "engines": { "node": "14 || >=16.14" @@ -3595,6 +3572,42 @@ "node": ">=4" } }, + "node_modules/resolve-import": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.6.tgz", + "integrity": "sha512-CIw9e64QcKcCFUj9+KxUCJPy8hYofv6eVfo3U9wdhCm2E4IjvFnZ6G4/yIC4yP3f11+h6uU5b3LdS7O64LgqrA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "glob": "^10.3.3", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/resolve-import/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -3686,7 +3699,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -3698,7 +3710,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -3716,7 +3727,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -3812,7 +3822,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3827,7 +3836,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3842,7 +3850,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3855,7 +3862,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4154,11 +4160,16 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "license": "ISC" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -4197,7 +4208,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", diff --git a/package.json b/package.json index faffd0ca1..ea899a28f 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "markdown-it": "^14.1.0", "minimatch": "^9.0.5", "shiki": "^1.9.1", - "yaml": "^2.4.5" + "yaml": "^2.4.5", + "resolve-import": "^1.4.6" }, "peerDependencies": { "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x" diff --git a/site/index.md b/site/index.md index 59d96f72a..d014e13f4 100644 --- a/site/index.md +++ b/site/index.md @@ -4,13 +4,20 @@ or a JSON model. ## Quick Start TypeDoc generates documentation based on your exports. It will follow re-exports -to document members declared in other files. +to document members declared in other files for each entry point. ```bash # Install npm install --save-dev typedoc -# Build docs using the exports of src/index.ts +# Build docs using package.json "exports" or "main" fields as entry points +npx typedoc +``` + +If TypeDoc is unable to discover your entry points, they can be provided manually: + +```bash +# Build docs using exports from src/index.ts npx typedoc src/index.ts ``` diff --git a/site/options/input.md b/site/options/input.md index 84e255e2d..f7fd9631c 100644 --- a/site/options/input.md +++ b/site/options/input.md @@ -25,6 +25,16 @@ the exports of these files and create documentation according to the exports. Entry points can be handled in one of four ways, see [--entryPointStrategy](#entryPointStrategy) for details. +If this option is not set, TypeDoc will automatically discover your entry points +according to the ["exports"](https://nodejs.org/api/packages.html#exports) or +["main"](https://nodejs.org/api/packages.html#main) fields in your package.json, +using your tsconfig options to map the JavaScript files back to the original TypeScript +source. + +If a `"typedoc"` [conditional +export](https://nodejs.org/api/packages.html#conditional-exports) is used, +TypeDoc will use it instead of the `"import"` export condition. + The set of entry points provided to TypeDoc determines the names displayed in the documentation. By default, TypeDoc will derive a [basePath](output.md#basePath) based on your entry point paths to determine the displayed module name, but it can be also be set with the [`@module`](../tags/module.md) tag. diff --git a/src/lib/application.ts b/src/lib/application.ts index 9483ab665..15e53d2d2 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -31,6 +31,7 @@ import { getEntryPoints, getPackageDirectories, getWatchEntryPoints, + inferEntryPoints, } from "./utils/entry-point.js"; import { nicePath } from "./utils/paths.js"; import { getLoadedPaths, hasBeenLoadedMultipleTimes } from "./utils/general.js"; @@ -320,11 +321,20 @@ export class Application extends AbstractComponent< return ts.version; } + public async getEntryPoints(): Promise< + DocumentationEntryPoint[] | undefined + > { + if (this.options.isSet("entryPoints")) { + return this.getDefinedEntryPoints(); + } + return inferEntryPoints(this.logger, this.options); + } + /** * Gets the entry points to be documented according to the current `entryPoints` and `entryPointStrategy` options. * May return undefined if entry points fail to be expanded. */ - public getEntryPoints(): DocumentationEntryPoint[] | undefined { + public getDefinedEntryPoints(): DocumentationEntryPoint[] | undefined { return getEntryPoints(this.logger, this.options); } @@ -362,7 +372,7 @@ export class Application extends AbstractComponent< ); } - const entryPoints = this.getEntryPoints(); + const entryPoints = await this.getEntryPoints(); if (!entryPoints) { // Fatal error already reported. diff --git a/src/lib/converter/converter.ts b/src/lib/converter/converter.ts index 39b8be0e3..7314b8bda 100644 --- a/src/lib/converter/converter.ts +++ b/src/lib/converter/converter.ts @@ -492,17 +492,6 @@ export class Converter extends AbstractComponent { reflection.comment = context.getFileComment(node); } - if (entryPoint.readmeFile) { - const readme = readFile(entryPoint.readmeFile); - const { content } = this.parseRawComment( - new MinimalSourceFile(readme, entryPoint.readmeFile), - context.project.files, - ); - reflection.readme = content; - } - - reflection.packageVersion = entryPoint.version; - context.finalizeDeclarationReflection(reflection); moduleContext = context.withScope(reflection); } diff --git a/src/lib/internationalization/locales/en.cts b/src/lib/internationalization/locales/en.cts index 5e70261c9..e6fbd9fbd 100644 --- a/src/lib/internationalization/locales/en.cts +++ b/src/lib/internationalization/locales/en.cts @@ -132,7 +132,7 @@ export = { // entry points no_entry_points_provided: - "No entry points were provided, this is likely a misconfiguration", + "No entry points were provided or discovered from package.json exports, this is likely a misconfiguration", unable_to_find_any_entry_points: "Unable to find any entry points. See previous warnings", watch_does_not_support_packages_mode: @@ -140,6 +140,7 @@ export = { watch_does_not_support_merge_mode: "Watch mode does not support 'merge' style entry points", entry_point_0_not_in_program: `The entry point {0} is not referenced by the 'files' or 'include' option in your tsconfig`, + failed_to_resolve_0_to_ts_path: `Failed to resolve entry point path {0} from package.json to a TypeScript source file`, use_expand_or_glob_for_files_in_dir: `If you wanted to include files inside this directory, set --entryPointStrategy to expand or specify a glob`, glob_0_did_not_match_any_files: `The glob {0} did not match any files`, entry_point_0_did_not_match_any_files_after_exclude: `The glob {0} did not match any files after applying exclude patterns`, diff --git a/src/lib/internationalization/locales/jp.cts b/src/lib/internationalization/locales/jp.cts index 20bf3bed9..2ae3cd3ee 100644 --- a/src/lib/internationalization/locales/jp.cts +++ b/src/lib/internationalization/locales/jp.cts @@ -146,8 +146,7 @@ export = localeUtils.buildIncompleteTranslation({ "テーマ '{0}' は定義されていません。使用可能なテーマは次のとおりです: {1}", custom_theme_does_not_define_getSlugger: "カスタムテーマはgetSlugger(reflection)メソッドを定義していませんが、マークダウンをレンダリングしようとします", - no_entry_points_provided: - "エントリポイントが提供されていません。これは設定ミスである可能性があります。", + // no_entry_points_provided: unable_to_find_any_entry_points: "エントリ ポイントが見つかりません。以前の警告を参照してください", watch_does_not_support_packages_mode: diff --git a/src/lib/internationalization/locales/ko.cts b/src/lib/internationalization/locales/ko.cts index 6a52fb8a3..b002c860b 100644 --- a/src/lib/internationalization/locales/ko.cts +++ b/src/lib/internationalization/locales/ko.cts @@ -43,8 +43,7 @@ export = localeUtils.buildIncompleteTranslation({ "다음 심볼은 의도적으로 내보내지 않았지만 문서화에서 참조되지 않았거나 내보내졌습니다:\n\t{0}", defaulting_project_name: '--name 옵션이 지정되지 않았고 package.json도 발견되지 않았습니다. 프로젝트 이름을 "Documentation"으로 기본 설정합니다', - no_entry_points_provided: - "진입점이 제공되지 않았습니다. 이는 구성 오류일 가능성이 높습니다", + // no_entry_points_provided: unable_to_find_any_entry_points: "어떤 진입점도 찾을 수 없습니다. 이전 경고를 확인하세요", watch_does_not_support_packages_mode: diff --git a/src/lib/internationalization/locales/zh.cts b/src/lib/internationalization/locales/zh.cts index 3d756dcd4..55ce900ff 100644 --- a/src/lib/internationalization/locales/zh.cts +++ b/src/lib/internationalization/locales/zh.cts @@ -128,7 +128,7 @@ export = localeUtils.buildIncompleteTranslation({ theme_0_is_not_defined_available_are_1: "主题“{0}”未定义。可用主题为:{1}", custom_theme_does_not_define_getSlugger: "自定义主题没有定义 getSlugger(reflection) 方法,但尝试渲染 markdown", - no_entry_points_provided: "没有提供入口点,这可能是配置错误", + // no_entry_points_provided: unable_to_find_any_entry_points: "无法找到任何入口点。请参阅先前的警告", watch_does_not_support_packages_mode: "监视模式不支持“包”样式的入口点", watch_does_not_support_merge_mode: "监视模式不支持“合并”样式的入口点", diff --git a/src/lib/models/reflections/ReflectionSymbolId.ts b/src/lib/models/reflections/ReflectionSymbolId.ts index 8d1be7815..f4e3b4511 100644 --- a/src/lib/models/reflections/ReflectionSymbolId.ts +++ b/src/lib/models/reflections/ReflectionSymbolId.ts @@ -141,6 +141,7 @@ function resolveDeclarationMaps(file: string): string { return file; } +// See also: inferEntryPoints in entry-point.ts export function addInferredDeclarationMapPaths( opts: ts.CompilerOptions, files: readonly string[], diff --git a/src/lib/utils/entry-point.ts b/src/lib/utils/entry-point.ts index 527e6523d..393d3ab74 100644 --- a/src/lib/utils/entry-point.ts +++ b/src/lib/utils/entry-point.ts @@ -1,4 +1,4 @@ -import { join, relative, resolve } from "path"; +import { dirname, join, relative, resolve } from "path"; import ts from "typescript"; import * as FS from "fs"; import { expandPackages } from "./package-manifest.js"; @@ -10,8 +10,16 @@ import { } from "./paths.js"; import type { Logger } from "./loggers.js"; import type { Options } from "./options/index.js"; -import { deriveRootDir, glob, isDir } from "./fs.js"; +import { + deriveRootDir, + discoverPackageJson, + getCommonDirectory, + glob, + isDir, +} from "./fs.js"; import { assertNever } from "./general.js"; +import { resolveAllExports } from "resolve-import/resolve-all-exports"; +import { fileURLToPath } from "url"; /** * Defines how entry points are interpreted. @@ -44,10 +52,8 @@ export type EntryPointStrategy = export interface DocumentationEntryPoint { displayName: string; - readmeFile?: string; program: ts.Program; sourceFile: ts.SourceFile; - version?: string; } export interface DocumentEntryPoint { @@ -55,6 +61,91 @@ export interface DocumentEntryPoint { path: string; } +export async function inferEntryPoints(logger: Logger, options: Options) { + const packageJson = discoverPackageJson(process.cwd()); + if (!packageJson) { + logger.warn(logger.i18n.no_entry_points_provided()); + return []; + } + + const entries = await resolveAllExports(packageJson.file, { + conditions: ["typedoc", "import", "node"], + }); + const pathEntries = Object.entries(entries).map(([k, v]) => { + if (typeof v === "object") { + return [k, fileURLToPath(v)]; + } + return [k, v]; + }); + + // resolveAllExports doesn't create a fake export for "main" + // so do that here if we don't have any exports. + if (pathEntries.length === 0) { + if ( + "main" in packageJson.content && + typeof packageJson.content["main"] === "string" + ) { + pathEntries.push([ + ".", + resolve(dirname(packageJson.file), packageJson.content["main"]), + ]); + } + } + + const entryPoints: DocumentationEntryPoint[] = []; + + const programs = getEntryPrograms( + pathEntries.map((p) => p[1]), + logger, + options, + ); + + // See also: addInferredDeclarationMapPaths in ReflectionSymbolId + const jsToTsSource = new Map(); + for (const program of programs) { + const opts = program.getCompilerOptions(); + const rootDir = + opts.rootDir || getCommonDirectory(program.getRootFileNames()); + const outDir = opts.outDir || rootDir; + + for (const tsFile of program.getRootFileNames()) { + const jsFile = normalizePath( + resolve(outDir, relative(rootDir, tsFile)).replace( + /\.([cm]?)[tj]sx?$/, + ".$1js", + ), + ); + jsToTsSource.set(jsFile, tsFile); + } + } + + for (const [name, path] of pathEntries) { + // Strip leading ./ from the display name + const displayName = name.replace(/^\.\/?/, ""); + const targetPath = jsToTsSource.get(path) || path; + + const program = programs.find((p) => p.getSourceFile(targetPath)); + if (program) { + entryPoints.push({ + displayName, + program, + sourceFile: program.getSourceFile(targetPath)!, + }); + } else if (/\.[cm]?js$/.test(path)) { + logger.warn( + logger.i18n.failed_to_resolve_0_to_ts_path(nicePath(path)), + ); + } + } + + if (entryPoints.length === 0) { + logger.warn(logger.i18n.no_entry_points_provided()); + return []; + } + + return entryPoints; +} + export function getEntryPoints( logger: Logger, options: Options, diff --git a/src/test/slow/entry-point.test.ts b/src/test/slow/entry-point.test.ts index 0300e89d7..082ffcd56 100644 --- a/src/test/slow/entry-point.test.ts +++ b/src/test/slow/entry-point.test.ts @@ -33,7 +33,7 @@ describe("Entry Points", () => { entryPointStrategy: EntryPointStrategy.Expand, }); - const entryPoints = app.getEntryPoints(); + const entryPoints = app.getDefinedEntryPoints(); ok(entryPoints); equal( entryPoints.length, @@ -49,7 +49,7 @@ describe("Entry Points", () => { entryPointStrategy: EntryPointStrategy.Expand, }); - const entryPoints = app.getEntryPoints(); + const entryPoints = app.getDefinedEntryPoints(); ok(entryPoints); equal( entryPoints.length, @@ -65,7 +65,7 @@ describe("Entry Points", () => { entryPointStrategy: EntryPointStrategy.Resolve, }); - const entryPoints = app.getEntryPoints(); + const entryPoints = app.getDefinedEntryPoints(); ok(entryPoints); equal( entryPoints.length,