Skip to content

Support files with multiple functions and one .displayName #437

@jesstelford

Description

@jesstelford

Hi! 👋

Firstly, thanks for your work on this project! 🙂

I have a file which exports a regular function who's first parameter is an object, plus a React function component with a defined displayName. When these conditions are met, the component's props are not output in the final result.

The minimum reproduction is:

export const Button = ({ label }: { label: string }) => (
  <button>{label}</button>
);
Button.displayName = 'Button';

export function areButtonsAwesome(obj = {}) {}

It appears the getTextValueOfFunctionProperty method is scanning the source file to generate display name's for each function by searching for the .displayName = assignment within the complete source file.

The issue occurs because it does not take into account the function on which the .displayName is being set; in the example above, both Button and areButtonsAwesome will end up with a displayName of Button thanks to the line Button.displayName = 'Button'. This on its own isn't an issue until later code deduplicates based on the generated displayName. In this case, the areButtonsAwesome wins, and Button is removed from the output as the "duplicate".

The fix is to check the .displayName is being assigned to the function in question, instead of just using the first one found.

Here is the diff that solved my problem:

diff --git a/node_modules/react-docgen-typescript/lib/parser.js b/node_modules/react-docgen-typescript/lib/parser.js
index e98cd64..09dc39e 100644
--- a/node_modules/react-docgen-typescript/lib/parser.js
+++ b/node_modules/react-docgen-typescript/lib/parser.js
@@ -797,7 +797,17 @@ function getTextValueOfFunctionProperty(exp, source, propertyName) {
         return (expr.left &&
             expr.left.name &&
             expr.left.name.escapedText ===
-                propertyName);
+                propertyName &&
+            // Ensure the .displayName is for the function we're processing. This
+            // avoids a situation where a file has multiple functions, only one of
+            // which has a .displayName; we don't want all functions inheriting that
+            // value by mistake.
+            statement.flowNode &&
+            statement.flowNode.node &&
+            statement.flowNode.node.name &&
+            statement.flowNode.node.name.escapedText &&
+            statement.flowNode.node.name.escapedText === exp.escapedName
+      );
     })
         .filter(function (statement) {
         return ts.isStringLiteral(statement

I'm not sure how to write this in TS, perhaps you can take my patch and apply it to the .ts file manually?

This issue body was partially generated by patch-package.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions