From 004dde1c8ce1376838ecd46988a5ebcf48121a46 Mon Sep 17 00:00:00 2001
From: Jerel Miller <jmiller@newrelic.com>
Date: Sun, 7 Jun 2020 00:38:52 -0700
Subject: [PATCH] feat: Add test and implementation to return meta for a func
 type

---
 src/utils/__tests__/propTypeInfo.js | 77 +++++++++++++++++++++++++++--
 src/utils/propTypeInfo.js           | 14 ++++++
 2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/src/utils/__tests__/propTypeInfo.js b/src/utils/__tests__/propTypeInfo.js
index 99e9ac2a8..87f7f866e 100644
--- a/src/utils/__tests__/propTypeInfo.js
+++ b/src/utils/__tests__/propTypeInfo.js
@@ -1,6 +1,32 @@
-import { getNormalizedTypeName, getDefaultValue } from '../propTypeInfo';
+import {
+  getNormalizedTypeName,
+  getDefaultValue,
+  getTypeMeta,
+} from '../propTypeInfo';
+
+const createDocs = (type, { description, returnValue, params } = {}) => {
+  const docs = {
+    text: description,
+  };
+
+  switch (type) {
+    case 'func':
+      docs.tags = {};
+
+      if (returnValue) {
+        docs.tags.returns = returnValue;
+      }
+
+      if (params) {
+        docs.tags.param = params;
+      }
+      break;
+  }
+
+  return docs;
+};
 
-const createPropType = (name, args, { isRequired = false } = {}) => {
+const createPropType = (name, args, { isRequired = false, docs } = {}) => {
   const propType = [{ name: 'PropTypes' }, { name }];
 
   if (args) {
@@ -11,7 +37,7 @@ const createPropType = (name, args, { isRequired = false } = {}) => {
     propType.push({ name: 'isRequired' });
   }
 
-  return { __reflect__: propType };
+  return { __reflect__: propType, __docs__: createDocs(name, docs) };
 };
 
 describe('getNormalizedTypeName', () => {
@@ -233,3 +259,48 @@ describe('getDefaultValue', () => {
     expect(getDefaultValue(component, 'gap')).toEqual('Grid.GAP.SMALL');
   });
 });
+
+describe('getTypeMeta', () => {
+  [
+    'any',
+    'array',
+    'element',
+    'elementType',
+    'number',
+    'node',
+    'object',
+    'string',
+    'symbol',
+  ].forEach((type) => {
+    test(`returns null for ${type} types`, () => {
+      const propType = createPropType(type);
+      const component = {
+        propTypes: {
+          [type]: propType,
+        },
+      };
+
+      expect(getTypeMeta(type, propType, { component })).toBeNull();
+    });
+  });
+
+  test('returns function information for func types', () => {
+    const propType = createPropType('func', undefined, {
+      docs: {
+        description: 'A click handler',
+        params: [{ description: '', name: 'event', type: 'Event' }],
+      },
+    });
+
+    const component = {
+      propTypes: {
+        onClick: propType,
+      },
+    };
+
+    expect(getTypeMeta('onClick', propType, { component })).toEqual({
+      returnValue: { type: 'undefined' },
+      params: [{ description: '', name: 'event', type: 'Event' }],
+    });
+  });
+});
diff --git a/src/utils/propTypeInfo.js b/src/utils/propTypeInfo.js
index 6441a16ba..e2151164b 100644
--- a/src/utils/propTypeInfo.js
+++ b/src/utils/propTypeInfo.js
@@ -92,6 +92,20 @@ export const getDefaultValue = (component, propTypeName) => {
   return defaultValue;
 };
 
+export const getTypeMeta = (name, propType, { component }) => {
+  const propTypeDocs = propType.__docs__;
+
+  switch (getRawTypeName(propType)) {
+    case 'func':
+      return {
+        returnValue: propTypeDocs.tags?.returnValue ?? { type: 'undefined' },
+        params: propTypeDocs.tags?.param,
+      };
+    default:
+      return null;
+  }
+};
+
 export const getPropTypeDefinition = (component, name, propType) => {
   const propDocs = propType.__docs__;
   const propMeta = propType.__reflect__;