UNPKG

4.59 kBJavaScriptView Raw
1// @ts-ignore
2import jsdoc from 'jsdoc-api'
3import * as fs from 'fs'
4
5const firstTagContentRegex = /<\w>([^<]+)<\/\w>([^]*)/
6const jsdocReturnRegex = /\* @return {(.*)}/
7const jsdocTypeRegex = /\* @type {(.*)}/
8
9const files = fs.readdirSync('./').filter(file => /(?<!(test|config))\.js$/.test(file))
10
11const _ltregex = /</g
12const _rtregex = />/g
13/**
14 * @param {string} s
15 */
16const toSafeHtml = s => s.replace(_ltregex, '&lt;').replace(_rtregex, '&gt;')
17
18const READMEcontent = fs.readFileSync('./README.md', 'utf8')
19
20jsdoc.explain({
21 files,
22 configure: '.jsdoc.json'
23}).then(/** @param {Array<any>} json */ json => {
24 const strBuilder = []
25 /**
26 * @type {Object<string, { items: Array<any>, name: string, description: string }>}
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 * @type {Object<string,string>}
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 // strBuilder.push(JSON.stringify(item)) // output json for debugging
60 switch (item.kind) {
61 case 'class': {
62 if (item.params == null) {
63 classDescriptions[item.longname] = item.classdesc
64 break
65 }
66 }
67 // eslint-disable-next-line
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 // eslint-disable-next-line
79 case 'function': {
80 /**
81 * @param {string} name
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(/** @param {any} ret */ 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(/** @param {any} r */ 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})