Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traversing and generating documentation from TypeDoc #2570

Open
KonnorRogers opened this issue May 5, 2024 · 2 comments
Open

Traversing and generating documentation from TypeDoc #2570

KonnorRogers opened this issue May 5, 2024 · 2 comments
Labels
question Question about functionality

Comments

@KonnorRogers
Copy link

KonnorRogers commented May 5, 2024

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:

Screenshot 2024-05-05 at 6 58 25 PM

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.

@KonnorRogers KonnorRogers added the question Question about functionality label May 5, 2024
@NullVoxPopuli
Copy link

this seems similar to something that would make my life way easier here:

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

@Gerrit0
Copy link
Collaborator

Gerrit0 commented May 6, 2024

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Question about functionality
Projects
None yet
Development

No branches or pull requests

3 participants