-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
/
Copy pathdefaultPropsHandler.js
90 lines (79 loc) · 2.79 KB
/
defaultPropsHandler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
const astTypes = require('ast-types');
const { utils: docgenUtils } = require('react-docgen');
const { getPropertyName, isReactForwardRefCall, printValue, resolveToValue } = docgenUtils;
// based on https://github.com/reactjs/react-docgen/blob/735f39ef784312f4c0e740d4bfb812f0a7acd3d5/src/handlers/defaultPropsHandler.js#L1-L112
// adjusted for material-ui getThemedProps
const { namedTypes: types } = astTypes;
function getDefaultValue(path) {
let node = path.node;
let defaultValue;
if (types.Literal.check(node)) {
defaultValue = node.raw;
} else {
if (types.AssignmentPattern.check(path.node)) {
path = resolveToValue(path.get('right'));
} else {
path = resolveToValue(path);
}
if (types.ImportDeclaration.check(path.node)) {
defaultValue = node.name;
} else {
node = path.node;
defaultValue = printValue(path);
}
}
if (typeof defaultValue !== 'undefined') {
return {
value: defaultValue,
computed:
types.CallExpression.check(node) ||
types.MemberExpression.check(node) ||
types.Identifier.check(node),
};
}
return null;
}
function getDefaultValuesFromProps(properties, documentation) {
properties
.filter(propertyPath => types.Property.check(propertyPath.node))
// Don't evaluate property if component is functional and the node is not an AssignmentPattern
.filter(propertyPath => types.AssignmentPattern.check(propertyPath.get('value').node))
.forEach(propertyPath => {
const propName = getPropertyName(propertyPath);
if (!propName) return;
const propDescriptor = documentation.getPropDescriptor(propName);
const defaultValue = getDefaultValue(propertyPath.get('value', 'right'));
if (defaultValue) {
propDescriptor.defaultValue = defaultValue;
}
});
}
function getRenderBody(componentDefinition) {
const value = resolveToValue(componentDefinition);
if (isReactForwardRefCall(value)) {
return value.get('arguments', 0, 'body', 'body');
}
return value.get('body', 'body');
}
function getPropsPath(functionBody) {
let propsPath;
// visitVariableDeclarator, can't use visit body.node since it looses scope information
functionBody
.filter(path => {
return types.VariableDeclaration.check(path.node);
})
.forEach(path => {
const declaratorPath = path.get('declarations', 0);
if (declaratorPath.get('init', 'name').value === 'props') {
propsPath = declaratorPath.get('id');
}
});
return propsPath;
}
module.exports = function defaultPropsHandler(documentation, componentDefinition) {
const renderBody = getRenderBody(componentDefinition);
const props = getPropsPath(renderBody);
if (props !== undefined) {
getDefaultValuesFromProps(props.get('properties'), documentation);
}
};