Skip to content

feat: Provide raw expression as part of parser output #398

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

Conversation

TrevorBurnham
Copy link
Contributor

This is re: hipstersmoothie/react-docgen-typescript-plugin#51 and storybookjs/storybook#15401 cc @hipstersmoothie @leepowelldev

tl;dr This PR would allow consumers who parse components with react-docgen-typescript to access the expression for that component.

Use case

In Storybook, a component's prop table will break if you set the component's displayName to a value that differs from its identifier. For example, let's say that you define a component like this:

export const Button = (props: ButtonComponentProps) => (
  <button>{props.text}</button>
);

Button.displayName = "MyButtonDisplayName";

Then react-docgen-typescript-plugin will append code to that module like this:

try {
    // @ts-ignore
    MyButtonDisplayName.displayName = "MyButtonDisplayName";
    // @ts-ignore
    MyButtonDisplayName.__docgenInfo = { "description": "", "displayName": "MyButtonDisplayName", "props": { "text": { "defaultValue": null, "description": "", "name": "text", "required": true, "type": { "name": "string" } } } };
}
catch (__react_docgen_typescript_loader_error) { }

That code will be a no-op, because MyButtonDisplayName is an invalid reference.

Why does react-docgen-typescript-plugin behave this way? Because the react-docgen-typescript parser doesn't return any way of obtaining the component's identifier other than displayName.

If the parser returned the component expression, then consumers like react-docgen-typescript-plugin could use expression.getName() instead of displayName to correctly handle cases where displayName is a different value.


Note that I opted to return the expression object here, rather than just the result of expression.getName(), because it might help to address another case: unnamed default exports. react-docgen-typescript-plugin fails for component declarations of the form export default function() { ... }, since there's no identifier to reference the component in that case. But using the expression, it might be able to inject one—that is, it could convert the component declaration to one of the form export default function SomeGeneratedName() { ... }, making it referencable.

@pvasek
Copy link
Collaborator

pvasek commented Nov 28, 2021

I think this can be really good for a lot of different use cases that would be hard to support in any other way.
My only concern is that this could be maybe a breaking change for some users. For example serialise the output to json or similar use cases.

I see the following possible issues there:

  • they will get more than they expected
  • not sure if ts.Symbol is even serializable

What do you think about it?

Shouldn't we at least include some kind of opt-in switch for that in ParserOptions?

@TrevorBurnham
Copy link
Contributor Author

@pvasek Ah, I hadn't considered serialization. Nice catch! I've updated this PR to only return the component expression if a new parser option, shouldIncludeExpression, is set to true: a784601

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

Successfully merging this pull request may close these issues.

2 participants