typedoc-plugin-mdn-links
Version:
Adds support for linking references to global types like `HTMLElement`, `WebAssembly`, and `Date` to their documentation pages on MDN.
91 lines (90 loc) • 3.31 kB
JavaScript
import { Application, Converter, ParameterType, Reflection, ReflectionSymbolId, splitUnquotedString, } from "typedoc";
import { resolveTsType } from "./typescript.js";
import { resolveWebApiPath } from "./webApi.js";
const defaultModuleSources = ["typescript", "@types/web", "@webgpu/types"];
export function load(app) {
const failed = new Set();
app.options.addDeclaration({
name: "resolveUtilityTypes",
defaultValue: true,
help: "[typedoc-plugin-mdn-links]: Resolve references to Partial, Omit, etc to the TypeScript website.",
type: ParameterType.Boolean,
});
app.options.addDeclaration({
name: "additionalModuleSources",
help: "[typedoc-plugin-mdn-links]: Additional module sources to resolve.",
type: ParameterType.Array,
defaultValue: [],
});
const resolvers = [resolveWebApiPath];
function resolveName(name) {
for (const res of resolvers) {
const result = res(name);
if (result)
return result;
}
}
app.converter.on(Converter.EVENT_BEGIN, () => {
if (app.options.getValue("resolveUtilityTypes")) {
resolvers.push(resolveTsType);
}
});
app.converter.addUnknownSymbolResolver(resolveSymbol);
function resolveSymbol(declaration, _refl, _part, symbolId) {
if (symbolId) {
return resolveDeclaration(makeDeclarationReference(symbolId));
}
return resolveDeclaration(declaration);
}
function resolveDeclaration(declaration) {
const validSources = [
...app.options.getValue("additionalModuleSources"),
...defaultModuleSources,
];
const moduleSource = declaration.moduleSource;
if ((moduleSource && validSources.includes(moduleSource))
|| (!moduleSource && declaration.resolutionStart === "global")) {
const names = declaration.symbolReference?.path;
if (!names)
return;
const dottedName = stringifyPath(names);
const result = resolveName(names);
if (!result && !failed.has(dottedName)) {
failed.add(dottedName);
app.logger.verbose(`[typedoc-plugin-mdn-links]: Failed to resolve type: ${dottedName}`);
}
if (result) {
return {
target: result,
caption: dottedName,
};
}
return result;
}
}
}
function stringifyPath(path) {
let result = path[0].path;
for (const part of path.slice(1)) {
result += part.navigation + part.path;
}
return result;
}
function makeDeclarationReference(symbolId) {
return removeLeadingGlobalRef(symbolId.toDeclarationReference());
}
function removeLeadingGlobalRef(ref) {
// This takes care of lib.esnext.iterator.d.ts which
// defines Iterator under declare global in a special way.
if (ref.resolutionStart === "global"
&& ref.symbolReference?.path?.[0].path === "__global") {
return {
...ref,
symbolReference: {
...ref.symbolReference,
path: ref.symbolReference.path.slice(1),
},
};
}
return ref;
}