Created
June 22, 2022 02:26
-
-
Save Gerrit0/73a03bc6dc8ec1677646f6e65032229f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @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