Skip to content

Instantly share code, notes, and snippets.

@gabriel-dehan
Last active November 29, 2019 10:47
Show Gist options
  • Save gabriel-dehan/fa64b997227758cef4080e25b7855ed3 to your computer and use it in GitHub Desktop.
Save gabriel-dehan/fa64b997227758cef4080e25b7855ed3 to your computer and use it in GitHub Desktop.
Given a component, returns an object with data about all props (what's the type, is it required, what are the options)...
import checkPropTypes from 'check-prop-types';
import pickBy from 'lodash/pickBy';
const getPropsSchema = (component) => {
if (component.type.propTypes) {
return Object.keys(component.type.propTypes).map((propName) => resolvePropType(component.type.propTypes, propName));
}
return [];
};
// Because we can't access proptypes, we have to take a prop and run the validator to determine the type
const resolvePropType = (propTypes, name) => {
// Object of value types to be checked
const types = {
array: [],
string: '',
number: 0,
bool: true,
func: () => {},
object: {},
element: (<div></div>),
oneOf: "____",
};
for (const typeName in types) {
// Get the validator
const propTypeValidator = pickBy(propTypes, (_, k) => k === name);
// Create objects with default values, for instance { type: '' }, { isLoading: true}, etc...
const defaultValueChecker = {};
defaultValueChecker[name] = types[typeName];
// Used to check if the field is required
const noValueChecker = {};
noValueChecker[name] = null;
// Run the validator for a default value of the given type and with no value
const error = checkPropTypes(propTypeValidator, defaultValueChecker, '_', '_');
const isRequiredError = checkPropTypes(propTypeValidator, noValueChecker, '_', '_');
const isRequired = /marked as required/.test(isRequiredError);
// If we don't have an error we found the right type
if (!error) {
return {
name: name,
required: isRequired,
type: typeName,
};
// If we have an error the type is not right OR it was a oneOf proptype so we try to extract the options
} else if (/one of/.test(error)) {
var oneOfArray = /expected one of (\[.*\])/.exec(error);
if (oneOfArray && oneOfArray[1]) {
const options = JSON.parse(oneOfArray[1]) || [];
return {
name: name,
required: isRequired,
type: options.length > 0 ? (typeof options[0]) : undefined,
options,
};
}
}
}
return {
name: name,
type: undefined,
required: false,
};
};
@gabriel-dehan
Copy link
Author

gabriel-dehan commented Nov 29, 2019

Result example

[
  {name: "type", required: true, type: "string", options: ["primary", "secondary", "simple"])},
  {name: "icon", required: false, type: "string"},
  {name: "iconHeight", required: false, type: "string"},
  {name: "iconWidth", required: false, type: "string"},
  {name: "iconColor", required: false, type: "string"},
  {name: "iconPosition", required: false, type: "string"}
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment