UNPKG

3.85 kBJavaScriptView Raw
1'use strict'
2const dox = require('dox')
3const fs = require('fs')
4const path = require('path')
5
6const readmePath = path.join(__dirname, '/../README.md')
7
8// read source
9const src = [
10 {
11 name: 'slapp',
12 src: fs.readFileSync(path.join(__dirname, '/../src/index.js'), { encoding: 'utf8' })
13 },
14 {
15 name: 'Slapp',
16 src: fs.readFileSync(path.join(__dirname, '/../src/slapp.js'), { encoding: 'utf8' })
17 },
18 {
19 name: 'Message',
20 description: `
21A Message object is created for every incoming Slack event, slash command, and interactive message action.
22It is generally always passed as \`msg\`.
23
24\`msg\` has three main top level properties
25- \`type\` - one of \`event\`, \`command\`, \`action\`
26- \`body\` - the unmodified payload of the original event
27- \`meta\` - derived or normalized properties and anything appended by middleware.
28
29\`meta\` should at least have these properties
30- \`app_token\` - token for the user for the app
31- \`app_user_id\` - userID for the user who install ed the app
32- \`bot_token\` - token for a bot user of the app
33- \`bot_user_id\` - userID of the bot user of the app
34 `,
35 src: fs.readFileSync(path.join(__dirname, '/../src/message.js'), { encoding: 'utf8' })
36 }
37]
38
39let apiLines = []
40
41src.forEach((item) => {
42 const comments = dox.parseComments(item.src, { raw: true })
43 apiLines.push('# ' + item.name)
44 if (item.description) apiLines.push(item.description)
45 apiLines.push(formatDoxComments(comments))
46})
47
48let api = apiLines.join('\n\n')
49let readme = fs.readFileSync(readmePath, { encoding: 'utf8' })
50let parts = readme.split('# API\n')
51let preamble = parts[0]
52parts = parts[1].split('# Contributing\n')
53let postamble = parts[1]
54
55let updatedReadme = [preamble, '# API\n\n', api, '\n\n# Contributing\n', postamble].join('')
56fs.writeFileSync(readmePath, updatedReadme)
57
58/**
59 * Adapted from dox source
60 */
61
62function formatDoxComments (comments) {
63 var buf = []
64
65 comments.forEach((comment) => {
66 if (comment.isPrivate) return
67 if (comment.ignore) return
68 var ctx = comment.ctx
69 var desc = comment.description
70 if (!ctx) return
71 if (~desc.full.indexOf('Module dependencies')) return
72 if (!ctx.string.indexOf('module.exports')) return
73 buf.push('### ' + context(comment))
74 buf.push('')
75 buf.push(desc.full.trim().replace(/^/gm, ' '))
76 buf.push('')
77 })
78
79 buf = buf
80 .join('\n')
81 .replace(/^ *#/gm, '')
82
83 var code = buf.match(/^( {4}[^\n]+\n*)+/gm) || []
84
85 code.forEach((block) => {
86 var code = block.replace(/^ {4}/gm, '')
87 buf = buf.replace(block, '```js\n' + code.trimRight() + '\n```\n\n')
88 })
89
90 return toc(buf) + '\n\n' + buf
91}
92
93function toc (str) {
94 return headings(str).filter((h) => { return h.level <= 2 }).map((h) => {
95 var clean = h.title.replace(/\(.*?\)/, '()')
96 return ' - [' + clean + '](#' + slug(h.title) + ')'
97 }).join('\n')
98}
99
100function slug (str) {
101 return str.replace(/\W+/g, '').toLowerCase()
102}
103
104function headings (str) {
105 return (str.match(/^#+ *([^\n]+)/gm) || []).map((str) => {
106 str = str.replace(/^(#+) */, '')
107 return {
108 title: str,
109 level: RegExp.$1.length
110 }
111 })
112}
113
114function context (comment) {
115 var ctx = comment.ctx
116 var tags = comment.tags
117
118 var alias = tags.map((tag) => {
119 return tag.type === 'alias' && tag.string
120 }).filter(Boolean)
121
122 let name
123
124 switch (ctx.type) {
125 case 'function':
126 name = alias.pop() || ctx.name
127 return name + '(' + params(tags) + ')'
128 case 'method':
129 case 'constructor':
130 name = alias.pop() || (ctx.cons || ctx.receiver) + '.' + ctx.name
131 return name + '(' + params(tags) + ')'
132 default:
133 return alias.pop() || ctx.string
134 }
135}
136
137function params (tags) {
138 return tags.filter((tag) => {
139 return tag.type === 'param'
140 }).map((param) => {
141 return param.name + ':' + param.types.join('|')
142 }).join(', ')
143}