typedoc
typedoc copied to clipboard
Traversing and generating documentation from TypeDoc
Search terms
Traversal, Visitors
Question
Are there any docs on how to traverse types and other signatures from TypeDoc?
My basic use-case is I have a type that looks like this:
export const AnchoredRegionProperties = () => /** @const */ ({
placement: { reflect: true },
currentPlacement: { attribute: "current-placement", reflect: true },
strategy: { reflect: true },
distance: { type: Number },
skidding: { type: Number },
arrow: { type: Boolean },
arrowPlacement: { attribute: 'arrow-placement' },
arrowPadding: { attribute: 'arrow-padding', type: Number },
flip: { type: Boolean },
flipFallbackPlacements: {
attribute: 'flip-fallback-placements',
converter: {
/**
* @param {string} value
*/
fromAttribute: (value) => {
return value
.split(' ')
.map(p => p.trim())
.filter(p => p !== '');
},
/**
* @param {[]} value
*/
toAttribute: (value) => {
return value.join(' ');
}
}
},
flipFallbackStrategy: { attribute: 'flip-fallback-strategy' },
flipBoundary: { type: Object },
flipPadding: { attribute: 'flip-padding', type: Number },
shift: { type: Boolean },
shiftBoundary: { type: Object },
shiftPadding: { attribute: 'shift-padding', type: Number },
autoSize: { attribute: 'auto-size' },
sync: {},
autoSizeBoundary: { type: Object },
autoSizePadding: { attribute: 'auto-size-padding', type: Number },
hoverBridge: { attribute: 'hover-bridge', type: Boolean },
})
export default class RoleTooltip extends AnchoredRegionMixin(BaseElement) {
static get properties() {
return {
...(AnchoredRegionProperties()),
id: { reflect: true },
role: { reflect: true },
placement: { reflect: true },
active: { reflect: true, type: Boolean },
popover: { reflect: true },
anchor: { attribute: false, state: true },
triggerSource: { attribute: "trigger-source", reflect: true },
};
}
}
Basically, what I want to do is the the final properties type from RoleTooltip.properties, but I can't quite figured out how the TypeDoc documentation is rendering the type.
Here's how TypeDoc generates it:
This is as far as I've gotten:
import { globSync } from "glob";
import * as TypeDoc from "typedoc"
async function main() {
// Application.bootstrap also exists, which will not load plugins
// Also accepts an array of option readers if you want to disable
// TypeDoc's tsconfig.json/package.json/typedoc.json option readers
const app = await TypeDoc.Application.bootstrapWithPlugins({
entryPoints: globSync("./exports/**/*.js"),
});
const project = await app.convert();
if (!project) return
project.children.forEach((child) => {
if (child.name === "tooltip/tooltip") {
const defaultExport = child.children.find((member) => member.name === "default" && member.variant === "declaration")
for (const member of defaultExport.children) {
if (member.flags.isStatic === true && member.name === "properties") {
// Finds "RoleTooltip.properties" and then outputs its object to console.
// It has the info I want, just not sure the right way to get it.
console.log(member.getSignature.toStringHierarchy())
}
}
}
})
}
main().catch(console.error);
But can't quite seem to understand how to get the static properties final type value.
I'd love to have either more functions or more documentation on how to traverse the TypeDoc trees. I feel like I've spent all day banging against this and haven't made any progress.
this seems similar to something that would make my life way easier here:
- https://github.com/universal-ember/kolay/blob/main/ui/src/typedoc/signature/component.gts#L94
- https://github.com/universal-ember/kolay/blob/main/ui/src/typedoc/signature/modifier.gts#L8
I'd love for a typedoc-provided runtime that takes the JSON output, maybe something like (psuedocode):
const typedoc = new TypeDoc(theJsonObject);
const fooModule = typedoc.modules.find(x => x.path === 'declarations/foo.js');
const properties = fooModule.types.find(x => x.propertyName === 'properties' && x.returnType);
// renders the ReturnType from the properties getter
properties
TypeDoc's reflection structure fairly closely resembles what's available on a TS AST... if that helps
In this case, since "properties" is a getter, it has a getSignature, which has a return type that describes the type. This will be a ReflectionType since it is an object. Object types are converted as reflection types to allow re-use of the code to convert arbitrary symbols, which is a decision I'm almost certain I wouldn't make if building TypeDoc today... but is how it has worked since before me.
Because it is a ReflectionType, what you want is actually on the declaration property, which is another DeclarationReflection, so the properties of the type are available in the getSignature.type.declaration.children array.
As you might have started to suspect, since the type of active, anchor, etc. are also objects, they'll also be ReflectionTypes, and have their own declaration... so to get the boolean type associated with the active.reflect property you need:
const activeType = getSignature.type.declaration.children[0].type
const reflectType = activeType.declaration.children[0].type
// reflectType.toString() == "boolean"
The non-object reflectType will finally be something sane, in this case an IntrinsicType
I'd love for a typedoc-provided runtime that takes the JSON output, maybe something like (psuedocode):
TypeDoc can revive the JSON output into a project with app.deserializer.reviveProject, but that's less useful than it could be as TypeDoc isn't suitable for bundling... someday I'd like to make the models work well with bundling at least, which would include this.
This still won't give you exactly that API, but ProjectReflection.getChildByName is at least helpful for finding reflections (note: It does not recurse into types)