diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f4ef972..cf45bd22d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - Added `--sourceLinkExternal` option to render source code links as external, #2415. +- TypeDoc no longer requires the `declarationMap` option to be set to true to handle cross-package links in packages mode, #2416. - Added `external-last` option for the `--sort` option, #2418. ### Bug Fixes diff --git a/src/lib/application.ts b/src/lib/application.ts index a45346d08..27dbac364 100644 --- a/src/lib/application.ts +++ b/src/lib/application.ts @@ -41,6 +41,7 @@ import { ApplicationEvents } from "./application-events"; import { findTsConfigFile } from "./utils/tsconfig"; import { deriveRootDir, glob, readFile } from "./utils/fs"; import { resetReflectionID } from "./models/reflections/abstract"; +import { addInferredDeclarationMapPaths } from "./models/reflections/ReflectionSymbolId"; // eslint-disable-next-line @typescript-eslint/no-var-requires const packageInfo = require("../../package.json") as { @@ -590,9 +591,10 @@ export class Application extends ChildableComponent< const origOptions = this.options; const projects: JSONOutput.ProjectReflection[] = []; + const projectsToConvert: { dir: string; options: Options }[] = []; // Generate a json file for each package for (const dir of packageDirs) { - this.logger.info(`Converting project at ${nicePath(dir)}`); + this.logger.verbose(`Reading project at ${nicePath(dir)}`); const opts = origOptions.copyForPackage(dir); await opts.read(this.logger, dir); // Invalid links should only be reported after everything has been merged. @@ -609,7 +611,17 @@ export class Application extends ChildableComponent< continue; } - this.options = opts; + addInferredDeclarationMapPaths( + opts.getCompilerOptions(), + opts.getFileNames(), + ); + + projectsToConvert.push({ dir, options: opts }); + } + + for (const { dir, options } of projectsToConvert) { + this.logger.info(`Converting project at ${nicePath(dir)}`); + this.options = options; const project = await this.convert(); if (project) { this.validate(project); diff --git a/src/lib/models/reflections/ReflectionSymbolId.ts b/src/lib/models/reflections/ReflectionSymbolId.ts index e257872cb..638192c72 100644 --- a/src/lib/models/reflections/ReflectionSymbolId.ts +++ b/src/lib/models/reflections/ReflectionSymbolId.ts @@ -2,7 +2,7 @@ import { existsSync } from "fs"; import { isAbsolute, join, relative, resolve } from "path"; import ts from "typescript"; import type { JSONOutput, Serializer } from "../../serialization/index"; -import { readFile } from "../../utils/fs"; +import { getCommonDirectory, readFile } from "../../utils/fs"; import { getQualifiedName } from "../../utils/tsutils"; import { optional, validate } from "../../utils/validation"; import { normalizePath } from "../../utils/paths"; @@ -61,15 +61,17 @@ export class ReflectionSymbolId { } toObject(serializer: Serializer) { + const sourceFileName = isAbsolute(this.fileName) + ? normalizePath( + relative( + serializer.projectRoot, + resolveDeclarationMaps(this.fileName), + ), + ) + : this.fileName; + return { - sourceFileName: isAbsolute(this.fileName) - ? normalizePath( - relative( - serializer.projectRoot, - resolveDeclarationMaps(this.fileName), - ), - ) - : this.fileName, + sourceFileName, qualifiedName: this.qualifiedName, }; } @@ -77,11 +79,8 @@ export class ReflectionSymbolId { const declarationMapCache = new Map(); -/** - * See also getTsSourceFromJsSource in package-manifest.ts. - */ function resolveDeclarationMaps(file: string): string { - if (!file.endsWith(".d.ts")) return file; + if (!/\.d\.[cm]?ts$/.test(file)) return file; if (declarationMapCache.has(file)) return declarationMapCache.get(file)!; const mapFile = file + ".map"; @@ -123,3 +122,19 @@ function resolveDeclarationMaps(file: string): string { return file; } + +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 = resolve(declDir, relative(rootDir, file)).replace( + /\.([cm]?[tj]s)x?$/, + ".d.$1", + ); + declarationMapCache.set(mapFile, file); + } +}