Skip to content

Commit

Permalink
feat: Add helper function for getting default value
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Jun 6, 2020
1 parent 110f52b commit 80485ed
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 1 deletion.
127 changes: 126 additions & 1 deletion src/utils/__tests__/propTypeInfo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getNormalizedTypeName } from '../propTypeInfo';
import { getNormalizedTypeName, getDefaultValue } from '../propTypeInfo';

const createPropType = (name, args, { isRequired = false } = {}) => {
const propType = [{ name: 'PropTypes' }, { name }];
Expand Down Expand Up @@ -108,3 +108,128 @@ describe('getNormalizedTypeName', () => {
expect(getNormalizedTypeName(propType)).toEqual('(string|number)[]');
});
});

describe('getDefaultValue', () => {
test('returns value for primitive types', () => {
const component = {
propTypes: {
message: createPropType('string'),
},
defaultProps: {
message: 'Hello',
},
};

expect(getDefaultValue(component, 'message')).toEqual('Hello');
});

test('returns undefined for undefined default values', () => {
const component = {
propTypes: {},
defaultProps: {},
};

expect(getDefaultValue(component, 'name')).toBeUndefined();
});

test('returns null for default values set to null', () => {
const component = {
propTypes: {
name: createPropType('string'),
},
defaultProps: {
name: null,
},
};

expect(getDefaultValue(component, 'name')).toBeNull();
});

test('returns stringified boolean value when it is a boolean', () => {
const component = {
propTypes: {
disabled: createPropType('bool'),
},
defaultProps: {
disabled: false,
},
};

expect(getDefaultValue(component, 'disabled')).toEqual('false');
});

test('returns a number if the default value is a number', () => {
const component = {
propTypes: {
count: createPropType('number'),
},
defaultProps: {
count: 5,
},
};

expect(getDefaultValue(component, 'count')).toEqual(5);
});

test('returns special number names if the default is a special number', () => {
const component = {
propTypes: {
bytes: createPropType('number'),
},
defaultProps: {
bytes: Number.MAX_SAFE_INTEGER,
},
};

expect(getDefaultValue(component, 'bytes')).toEqual(
'Number.MAX_SAFE_INTEGER'
);
});

test('returns undefined if the default value is an arbitrary object', () => {
const component = {
propTypes: {
bytes: createPropType('object'),
},
defaultProps: {
location: { state: '1234' },
},
};

expect(getDefaultValue(component, 'location')).toBeUndefined();
});

test('returns stringfied representation of array if the default value is an array', () => {
const component = {
propTypes: {
bytes: createPropType('array'),
},
defaultProps: {
sizes: [1, 2, 3],
},
};

expect(getDefaultValue(component, 'sizes')).toEqual('[1,2,3]');
});

test('returns static constant if the default value is a union prop', () => {
const GAP = {
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
};

const component = {
name: 'Grid',
propTypes: {
gap: createPropType('oneOf', [[GAP.SMALL, GAP.MEDIUM, GAP.LARGE]]),
},
defaultProps: {
gap: GAP.SMALL,
},
GAP,
};

expect(getDefaultValue(component, 'gap')).toEqual('Grid.GAP.SMALL');
});
});
57 changes: 57 additions & 0 deletions src/utils/propTypeInfo.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
const UNION_DELIMITER = '|';

const SPECIAL_NUMBERS = [
'MAX_VALUE',
'MIN_VALUE',
'NEGATIVE_INFINITY',
'POSITIVE_INFINITY',
'MAX_SAFE_INTEGER',
'MIN_SAFE_INTEGER',
'EPSILON',
];

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

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

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

const toStaticName = (name) =>
name
.replace(/(.+?)(?=[A-Z])/g, '$1_')
.replace('.', '_')
.toUpperCase();

export const getRawTypeName = (propType) => propType.__reflect__[1].name;

export const getNormalizedTypeName = (propType) => {
Expand Down Expand Up @@ -34,3 +54,40 @@ export const getNormalizedTypeName = (propType) => {
return name;
}
};

export const getDefaultValue = (component, propTypeName) => {
const defaultValue = component.defaultProps?.[propTypeName];

if (defaultValue == null) {
return defaultValue;
}

if (typeof defaultValue === 'boolean') {
return defaultValue.toString();
}

if (Array.isArray(defaultValue)) {
return JSON.stringify(defaultValue);
}

if (typeof defaultValue === 'object') {
return undefined;
}

if (isEnum(component.propTypes[propTypeName])) {
const staticProperty = toStaticName(propTypeName);
const property = Object.entries(component[staticProperty]).find(
([_, value]) => value === defaultValue
)[0];

return `${component.name}.${staticProperty}.${property}`;
}

if (typeof defaultValue === 'number') {
const specialNumber = findSpecialNumber(defaultValue);

return specialNumber ? `Number.${specialNumber}` : defaultValue;
}

return defaultValue;
};

0 comments on commit 80485ed

Please sign in to comment.