Skip to content

Instantly share code, notes, and snippets.

@Gerrit0
Created June 22, 2022 02:26
Show Gist options
  • Save Gerrit0/73a03bc6dc8ec1677646f6e65032229f to your computer and use it in GitHub Desktop.
Save Gerrit0/73a03bc6dc8ec1677646f6e65032229f to your computer and use it in GitHub Desktop.
// @ts-check
/**
* typedoc-plugin-not-exported
* TypeDoc plugin that forces inclusion of non-exported symbols (variables)
* Originally from https://github.com/TypeStrong/typedoc/issues/1474#issuecomment-766178261
* https://github.com/tomchen/typedoc-plugin-not-exported
* CC0
*/
const {
Converter,
Context,
TypeScript,
Application,
DeclarationReflection,
ReflectionKind,
Reflection,
} = require("typedoc");
const ModuleFlags =
TypeScript.SymbolFlags.ValueModule | TypeScript.SymbolFlags.NamespaceModule;
/**
* @param {Application} application
*/
exports.load = function (application) {
/** @type {Map<Reflection, Set<TypeScript.SourceFile>>} */
const checkedForModuleExports = new Map();
let includeTag = "notExported";
application.options.addDeclaration({
name: "includeTag",
help: "[typedoc-plugin-not-exported] Specify the tag name for non-exported member to be imported under",
defaultValue: includeTag,
});
application.converter.on(Converter.EVENT_BEGIN, () => {
const includeTagTemp = application.options.getValue("includeTag");
if (typeof includeTagTemp === "string") {
includeTag = includeTagTemp.toLocaleLowerCase();
}
});
application.converter.on(
Converter.EVENT_CREATE_DECLARATION,
lookForFakeExports
);
application.converter.on(Converter.EVENT_END, () => {
checkedForModuleExports.clear();
});
/**
* @param {Context} context
* @param {DeclarationReflection} reflection
*/
function lookForFakeExports(context, reflection) {
// Figure out where "not exports" will be placed, go up the tree until we get to
// the module where it belongs.
let targetModule = reflection;
while (
!targetModule.kindOf(ReflectionKind.Module | ReflectionKind.Project)
) {
targetModule = /** @type {DeclarationReflection} */ (
targetModule.parent
);
}
const moduleContext = context.withScope(targetModule);
const reflSymbol = context.project.getSymbolFromReflection(reflection);
if (!reflSymbol) {
// Global file, no point in doing anything here. TypeDoc will already
// include everything declared in this file.
return;
}
for (const declaration of reflSymbol.declarations || []) {
checkFakeExportsOfFile(declaration.getSourceFile(), moduleContext);
}
}
/**
* @param {TypeScript.SourceFile} file
* @param {Context} context
*/
function checkFakeExportsOfFile(file, context) {
console.log("Check", file.fileName);
const moduleSymbol = context.checker.getSymbolAtLocation(file);
// Make sure we are allowed to call getExportsOfModule
if (!moduleSymbol || (moduleSymbol.flags & ModuleFlags) === 0) {
return;
}
const checkedScopes =
checkedForModuleExports.get(context.scope) || new Set();
checkedForModuleExports.set(context.scope, checkedScopes);
if (checkedScopes.has(file)) return;
checkedScopes.add(file);
const exportedSymbols =
context.checker.getExportsOfModule(moduleSymbol);
const symbols = context.checker
.getSymbolsInScope(file, TypeScript.SymbolFlags.ModuleMember)
.filter(
(symbol) =>
symbol.declarations?.some(
(d) => d.getSourceFile() === file
) && !exportedSymbols.includes(symbol)
);
for (const symbol of symbols) {
if (
symbol
.getJsDocTags()
.some((tag) => tag.name.toLocaleLowerCase() === includeTag)
) {
context.converter.convertSymbol(context, symbol);
}
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment