Skip to content

Commit 02f9b9e

Browse files
slusarzcmouse
authored andcommitted
settings: Abstract data parsing code out into reusable library/module
1 parent b92aa06 commit 02f9b9e

File tree

4 files changed

+232
-224
lines changed

4 files changed

+232
-224
lines changed

data/settings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Dovecot settings. */
22

3-
import { setting_types } from '../lib/settings.js'
3+
import { setting_types } from '../lib/constants/settings.js'
44

55
export const settings = {
66

lib/constants/settings.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* List of Dovecot settings value types. */
2+
export const setting_types = {
3+
BOOLEAN: {
4+
label: 'Boolean',
5+
url: '[[link,settings_types_boolean]]',
6+
default_required: true,
7+
},
8+
IPADDR: {
9+
label: 'IP Address(es)',
10+
url: '[[link,settings_types_ip]]',
11+
// Default: empty
12+
},
13+
SIZE: {
14+
label: 'Size',
15+
url: '[[link,settings_types_size]]',
16+
default_required: true,
17+
},
18+
STRING: {
19+
label: 'String',
20+
url: '[[link,settings_types_string]]'
21+
// Default: empty
22+
},
23+
STRING_NOVAR: {
24+
label: 'String Without Variables',
25+
url: '[[link,settings_types_string_novar]]'
26+
// Default: empty
27+
},
28+
/* This is a String entry, with specific allowable values. */
29+
ENUM: {
30+
label: 'String',
31+
url: '[[link,settings_types_string]]',
32+
enum_required: true,
33+
},
34+
TIME: {
35+
label: 'Time',
36+
url: '[[link,settings_types_time]]',
37+
default_required: true,
38+
},
39+
TIME_MSECS: {
40+
label: 'Time (milliseconds)',
41+
url: '[[link,settings_types_time_msecs]]',
42+
default_required: true,
43+
},
44+
UINT: {
45+
label: 'Unsigned Integer',
46+
url: '[[link,settings_types_uint]]',
47+
default_required: true,
48+
},
49+
OCTAL_UINT: {
50+
label: 'Octal Unsigned Integer',
51+
url: '[[link,settings_types_octal_uint]]',
52+
default_required: true,
53+
},
54+
URL: {
55+
label: 'URL',
56+
url: '[[link,settings_types_url]]'
57+
// Default: empty
58+
},
59+
FILE: {
60+
label: 'File',
61+
url: '[[link,settings_types_file]]'
62+
// Default: empty
63+
},
64+
NAMED_FILTER: {
65+
label: 'Named Filter',
66+
url: '[[link,settings_types_named_filter]]',
67+
no_default: true,
68+
},
69+
NAMED_LIST_FILTER: {
70+
label: 'Named List Filter',
71+
url: '[[link,settings_types_named_list_filter]]'
72+
// Default: empty
73+
},
74+
STRLIST: {
75+
label: 'String List',
76+
url: '[[link,settings_types_strlist]]'
77+
// Default: empty
78+
},
79+
BOOLLIST: {
80+
label: 'Boolean List',
81+
url: '[[link,settings_types_boollist]]'
82+
// Default: empty
83+
},
84+
IN_PORT: {
85+
label: 'Port Number',
86+
url: '[[link,settings_types_in_port]]',
87+
default_required: true,
88+
},
89+
GROUP: {
90+
label: 'Settings Group',
91+
url: '[[link,settings_groups_includes]]'
92+
}
93+
}

lib/data/settings.data.js

Lines changed: 3 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,8 @@
1-
import { addWatchPaths, loadData, normalizeArrayData } from '../utility.js'
2-
import { getVitepressMd } from '../markdown.js'
3-
4-
function wrapInTag(str, tag) {
5-
if (tag)
6-
return `<${tag}>${str}</${tag}>`
7-
return str
8-
}
9-
10-
/* Resolve links in given parameter. If no singular link is detected, it is
11-
* rendered with the provided tag surrounding the value. */
12-
function normalizeString(md, str, tag = null) {
13-
let out = ''
14-
15-
if (str) {
16-
/* FIXME: This makes the following .startsWith() call work, but might
17-
* lead to type-specific errors, e.g. String({}) yields
18-
* '[object Object]'. This still needs to be verified manually. */
19-
out = String(str)
20-
if (!out.startsWith('[[')) {
21-
out = wrapInTag(out, tag)
22-
}
23-
return md.renderInline(out)
24-
}
25-
26-
return str
27-
}
28-
29-
/* Mark a plain item as an inter-settings dovecot-specific link, i.e.
30-
* [[setting,<item>]]. Don't process already marked links. */
31-
function normalizeArray(md, arr) {
32-
if (arr) {
33-
return arr.map(entry => (
34-
md.renderInline(
35-
entry.startsWith('[[')
36-
? entry
37-
: `[[setting,${entry}]]`
38-
)
39-
))
40-
}
41-
42-
return arr
43-
}
44-
45-
async function normalizeSettings(settings) {
46-
const data = normalizeArrayData(
47-
settings,
48-
['dependencies', 'seealso', 'tags', 'values_enum']
49-
)
50-
51-
const md = await getVitepressMd()
52-
53-
for (const [k, v] of Object.entries(data)) {
54-
if (!v) {
55-
delete data[k]
56-
continue
57-
}
58-
59-
/* Style default entry. */
60-
if (!!v.default) {
61-
if (['string', 'number'].includes(typeof v.default) ||
62-
v.default instanceof String)
63-
v.default = normalizeString(md, v.default, 'code')
64-
else {
65-
let out = normalizeString(md, v.default.value ?? '', 'code')
66-
if (out.length > 0)
67-
out += '<br />'
68-
if (!!v.default.text)
69-
out += `${normalizeString(md, v.default.text ?? '')}`
70-
v.default = out
71-
}
72-
}
73-
74-
/* Add list of dependencies. */
75-
v.dependencies = normalizeArray(md, v.dependencies)
76-
77-
/* Add markdown to seealso settings. */
78-
v.seealso = normalizeArray(md, v.seealso)
79-
80-
/* Plugin. */
81-
if (v.plugin) {
82-
v.plugin = [ v.plugin ].flat()
83-
v.plugin_link = v.plugin.map((x) =>
84-
md.renderInline('[[plugin,' + x + ']]')
85-
).join(', ')
86-
}
87-
88-
/* There can be multiple value entries. */
89-
if (!Array.isArray(v.values)) {
90-
v.values = [ v.values ]
91-
}
92-
93-
for (const v2 of v.values) {
94-
if (!v2) {
95-
throw new Error("Incorrect value type for " + k)
96-
}
97-
98-
if (v2.default_required && (v.default === undefined)) {
99-
throw new Error("Default value missing for " + k)
100-
}
101-
if (v2.enum_required && !v.values_enum) {
102-
throw new Error("Enum array missing for " + k)
103-
}
104-
105-
v2.url = md.renderInline(v2.url)
106-
107-
if (v2.no_default) {
108-
v.no_default = true
109-
}
110-
}
111-
112-
for (const k2 of ['added', 'changed', 'deprecated', 'removed']) {
113-
if (v[k2]) {
114-
const changes = []
115-
for (const[k3, v3] of Object.entries(v[k2])) {
116-
changes.push({
117-
text: v3 ? md.render(v3.trim()) : null,
118-
version: md.renderInline('[[' + k2 + ',' + k3 + ']]')
119-
})
120-
}
121-
v[k2] = changes
122-
}
123-
}
124-
125-
v.text = md.render(v.text.trim())
126-
}
127-
128-
return data
129-
}
1+
import { addWatchPaths } from '../utility.js'
2+
import { loadSettings } from '../settings.js'
1303

1314
export default addWatchPaths({
1325
async load() {
133-
return await normalizeSettings(
134-
structuredClone(loadData('settings').settings)
135-
)
6+
return await loadSettings()
1367
}
1378
})

0 commit comments

Comments
 (0)