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

hyperlink not generated for {@link type#property} #2808

Closed
techfg opened this issue Dec 10, 2024 · 8 comments
Closed

hyperlink not generated for {@link type#property} #2808

techfg opened this issue Dec 10, 2024 · 8 comments
Labels
bug Functionality does not match expectation

Comments

@techfg
Copy link

techfg commented Dec 10, 2024

Search terms

anchor, hyperlink, property, member

Expected Behavior

Per the release notes for v0.27.0, it indicates that "TypeDoc can now link to type alias properties, #2524." Unless I'm misunderstanding what was fixed and what scenarios the fix covers, when using {@link type#property}, the generated HTML should contain a hyperlink to the corresponding anchor tag on the type declaration page.

import { z } from 'zod';

export const foo = {
  /** foo a property */
  a: '',
  /** foo b property */
  b: '',
};
export type FooType = typeof foo;
/** @useDeclaredType */
export type FooTypeDT = typeof foo;
export type FooExplicit = {
  /** FooExplicit a property */
  a: string;
  /** FooExplicit b property */
  b: string;
};
export const zfoo = z.object({
  /** ZodFoo a property */
  a: z.string(),
  /** ZodFoo b property */
  b: z.string(),
});
export type ZodFoo = z.infer<typeof zfoo>;
/** @useDeclaredType */
export type ZodFooDT = z.infer<typeof zfoo>;

/**
 * Link Tests
 *
 * {@link foo} | {@link foo.a}
 *
 * {@link FooType} | {@link FooType.a}
 *
 * {@link FooTypeDT} | {@link FooTypeDT.a}
 * 
 * {@link FooExplicit} | {@link FooExplicit.a}
 *
 * {@link ZodFoo} | {@link ZodFoo#a}
 *
 * {@link ZodFooDT} | {@link ZodFooDT#a}
 */
export const doSomething = () => {};

Actual Behavior

image

  1. The property is hyperlinked but it links to foo.a instead of FooTypeDT.a. I'm not 100% sure if it should link to FooTypeDT.a but mentioning this as a potential bug/issue since I would think it should link to FooTypeDT.a since FooTypeDT is decorated with @useDeclaredType.
  2. Not hyperlinked
  3. Not hyperlinked

For 2 & 3, I was unable to narrow this down any further except for when zod is used, apologies for that. Although I could be mistaken, I do not think this is a zod and/or typedoc-plugin-zod issue because the anchor tag is emitted on the ZodFoo & ZodFooDT declaration pages, the {@link} reference does not error meaning it finds the corresponding type/property, it's only that the hyperlink is not emitted.

Steps to reproduce the bug

Repro: https://stackblitz.com/edit/vitejs-vite-gbh2bhqb

  1. Open repro
  2. npm run docs
  3. View docs/functions/doSomething.html

Environment

  • Typedoc version: 0.27.4
  • TypeScript version: 5.7.2
  • Node.js version: 18.20.3 & 20.18.0
  • OS: linux & windows
@techfg techfg added the bug Functionality does not match expectation label Dec 10, 2024
@Gerrit0
Copy link
Collaborator

Gerrit0 commented Dec 10, 2024

  1. Working as intended, unfortunately. TypeDoc relies on TypeScript to define symbols for properties, and TS says all of those symbols are the same.

2/3. That's... weird. A very Quick Look before heading to bed seems to indicate that TypeDoc isn't actually resolving the link correctly and should be producing a warning, though it also ought to be producing a link there, so there might be two things wrong here.

@techfg
Copy link
Author

techfg commented Dec 10, 2024

@Gerrit0 -

Thanks for the quick reply and initial thoughts.

1 - Makes sense and what I was expecting, just wanted to be sure 😄
2/3 - Yeah, would assume either a warning or a link. The declaration page does contain an anchor for the property so that part appears to be working correctly at least. If there's anything I can do to assist as you work through this, just let me know.

Have a good night and thanks again!

@techfg
Copy link
Author

techfg commented Dec 11, 2024

@Gerrit0 -

I came across a couple other situations that produce an identical result with the property not hyperlinked but the declaration page itself containing the anchor tag. I can't be certain these are the same underlying problem, but they are equally as weird and likely the same as the repro in the OP.

  1. Using interfaces - This is the same as the repro in the OP but ZodFoo and ZodFooDT are interfaces instead of types.
    Repro

  2. Using interfaces & nested types - In this situation, OptionsSchema contains a property collections which is based on CollectionConfigSchema.
    Repro
    image

    1. No hyperlink
    2. No hyperlink
    3. The text before the link which does not contain @link is hyperlinked to http://collectionconfig.name - Very strange!

Important

If you comment out this line and replace it with this line, problem 1 & 2 do not happen although 3 still does.

Hope this helps, thank you!

@Gerrit0
Copy link
Collaborator

Gerrit0 commented Dec 12, 2024

1 - Yes, interfaces vs types makes no difference here. Expected result.

2.i / 2.ii - Looks like it's probably the same issue as with types.

2.iii - Working as expected. .name is a top level domain. This behavior comes from Markdown-It's auto linking. playground

If you use TypeDoc's markdownItOptions option, you can disable linkify to disable this behavior.

3.iv - Yes, when redeclaring the type there you introduce new symbols, so they have their own identity.

@techfg
Copy link
Author

techfg commented Dec 12, 2024

Thanks @Gerrit0!

1 - Yes, interfaces vs types makes no difference here. Expected result.

Makes sense.

2.i / 2.ii - Looks like it's probably the same issue as with types.

Makes sense and as suspected - wanted to mention specifically since I thought the issue was related to type property resolution specifically but it seems it may be otherwise. Have you had any luck tracking this down further?

2.iii - Working as expected. .name is a top level domain. This behavior comes from Markdown-It's auto linking. playground

If you use TypeDoc's markdownItOptions option, you can disable linkify to disable this behavior.

Very interesting and good to know. Was not aware of this but makes sense, thanks for pointing it out and the playground to see it in action.

3.iv - Yes, when redeclaring the type there you introduce new symbols, so they have their own identity.

Assuming you were referring to the information in the "important" section for this, correct? Assuming yes, would agree that redeclaring the types would introduce new symbols but the @link is the same before/after and points to CollectionConfig.<property> and not the Options.collections.<property> so even though Options.collections is changing and not re-using CollectionConfigSchema, the links to CollectionConfig.<property> should work in both before/after scenarios just as the @link to Options.<property> work in both- no? In short, I wouldn't expect changing Options.collections would have any impact on why @link to CollectionConfig.<anyproperty> would work and why links to Options.<property> always seem to work. Possibly I'm misunderstanding what you were saying for this one?

Thanks!

@Gerrit0
Copy link
Collaborator

Gerrit0 commented Dec 14, 2024

Well that was an interesting multi-hour debugging adventure... there's never a good answer for anything... Notes:

  1. typedoc-plugin-zod has a couple bugs. It is removing reflections during Converter.EVENT_END which isn't permitted, and it is creating type reflections as children of the project rather than the reflection they belong to, which prevents links from being assigned correctly when rendering in some cases.

  2. When multiple reflections are associated with a symbol, TypeDoc should be smarter about which reflections it resolves @links to. I think the rule here should be: First, try reflections which can be directly exported. Then, check members which are owned by something that can be directly exported, then fall back to grabbing the first symbol as it does today.

  3. TypeDoc's invalid link validation today checks for links which cannot be resolved to a reflection. It does not report a problem if a link can be resolved, but is resolved to a reflection which does not have a link within the page it is rendered on. These links are just silently rendered as text. (This is half of what's going on with all of your broken links, the other half is the bugs in typedoc-plugin-zod which manifest very strangely, pretty sure those bugs are what's causing the CollectionConfig issues as that seems to have gone away with my experimental changes)

    Unfortunately, the question of whether or not a reflection has a URL and can be linked to is not a trivial one. Today, TypeDoc's link creation logic defines URLs for all reflections which might have an anchor on the page. Whether a URL is actually used is up to the theme logic and can't easily be known until we render that page in the output, which is really too late for knowing if a link will be valid.

    TypeDoc could be changed to only define anchors for reflections which are known will have anchors within the page, but that will come at the cost of not having anchors for deeply nested properties. In the following example, it would result in TypeDoc having to link to prop, rather than here. I think this is probably an okay sacrifice to gain the ability to validate if a link will be valid... annoyingly, this is a breaking change that for some people will likely be very breaking.

    /**
     * {@link GH2808DeeplyNestedLink.prop.nested.here}
    */
    export interface GH2808DeeplyNestedLink {
        /** Prop docs */
        prop: {
            /** Nested docs */
            nested: {
                /** Here docs */
                here: true;
            };
        };
    }

    The problem with making this change is that anyone who uses object-variables and expects to link to properties on them is then out of luck as they'll never have anchors. This is a really annoyingly thorny problem... rendering every page twice is out of the question.

@Gerrit0
Copy link
Collaborator

Gerrit0 commented Dec 14, 2024

Sleeping on a problem is always a good idea. The answer for no. 3 is rather obvious now. TypeDoc should just check if anchor properties for a type are directly within a type literal on a variable/type alias. If they are, it should assign a URL, and always render those properties in a way that they'll have a URL on the page.

Gerrit0 added a commit that referenced this issue Dec 14, 2024
techfg added a commit to techfg/astro-rehype-relative-markdown-links that referenced this issue Dec 14, 2024
@techfg
Copy link
Author

techfg commented Dec 14, 2024

@Gerrit0 -

Thank you for your persistence and for the fixes, greatly appreciated! I tested all three repros and my actual project and all generate correctly now with 0.27.5.

Apologies again for the repro's including typedoc-plugin-zod. In my actual project, I don't use it but to create the isolated repro, I wasn't able to reproduce the issue without it. In doing some more testing now, I was able to reproduce the problem without typedoc-plugin-zod using typedoc v0.27.4. Not sure what I was doing at the time but thankfully the repro exposed issues in both packages that you were able to address 😄

Thank you again!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Functionality does not match expectation
Projects
None yet
Development

No branches or pull requests

2 participants