Skip to content

Commit bef3b66

Browse files
committed
doveadm: Abstract data parsing code out into reusable library/module
1 parent b9c5300 commit bef3b66

File tree

2 files changed

+162
-155
lines changed

2 files changed

+162
-155
lines changed

lib/data/doveadm.data.js

Lines changed: 3 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,8 @@
1-
import { doveadm_arg_types, doveadm_flag_types, getDoveadmCmdLine } from '../doveadm.js'
2-
import { getVitepressMd } from '../markdown.js'
3-
import { addWatchPaths, loadData, normalizeArrayData } from '../utility.js'
4-
import camelCase from 'camelcase'
5-
import slugify from '@sindresorhus/slugify'
6-
7-
const doveadm_userargs = {
8-
'all-users': {
9-
cli: 'A',
10-
example: false,
11-
type: doveadm_arg_types.BOOL,
12-
text: `Apply operation to all users.`
13-
},
14-
'socket-path': {
15-
cli: 'S',
16-
example: '/var/run/dovecot/doveadm-server',
17-
type: doveadm_arg_types.STRING,
18-
text: `Path to doveadm socket.`
19-
},
20-
user: {
21-
cli: 'u',
22-
example: 'username',
23-
type: doveadm_arg_types.STRING,
24-
text: `UID of user to apply operation to.`,
25-
},
26-
}
27-
28-
const doveadm_userfileargs = {
29-
/* Hidden from documentation.
30-
'trans-flags': {
31-
type: doveadm_arg_types.INTEGER,
32-
text: `Transaction flags.`
33-
},
34-
*/
35-
'user-file': {
36-
cli: 'F',
37-
type: doveadm_arg_types.STRING,
38-
text: `A filename. If set, fetch usernames from file. One username per line.`
39-
},
40-
}
41-
42-
function typeToString(type) {
43-
switch (type) {
44-
case doveadm_arg_types.ARRAY:
45-
return 'array'
46-
case doveadm_arg_types.BOOL:
47-
return 'boolean'
48-
case doveadm_arg_types.INTEGER:
49-
return 'integer'
50-
case doveadm_arg_types.STRING:
51-
return 'string'
52-
case doveadm_arg_types.SEARCH_QUERY:
53-
return 'search_query'
54-
case doveadm_arg_types.ISTREAM:
55-
return 'istream'
56-
}
57-
}
58-
59-
function argToHttpParam(arg) {
60-
return arg.split('-').reduce((s, c) =>
61-
s + (c.charAt(0).toUpperCase() + c.slice(1)))
62-
}
63-
64-
async function normalizeDoveadm(doveadm) {
65-
const md = await getVitepressMd()
66-
67-
for (const [k, v] of Object.entries(doveadm)) {
68-
if (!v) {
69-
delete doveadm[k]
70-
continue
71-
}
72-
73-
if (v.flags && (v.flags & doveadm_flag_types.USER)) {
74-
v.args = { ...v.args, ...doveadm_userargs }
75-
}
76-
77-
if (v.flags && (v.flags & doveadm_flag_types.USERFILE)) {
78-
v.args = { ...v.args, ...doveadm_userfileargs }
79-
}
80-
81-
/* Convert 'man' entry into a markdown link to man page.
82-
* We will add the hash to all URLs for simplicity; for those man
83-
* pages that don't have individual command names, this will just
84-
* be ignored by the browser. */
85-
if (v.man) {
86-
v.man_link = md.renderInline('[[man,' + v.man + ',' + slugify(k) + ']]')
87-
}
88-
89-
/* Change entries. */
90-
for (const k2 of ['added', 'changed', 'deprecated', 'removed']) {
91-
if (v[k2]) {
92-
const changes = []
93-
for (const[k3, v3] of Object.entries(v[k2])) {
94-
changes.push({
95-
text: v3 ? md.render(v3.trim()) : null,
96-
version: md.renderInline('[[' + k2 + ',' + k3 + ']]')
97-
})
98-
}
99-
v[k2] = changes
100-
}
101-
}
102-
103-
/* Response values. */
104-
if (v.response) {
105-
if (v.response.text) {
106-
v.response.text = md.render(String(v.response.text))
107-
}
108-
} else {
109-
delete v['response']
110-
}
111-
112-
/* Text Description. */
113-
if (v.text) {
114-
v.text = md.render(v.text)
115-
}
116-
117-
/* Cmd line arguments. */
118-
v.usage = k + (v.args ? ' ' + getDoveadmCmdLine(v.args) : '')
119-
120-
if (v.args) {
121-
const args = []
122-
for (const [k2, v2] of Object.entries(v.args)) {
123-
if (!v2.hidden) {
124-
args.push({
125-
/* Undefined examples will resolve to undefined. */
126-
cli_only: v2.cli_only,
127-
example: v2.example,
128-
flag: v2.cli ? '-' + v2.cli : (v2.positional ? k2 : '--' + k2),
129-
param: argToHttpParam(k2),
130-
type: typeToString(v2.type),
131-
text: v2.text ? md.render(v2.text) : null
132-
})
133-
}
134-
}
135-
v.args = args
136-
}
137-
if (!v.args || !v.args.length) {
138-
delete v['args']
139-
}
140-
141-
/* HTTP API info. */
142-
v.http_cmd = camelCase(k)
143-
}
144-
145-
return {
146-
doveadm: normalizeArrayData(
147-
doveadm,
148-
['tags']
149-
),
150-
http_api_link: md.renderInline('[[link,doveadm_http_api,HTTP API]]')
151-
}
152-
}
1+
import { addWatchPaths } from '../utility.js'
2+
import { loadDoveadm } from '../doveadm.js'
1533

1544
export default addWatchPaths({
1555
async load() {
156-
return await normalizeDoveadm(
157-
structuredClone((await loadData('doveadm')).doveadm)
158-
)
6+
return await loadDoveadm()
1597
}
1608
})

lib/doveadm.js

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import { getVitepressMd } from './markdown.js'
2+
import { loadData, normalizeArrayData } from './utility.js'
3+
import camelCase from 'camelcase'
4+
import slugify from '@sindresorhus/slugify'
5+
16
/* List of Doveadm argument value types. */
27
export const doveadm_arg_types = {
38
ARRAY: 1,
@@ -68,3 +73,157 @@ export function getDoveadmCmdLine(args) {
6873

6974
return ret.trim()
7075
}
76+
77+
const doveadm_userargs = {
78+
'all-users': {
79+
cli: 'A',
80+
example: false,
81+
type: doveadm_arg_types.BOOL,
82+
text: `Apply operation to all users.`
83+
},
84+
'socket-path': {
85+
cli: 'S',
86+
example: '/var/run/dovecot/doveadm-server',
87+
type: doveadm_arg_types.STRING,
88+
text: `Path to doveadm socket.`
89+
},
90+
user: {
91+
cli: 'u',
92+
example: 'username',
93+
type: doveadm_arg_types.STRING,
94+
text: `UID of user to apply operation to.`,
95+
},
96+
}
97+
98+
const doveadm_userfileargs = {
99+
/* Hidden from documentation.
100+
'trans-flags': {
101+
type: doveadm_arg_types.INTEGER,
102+
text: `Transaction flags.`
103+
},
104+
*/
105+
'user-file': {
106+
cli: 'F',
107+
type: doveadm_arg_types.STRING,
108+
text: `A filename. If set, fetch usernames from file. One username per line.`
109+
},
110+
}
111+
112+
function typeToString(type) {
113+
switch (type) {
114+
case doveadm_arg_types.ARRAY:
115+
return 'array'
116+
case doveadm_arg_types.BOOL:
117+
return 'boolean'
118+
case doveadm_arg_types.INTEGER:
119+
return 'integer'
120+
case doveadm_arg_types.STRING:
121+
return 'string'
122+
case doveadm_arg_types.SEARCH_QUERY:
123+
return 'search_query'
124+
case doveadm_arg_types.ISTREAM:
125+
return 'istream'
126+
}
127+
}
128+
129+
function argToHttpParam(arg) {
130+
return arg.split('-').reduce((s, c) =>
131+
s + (c.charAt(0).toUpperCase() + c.slice(1)))
132+
}
133+
134+
async function normalizeDoveadm(doveadm) {
135+
const md = await getVitepressMd()
136+
137+
for (const [k, v] of Object.entries(doveadm)) {
138+
if (!v) {
139+
delete doveadm[k]
140+
continue
141+
}
142+
143+
if (v.flags && (v.flags & doveadm_flag_types.USER)) {
144+
v.args = { ...v.args, ...doveadm_userargs }
145+
}
146+
147+
if (v.flags && (v.flags & doveadm_flag_types.USERFILE)) {
148+
v.args = { ...v.args, ...doveadm_userfileargs }
149+
}
150+
151+
/* Convert 'man' entry into a markdown link to man page.
152+
* We will add the hash to all URLs for simplicity; for those
153+
* man pages that don't have individual command names, this
154+
* will just be ignored by the browser. */
155+
if (v.man) {
156+
v.man_link = md.renderInline('[[man,' + v.man + ',' + slugify(k) + ']]')
157+
}
158+
159+
/* Change entries. */
160+
for (const k2 of ['added', 'changed', 'deprecated', 'removed']) {
161+
if (v[k2]) {
162+
const changes = []
163+
for (const[k3, v3] of Object.entries(v[k2])) {
164+
changes.push({
165+
text: v3 ? md.render(v3.trim()) : null,
166+
version: md.renderInline('[[' + k2 + ',' + k3 + ']]')
167+
})
168+
}
169+
v[k2] = changes
170+
}
171+
}
172+
173+
/* Response values. */
174+
if (v.response) {
175+
if (v.response.text) {
176+
v.response.text = md.render(String(v.response.text))
177+
}
178+
} else {
179+
delete v['response']
180+
}
181+
182+
/* Text Description. */
183+
if (v.text) {
184+
v.text = md.render(v.text)
185+
}
186+
187+
/* Cmd line arguments. */
188+
v.usage = k + (v.args ? ' ' + getDoveadmCmdLine(v.args) : '')
189+
190+
if (v.args) {
191+
const args = []
192+
for (const [k2, v2] of Object.entries(v.args)) {
193+
if (!v2.hidden) {
194+
args.push({
195+
cli_only: v2.cli_only,
196+
/* Undefined examples will
197+
* resolve to undefined. */
198+
example: v2.example,
199+
flag: v2.cli ? '-' + v2.cli : (v2.positional ? k2 : '--' + k2),
200+
param: argToHttpParam(k2),
201+
type: typeToString(v2.type),
202+
text: v2.text ? md.render(v2.text) : null
203+
})
204+
}
205+
}
206+
v.args = args
207+
}
208+
if (!v.args || !v.args.length) {
209+
delete v['args']
210+
}
211+
212+
/* HTTP API info. */
213+
v.http_cmd = camelCase(k)
214+
}
215+
216+
return {
217+
doveadm: normalizeArrayData(
218+
doveadm,
219+
['tags']
220+
),
221+
http_api_link: md.renderInline('[[link,doveadm_http_api,HTTP API]]')
222+
}
223+
}
224+
225+
export async function loadDoveadm() {
226+
return await normalizeDoveadm(
227+
structuredClone((await loadData('doveadm')).doveadm)
228+
)
229+
}

0 commit comments

Comments
 (0)