-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
123 lines (101 loc) · 3.63 KB
/
index.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
* Auto-generate documentation from the component's propTypes.
* Adapted from Material-UI's PropTypeDescription component:
* https://github.com/callemall/material-ui/blob/82482758573dc714b210529dcf092dab904db0ba/docs/src/app/components/PropTypeDescription.js
* (c) Call-Em-All
*/
import ts from '@babel/plugin-syntax-typescript'
import { parse } from 'react-docgen'
import { parse as parseDoctrine } from 'doctrine'
export default render
function generatePropType (type) {
switch (type.name) {
case 'func':
return 'function'
case 'custom':
return type.raw
case 'enum': {
const values = type.value.map(v => v.value).join('<br> ')
return `enum:<br> ${values}<br>`
}
case 'union':
return type.value.map(generatePropType).join(', ')
default:
return type.name
}
}
function generateTsPropType (type) {
switch (type.name) {
case 'union':
return type.raw
default:
return type.name
}
}
function generateDescription (required, description, type, tsType) {
const parsed = parseDoctrine(description)
// two new lines result in a newline in the table. all other new lines
// must be eliminated to prevent markdown mayhem.
const jsDocText = parsed.description.replace(/\n\n/g, '<br>').replace(/\n/g, ' ')
if (parsed.tags.some(tag => tag.title === 'ignore')) {
return null
}
let signature = ''
if (type != null && type.name === 'func' && parsed.tags.length > 0) {
// Remove new lines from tag descriptions to avoid markdown errors.
parsed.tags.forEach((tag) => {
if (tag.description) {
// eslint-disable-next-line no-param-reassign
tag.description = tag.description.replace(/\n/g, ' ')
}
})
// Split up the parsed tags into 'arguments' and 'returns' parsed objects. If there's no
// 'returns' parsed object (i.e., one with title being 'returns'), make one of type 'void'.
const parsedLength = parsed.tags.length
let parsedArgs = []
let parsedReturns
if (parsed.tags[parsedLength - 1].title === 'returns') {
parsedArgs = parsed.tags.slice(0, parsedLength - 1)
parsedReturns = parsed.tags[parsedLength - 1]
} else {
parsedArgs = parsed.tags
parsedReturns = {
type: { name: 'void' }
}
}
signature += '<br><br>**Signature:**<br>`function('
signature += parsedArgs.map(tag => `${tag.name}: ${tag.type.name}`).join(', ')
signature += `) => ${parsedReturns.type.name}\`<br>`
signature += parsedArgs.map(tag => `*${tag.name}:* ${tag.description}`).join('<br>')
if (parsedReturns.description) {
signature += `<br> *returns* (${parsedReturns.type.name}): ${parsedReturns.description}`
}
}
return `${jsDocText}${signature}`
}
function render (code) {
let text = '| Name | Type | Default | Description |\n' +
'|:-----|:-----|:-----|:-----|\n'
const [componentInfo] = parse(code, {
babelOptions: {
plugins: [
[ts, { isTSX: true }]
]
}
})
Object.keys(componentInfo.props).forEach((key) => {
const prop = componentInfo.props[key]
const description = generateDescription(prop.required, prop.description, prop.type, prop.tsType)
if (description === null) return
let defaultValue = ''
if (prop.defaultValue) {
defaultValue = prop.defaultValue.value.replace(/\n/g, '')
}
if (prop.required) {
key = `<span style="color: #31a148">${key} *</span>` // eslint-disable-line no-param-reassign
}
const ty = prop.tsType ? generateTsPropType(prop.tsType) : generatePropType(prop.type)
text += `| ${key} | ${ty} | ${defaultValue} | ${description} |\n`
})
return text
}