typedoc-plugin-missing-exports
Advanced tools
Comparing version 1.0.0 to 2.0.0
@@ -0,1 +1,5 @@ | ||
### 2.0.0 (2023-04-15) | ||
- BREAKING: Drop support for TypeDoc 0.22 and 0.23 | ||
### 1.0.0 (2022-08-12) | ||
@@ -2,0 +6,0 @@ |
200
index.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.discoverMissingExports = exports.load = void 0; | ||
exports.load = void 0; | ||
const assert_1 = require("assert"); | ||
const typedoc_1 = require("typedoc"); | ||
let hasMonkeyPatched = false; | ||
function load(app) { | ||
app.options.addDeclaration({ | ||
name: "internalModule", | ||
help: "Define the name of the module that internal symbols which are not exported should be placed into.", | ||
defaultValue: "<internal>", | ||
}); | ||
if (hasMonkeyPatched) { | ||
throw new Error("typedoc-plugin-missing-exports cannot be loaded multiple times"); | ||
} | ||
hasMonkeyPatched = true; | ||
let activeReflection; | ||
const referencedSymbols = new Map(); | ||
const symbolToActiveRefl = new Map(); | ||
const knownPrograms = new Map(); | ||
app.converter.on(typedoc_1.Converter.EVENT_CREATE_DECLARATION, (context) => { | ||
if (context.scope.kindOf(typedoc_1.ReflectionKind.Project | typedoc_1.ReflectionKind.Module)) { | ||
knownPrograms.set(context.scope, context.program); | ||
} | ||
}); | ||
app.converter.on(typedoc_1.Converter.EVENT_RESOLVE_BEGIN, onResolveBegin.bind(void 0, knownPrograms), void 0, 1e9); | ||
} | ||
exports.load = load; | ||
function onResolveBegin(knownPrograms, context) { | ||
const modules = context.project.getChildrenByKind(typedoc_1.ReflectionKind.Module); | ||
if (modules.length === 0) { | ||
// Single entry point, just target the project. | ||
modules.push(context.project); | ||
} | ||
for (const mod of modules) { | ||
let missing = discoverMissingExports(mod); | ||
if (missing.size === 0) | ||
continue; | ||
// Nasty hack here that will almost certainly break in future TypeDoc versions. | ||
context.setActiveProgram(knownPrograms.get(mod)); | ||
const internalNs = context | ||
.withScope(mod) | ||
.createDeclarationReflection(typedoc_1.ReflectionKind.Module, void 0, void 0, context.converter.application.options.getValue("internalModule")); | ||
context.finalizeDeclarationReflection(internalNs); | ||
const internalContext = context.withScope(internalNs); | ||
// Keep track of which symbols we've tried to convert. If they don't get converted | ||
// when calling convertSymbol, then the user has excluded them somehow, don't go into | ||
// an infinite loop when converting. | ||
const tried = new Set(); | ||
do { | ||
for (const s of missing) { | ||
if (shouldConvertSymbol(s, context.checker)) { | ||
internalContext.converter.convertSymbol(internalContext, s); | ||
} | ||
tried.add(s); | ||
function discoverMissingExports(context, program) { | ||
// An export is missing if if was referenced | ||
// Is not contained in the documented | ||
// And is "owned" by the active reflection | ||
const referenced = referencedSymbols.get(program) || new Set(); | ||
const ownedByOther = new Set(); | ||
referencedSymbols.set(program, ownedByOther); | ||
for (const s of [...referenced]) { | ||
if (context.project.getReflectionFromSymbol(s)) { | ||
referenced.delete(s); | ||
} | ||
missing = discoverMissingExports(internalNs); | ||
for (const s of tried) { | ||
missing.delete(s); | ||
else if (symbolToActiveRefl.get(s) !== activeReflection) { | ||
referenced.delete(s); | ||
ownedByOther.add(s); | ||
} | ||
} while (missing.size > 0); | ||
// All the missing symbols were excluded, so get rid of our namespace. | ||
if (!internalNs.children?.length) { | ||
context.project.removeReflection(internalNs); | ||
} | ||
context.setActiveProgram(void 0); | ||
return referenced; | ||
} | ||
knownPrograms.clear(); | ||
} | ||
function discoverMissingExports(root) { | ||
const missing = new Set(); | ||
const queue = []; | ||
let current = root; | ||
const visitor = (0, typedoc_1.makeRecursiveVisitor)({ | ||
reference(type) { | ||
if (!type.reflection) { | ||
const symbol = type.getSymbol(); | ||
if (symbol) { | ||
missing.add(symbol); | ||
} | ||
} | ||
}, | ||
reflection(type) { | ||
queue.push(type.declaration); | ||
}, | ||
}); | ||
const add = (item) => { | ||
if (!item) | ||
return; | ||
if (item instanceof typedoc_1.Reflection) { | ||
queue.push(item); | ||
// Monkey patch the constructor for references so that we can get every | ||
const origCreateSymbolReference = typedoc_1.ReferenceType.createSymbolReference; | ||
typedoc_1.ReferenceType.createSymbolReference = function (symbol, context, name) { | ||
(0, assert_1.ok)(activeReflection, "active reflection has not been set"); | ||
const set = referencedSymbols.get(context.program); | ||
symbolToActiveRefl.set(symbol, activeReflection); | ||
if (set) { | ||
set.add(symbol); | ||
} | ||
else { | ||
queue.push(...item); | ||
referencedSymbols.set(context.program, new Set([symbol])); | ||
} | ||
return origCreateSymbolReference.call(this, symbol, context, name); | ||
}; | ||
do { | ||
// Ugly? Yeah, it is. TypeDoc doesn't have a "visit all types" function, | ||
// so we have to build our own. This is modeled after the one in | ||
// https://github.com/TypeStrong/typedoc/blob/beta/src/lib/validation/exports.ts | ||
if (current instanceof typedoc_1.ContainerReflection) { | ||
add(current.children); | ||
app.options.addDeclaration({ | ||
name: "internalModule", | ||
help: "Define the name of the module that internal symbols which are not exported should be placed into.", | ||
defaultValue: "<internal>", | ||
}); | ||
app.converter.on(typedoc_1.Converter.EVENT_CREATE_DECLARATION, (context, refl) => { | ||
if (refl.kindOf(typedoc_1.ReflectionKind.Project | typedoc_1.ReflectionKind.Module)) { | ||
knownPrograms.set(refl, context.program); | ||
activeReflection = refl; | ||
} | ||
if (current instanceof typedoc_1.DeclarationReflection) { | ||
current.type?.visit(visitor); | ||
add(current.typeParameters); | ||
add(current.signatures); | ||
add(current.indexSignature); | ||
add(current.getSignature); | ||
add(current.setSignature); | ||
current.overwrites?.visit(visitor); | ||
current.inheritedFrom?.visit(visitor); | ||
current.implementationOf?.visit(visitor); | ||
current.extendedTypes?.forEach((type) => type.visit(visitor)); | ||
// do not validate extendedBy, guaranteed to all be in the documentation. | ||
current.implementedTypes?.forEach((type) => type.visit(visitor)); | ||
// do not validate implementedBy, guaranteed to all be in the documentation. | ||
}); | ||
app.converter.on(typedoc_1.Converter.EVENT_RESOLVE_BEGIN, function onResolveBegin(context) { | ||
const modules = context.project.getChildrenByKind(typedoc_1.ReflectionKind.Module); | ||
if (modules.length === 0) { | ||
// Single entry point, just target the project. | ||
modules.push(context.project); | ||
} | ||
if (current instanceof typedoc_1.SignatureReflection) { | ||
add(current.parameters); | ||
add(current.typeParameters); | ||
current.type?.visit(visitor); | ||
current.overwrites?.visit(visitor); | ||
current.inheritedFrom?.visit(visitor); | ||
current.implementationOf?.visit(visitor); | ||
for (const mod of modules) { | ||
activeReflection = mod; | ||
const program = knownPrograms.get(mod); | ||
if (!program) | ||
continue; | ||
let missing = discoverMissingExports(context, program); | ||
if (!missing || !missing.size) | ||
continue; | ||
// Nasty hack here that will almost certainly break in future TypeDoc versions. | ||
context.setActiveProgram(program); | ||
const internalNs = context | ||
.withScope(mod) | ||
.createDeclarationReflection(typedoc_1.ReflectionKind.Module, void 0, void 0, context.converter.application.options.getValue("internalModule")); | ||
context.finalizeDeclarationReflection(internalNs); | ||
const internalContext = context.withScope(internalNs); | ||
// Keep track of which symbols we've tried to convert. If they don't get converted | ||
// when calling convertSymbol, then the user has excluded them somehow, don't go into | ||
// an infinite loop when converting. | ||
const tried = new Set(); | ||
do { | ||
for (const s of missing) { | ||
if (shouldConvertSymbol(s, context.checker)) { | ||
internalContext.converter.convertSymbol(internalContext, s); | ||
} | ||
tried.add(s); | ||
} | ||
missing = discoverMissingExports(context, program); | ||
for (const s of tried) { | ||
missing.delete(s); | ||
} | ||
} while (missing.size > 0); | ||
// All the missing symbols were excluded, so get rid of our namespace. | ||
if (!internalNs.children?.length) { | ||
context.project.removeReflection(internalNs); | ||
} | ||
context.setActiveProgram(void 0); | ||
} | ||
if (current instanceof typedoc_1.ParameterReflection) { | ||
current.type?.visit(visitor); | ||
} | ||
if (current instanceof typedoc_1.TypeParameterReflection) { | ||
current.type?.visit(visitor); | ||
current.default?.visit(visitor); | ||
} | ||
} while ((current = queue.shift())); | ||
return missing; | ||
knownPrograms.clear(); | ||
referencedSymbols.clear(); | ||
}, void 0, 1e9); | ||
} | ||
exports.discoverMissingExports = discoverMissingExports; | ||
exports.load = load; | ||
function shouldConvertSymbol(symbol, checker) { | ||
@@ -130,0 +108,0 @@ while (symbol.flags & typedoc_1.TypeScript.SymbolFlags.Alias) { |
{ | ||
"name": "typedoc-plugin-missing-exports", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "Include non-exported types in TypeDoc documentation", | ||
@@ -11,6 +11,6 @@ "main": "./index.js", | ||
"@types/node": "^16.11.10", | ||
"ava": "^4.3.0", | ||
"prettier": "^2.7.1", | ||
"typedoc": "^0.23.1", | ||
"typescript": "^4.7.4" | ||
"prettier": "^2.8.7", | ||
"typedoc": "^0.24.2", | ||
"typescript": "^5.0.4", | ||
"vitest": "^0.30.1" | ||
}, | ||
@@ -28,14 +28,8 @@ "repository": { | ||
"peerDependencies": { | ||
"typedoc": "0.22.x || 0.23.x" | ||
"typedoc": "0.24.x" | ||
}, | ||
"scripts": { | ||
"pretest": "node scripts/copy_test_files.js", | ||
"test": "ava", | ||
"test": "vitest run test/packages.test.ts", | ||
"build": "tsc" | ||
}, | ||
"ava": { | ||
"files": [ | ||
"test/**/*.test.js" | ||
] | ||
} | ||
} |
@@ -5,3 +5,3 @@ # typedoc-plugin-missing-exports | ||
> Supports TypeDoc 0.22.x and 0.23.x | ||
> Supports TypeDoc 0.24.x | ||
@@ -16,6 +16,7 @@ TypeDoc 0.20 switched from documenting each file individually to documenting based on entry points. TypeDoc looks at each provided entry point and documents all exports from that entry point. | ||
`npm install typedoc-plugin-missing-exports` | ||
```bash | ||
npm install typedoc-plugin-missing-exports | ||
npx typedoc --plugin typedoc-plugin-missing-exports | ||
``` | ||
TypeDoc will automatically use this plugin when present. | ||
### Options | ||
@@ -22,0 +23,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
27
0
9654
5
123