typedoc
Version:
Create api documentation for TypeScript projects.
66 lines (65 loc) • 3.09 kB
JavaScript
import { ok } from "assert";
import { discoverAllReferenceTypes } from "../utils/reflections.js";
import { i18n } from "#utils";
function makeIntentionallyExportedHelper(project, intentional, logger) {
const used = new Set();
const processed = intentional.map((v) => {
const index = v.lastIndexOf(":");
if (index === -1) {
return ["", v];
}
return [v.substring(0, index), v.substring(index + 1)];
});
return {
has(type, typeName) {
ok(!type.reflection);
// If it isn't declared anywhere, we can't produce a good error message about where
// the non-exported symbol is, so even if it isn't ignored, pretend it is. In practice,
// this will happen incredibly rarely, since symbols without declarations are very rare.
// I know of only two instances:
// 1. `undefined` in `globalThis`
// 2. Properties on non-homomorphic mapped types, e.g. the symbol for "foo" on `Record<"foo", 1>`
// There might be others, so still check this here rather than asserting, but print a debug log
// so that we can possibly improve this in the future.
if (!type.package) {
logger.verbose(`The type ${type.qualifiedName} has no declarations, implicitly allowing missing export.`);
return true;
}
// Don't produce warnings for third-party symbols.
if (type.package !== project.packageName) {
return true;
}
for (const [index, [file, name]] of processed.entries()) {
if (typeName === name &&
`${type.symbolId.packageName}/${type.symbolId.packagePath}`.endsWith(file)) {
used.add(index);
return true;
}
}
return false;
},
getUnused() {
return intentional.filter((_, i) => !used.has(i));
},
};
}
export function validateExports(project, logger, intentionallyNotExported) {
const intentional = makeIntentionallyExportedHelper(project, intentionallyNotExported, logger);
const warned = new Set();
for (const { type, owner } of discoverAllReferenceTypes(project, true)) {
const uniqueId = type.symbolId?.getStableKey();
if (!type.reflection &&
!type.externalUrl &&
!type.isIntentionallyBroken() &&
!intentional.has(type, type.qualifiedName) &&
!warned.has(uniqueId) &&
!project.symbolIdHasBeenRemoved(type.symbolId)) {
warned.add(uniqueId);
logger.warn(i18n.type_0_defined_in_1_is_referenced_by_2_but_not_included_in_docs(type.qualifiedName, `${type.symbolId.packageName}/${type.symbolId.packagePath}`, owner.getFriendlyFullName()));
}
}
const unusedIntentional = intentional.getUnused();
if (unusedIntentional.length) {
logger.warn(i18n.invalid_intentionally_not_exported_symbols_0(unusedIntentional.join("\n\t")));
}
}