1 | 'use strict'
|
2 | const dox = require('dox')
|
3 | const fs = require('fs')
|
4 | const path = require('path')
|
5 |
|
6 | const readmePath = path.join(__dirname, '/../README.md')
|
7 |
|
8 |
|
9 | const 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: `
|
21 | A Message object is created for every incoming Slack event, slash command, and interactive message action.
|
22 | It 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 |
|
39 | let apiLines = []
|
40 |
|
41 | src.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 |
|
48 | let api = apiLines.join('\n\n')
|
49 | let readme = fs.readFileSync(readmePath, { encoding: 'utf8' })
|
50 | let parts = readme.split('# API\n')
|
51 | let preamble = parts[0]
|
52 | parts = parts[1].split('# Contributing\n')
|
53 | let postamble = parts[1]
|
54 |
|
55 | let updatedReadme = [preamble, '# API\n\n', api, '\n\n# Contributing\n', postamble].join('')
|
56 | fs.writeFileSync(readmePath, updatedReadme)
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | function 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 |
|
93 | function 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 |
|
100 | function slug (str) {
|
101 | return str.replace(/\W+/g, '').toLowerCase()
|
102 | }
|
103 |
|
104 | function 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 |
|
114 | function 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 |
|
137 | function 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 | }
|