1 |
|
2 | import jsdoc from 'jsdoc-api'
|
3 | import * as fs from 'fs'
|
4 |
|
5 | const firstTagContentRegex = /<\w>([^<]+)<\/\w>([^]*)/
|
6 | const jsdocReturnRegex = /\* @return {(.*)}/
|
7 | const jsdocTypeRegex = /\* @type {(.*)}/
|
8 |
|
9 | const files = fs.readdirSync('./').filter(file => /(?<!(test|config))\.js$/.test(file))
|
10 |
|
11 | const _ltregex = /</g
|
12 | const _rtregex = />/g
|
13 |
|
14 |
|
15 |
|
16 | const toSafeHtml = s => s.replace(_ltregex, '<').replace(_rtregex, '>')
|
17 |
|
18 | const READMEcontent = fs.readFileSync('./README.md', 'utf8')
|
19 |
|
20 | jsdoc.explain({
|
21 | files,
|
22 | configure: '.jsdoc.json'
|
23 | }).then( json => {
|
24 | const strBuilder = []
|
25 | |
26 |
|
27 |
|
28 | const modules = {}
|
29 | json.forEach(item => {
|
30 | if (item.meta && item.meta.filename) {
|
31 | const mod = modules[item.meta.filename] || (modules[item.meta.filename] = { items: [], name: item.meta.filename.slice(0, -3), description: '' })
|
32 | if (item.kind === 'module') {
|
33 | mod.name = item.name
|
34 | mod.description = item.description || ''
|
35 | } else {
|
36 | mod.items.push(item)
|
37 | }
|
38 | }
|
39 | })
|
40 | |
41 |
|
42 |
|
43 | const classDescriptions = {}
|
44 | for (const fileName in modules) {
|
45 | const mod = modules[fileName]
|
46 | const items = mod.items
|
47 | const desc = firstTagContentRegex.exec(mod.description)
|
48 | const descHead = desc ? desc[1] : ''
|
49 | const descRest = desc ? desc[2] : ''
|
50 | strBuilder.push(`<details><summary><b>[lib0/${mod.name}]</b> ${descHead}</summary>`)
|
51 | strBuilder.push(`<pre>import * as ${mod.name} from 'lib0/${fileName.slice(0, -3)}'</pre>`)
|
52 | if (descRest.length > 0) {
|
53 | strBuilder.push(descRest)
|
54 | }
|
55 | strBuilder.push('<dl>')
|
56 | for (let i = 0; i < items.length; i++) {
|
57 | const item = items[i]
|
58 | if (!item.ignore && item.scope !== 'inner' && item.name[0] !== '_' && item.longname.indexOf('~') < 0) {
|
59 |
|
60 | switch (item.kind) {
|
61 | case 'class': {
|
62 | if (item.params == null) {
|
63 | classDescriptions[item.longname] = item.classdesc
|
64 | break
|
65 | }
|
66 | }
|
67 |
|
68 | case 'constant': {
|
69 | if (item.params == null && item.returns == null) {
|
70 | const typeEval = jsdocTypeRegex.exec(item.comment)
|
71 | strBuilder.push(`<b><code>${item.longname.slice(7)}${typeEval ? (': ' + toSafeHtml(typeEval[1])) : ''}</code></b><br>`)
|
72 | if (item.description) {
|
73 | strBuilder.push(`<dd>${item.description}</dd>`)
|
74 | }
|
75 | break
|
76 | }
|
77 | }
|
78 |
|
79 | case 'function': {
|
80 | |
81 |
|
82 |
|
83 | const getOriginalParamTypeDecl = name => {
|
84 | const regval = new RegExp('@param {(.*)} \\[?' + name + '\\]?[^\\w]*').exec(item.comment)
|
85 | return regval ? regval[1] : null
|
86 | }
|
87 | if (item.params == null && item.returns == null) {
|
88 | break
|
89 | }
|
90 | const paramVal = (item.params || []).map( ret => `${ret.name}: ${getOriginalParamTypeDecl(ret.name) || ret.type.names.join('|')}`).join(', ')
|
91 | const evalReturnRegex = jsdocReturnRegex.exec(item.comment)
|
92 | const returnVal = evalReturnRegex ? `: ${evalReturnRegex[1]}` : (item.returns ? item.returns.map( r => r.type.names.join('|')).join('|') : '')
|
93 | strBuilder.push(`<b><code>${item.kind === 'class' ? 'new ' : ''}${item.longname.slice(7)}(${toSafeHtml(paramVal)})${toSafeHtml(returnVal)}</code></b><br>`)
|
94 | const desc = item.description || item.classdesc || classDescriptions[item.longname] || null
|
95 | if (desc) {
|
96 | strBuilder.push(`<dd>${desc}</dd>`)
|
97 | }
|
98 | break
|
99 | }
|
100 | case 'member': {
|
101 | if (item.type) {
|
102 | strBuilder.push(`<b><code>${item.longname.slice(7)}: ${toSafeHtml(/** @type {RegExpExecArray} */ (jsdocTypeRegex.exec(item.comment))[1])}</code></b><br>`)
|
103 | if (item.description) {
|
104 | strBuilder.push(`<dd>${item.description}</dd>`)
|
105 | }
|
106 | }
|
107 | }
|
108 | }
|
109 | }
|
110 | }
|
111 | strBuilder.push('</dl>')
|
112 | strBuilder.push('</details>')
|
113 | }
|
114 | const replaceReadme = READMEcontent.replace(/<details>[^]*<\/details>/, strBuilder.join('\n'))
|
115 | fs.writeFileSync('./README.md', replaceReadme)
|
116 | })
|