Skip to content

Commit

Permalink
fix: Handle enums that are nested in a shape prop type
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Jun 8, 2020
1 parent dcdb3fa commit 97b7a1b
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
26 changes: 26 additions & 0 deletions src/utils/__tests__/propTypeInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,32 @@ describe('getTypeMeta', () => {
});
});

test('handles enums nested in shape prop types', () => {
const OUTER_SPACE = {
SMALL: 'sm',
MEDIUM: 'md',
LARGE: 'lg',
};
const enumPropType = createPropType('oneOf', [Object.values(OUTER_SPACE)]);
const propType = createPropType('shape', [{ space: enumPropType }]);

const component = {
name: 'Button',
propTypes: {
outer: propType,
},
OUTER_SPACE,
};

expect(getTypeMeta('space', enumPropType, { component })).toEqual({
constants: [
'Button.OUTER_SPACE.SMALL',
'Button.OUTER_SPACE.MEDIUM',
'Button.OUTER_SPACE.LARGE',
],
});
});

test('handles advanced case', () => {
const CRAZY = {
ONE: 1,
Expand Down
44 changes: 30 additions & 14 deletions src/utils/propTypeInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,30 @@ const SPECIAL_NUMBERS = [
'EPSILON',
];

const IGNORED_PROPERTIES = [
'prototype',
'length',
'name',
'propTypes',
'getDerivedStateFromProps',
'defaultProps',
];

const getArgs = (propType) =>
propType.__reflect__.find(({ args }) => args)?.args;

const isEnum = (propType) => getRawTypeName(propType) === 'oneOf';
const isUnion = (propType) => getRawTypeName(propType) === 'oneOfType';

const matchesEnum = (property, enums) => {
const values = Object.values(property);

return (
values.length === enums.length &&
enums.every((value) => values.includes(value))
);
};

const findSpecialNumber = (number) =>
SPECIAL_NUMBERS.find((property) => Number[property] === number);

Expand Down Expand Up @@ -92,7 +110,7 @@ export const getDefaultValue = (component, propTypeName) => {
return defaultValue;
};

export const getTypeMeta = (name, propType, { component, prefix }) => {
export const getTypeMeta = (name, propType, { component }) => {
const propTypeDocs = propType.__docs__;

switch (getRawTypeName(propType)) {
Expand All @@ -106,16 +124,19 @@ export const getTypeMeta = (name, propType, { component, prefix }) => {

return {
types: Object.entries(shape).map(([shapePropName, propType]) =>
getPropTypeDefinition(component, shapePropName, propType, {
prefix: name,
})
getPropTypeDefinition(component, shapePropName, propType)
),
};
}
case 'oneOf': {
const staticProperty = toStaticPropertyName(
prefix ? `${prefix}.${name}` : name
);
const [enums] = getArgs(propType);
const staticProperty = Object.getOwnPropertyNames(component)
.filter(
(member) =>
!IGNORED_PROPERTIES.includes(member) &&
typeof component[member] === 'object'
)
.find((member) => matchesEnum(component[member], enums));

return {
constants: Object.keys(component[staticProperty] ?? {}).map(
Expand Down Expand Up @@ -150,12 +171,7 @@ export const getTypeMeta = (name, propType, { component, prefix }) => {
}
};

export const getPropTypeDefinition = (
component,
name,
propType,
{ prefix } = {}
) => {
export const getPropTypeDefinition = (component, name, propType) => {
const propDocs = propType.__docs__;
const propMeta = propType.__reflect__;

Expand All @@ -167,7 +183,7 @@ export const getPropTypeDefinition = (
isRequired: propMeta?.some((item) => item.name === 'isRequired') ?? false,
examples: propDocs?.tags?.examples ?? [],
type: {
meta: getTypeMeta(name, propType, { component, prefix }),
meta: getTypeMeta(name, propType, { component }),
raw: getRawTypeName(propType),
name: getNormalizedTypeName(propType),
},
Expand Down

0 comments on commit 97b7a1b

Please sign in to comment.