UNPKG

2.3 kBJavaScriptView Raw
1import isNumber from './prop-is-number.js'
2
3const isActionable = item =>
4 // (item.type === 'Horizontal' ||
5 // item.type === 'Vertical' ||
6 // /^Capture/.test(item.type)) &&
7 item.name !== 'onWhen' && /^on[A-Z]/.test(item.name)
8
9const extractPropsAndItems = item => {
10 const props = []
11 const regex = /(props|item)\.([a-zA-Z][a-zA-Z0-9.]*[a-zA-Z0-9]+)(.)?/g
12
13 let matches = regex.exec(item.value)
14 while (matches !== null) {
15 // This is necessary to avoid infinite loops with zero-width matches
16 if (matches.index === regex.lastIndex) {
17 regex.lastIndex++
18 }
19
20 const isExplicitFunctionCall = matches[3] === '('
21 props.push({
22 isItem: matches[1] === 'item',
23 path: matches[2],
24 type:
25 isActionable(item) || isExplicitFunctionCall
26 ? 'function'
27 : isNumber[item.name] ? 'number' : 'string',
28 })
29 matches = regex.exec(item.value)
30 }
31 return props
32}
33
34const isList = item => item.type === 'List'
35const isListFrom = item => item.name === 'from' && isList(item)
36
37export default list => {
38 const flatProps = {}
39
40 let listFromPath
41 list.forEach((item, index) => {
42 extractPropsAndItems(item).forEach(propOrItem => {
43 if (isListFrom(item)) {
44 // store the list prop path for later
45 listFromPath = propOrItem.path
46 } else if (isList(item) && propOrItem.path.endsWith('.length')) {
47 // skip array length checks in list
48 return
49 }
50
51 if (propOrItem.isItem) {
52 // if we didn't find a list, don't include item props
53 if (!listFromPath) return
54
55 propOrItem.path = `${listFromPath}.${propOrItem.path}`
56 }
57
58 flatProps[propOrItem.path] = propOrItem
59 })
60 })
61
62 const props = {}
63
64 Object.keys(flatProps)
65 .sort()
66 .forEach(key => {
67 const prop = flatProps[key]
68
69 if (key.includes('.')) {
70 const [main, ...rest] = key.split('.')
71 let ref = props[main]
72 if (!ref || typeof ref === 'string') {
73 ref = props[main] = {
74 type: prop.isItem ? 'array' : 'object',
75 shape: {},
76 }
77 }
78
79 // TODO support any nesting
80 rest.forEach(part => {
81 ref.shape[part] = prop.type
82 })
83 } else {
84 props[key] = prop.type
85 }
86 })
87
88 return props
89}