Skip to content

Commit 5cde0d8

Browse files
committed
settings: Abstract data parsing code out into reusable library/module
1 parent 3f31a02 commit 5cde0d8

File tree

2 files changed

+140
-132
lines changed

2 files changed

+140
-132
lines changed

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
})

lib/settings.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { getVitepressMd } from './markdown.js'
2+
import { loadData, normalizeArrayData } from './utility.js'
3+
14
/* List of Dovecot settings value types. */
25
export const setting_types = {
36
BOOLEAN: {
@@ -91,3 +94,137 @@ export const setting_types = {
9194
url: '[[link,settings_groups_includes]]'
9295
}
9396
}
97+
98+
function wrapInTag(str, tag) {
99+
if (tag)
100+
return `<${tag}>${str}</${tag}>`
101+
return str
102+
}
103+
104+
/* Resolve links in given parameter. If no singular link is detected, it is
105+
* rendered with the provided tag surrounding the value. */
106+
function normalizeString(md, str, tag = null) {
107+
let out = ''
108+
109+
if (str) {
110+
/* FIXME: This makes the following .startsWith() call work,
111+
* but might lead to type-specific errors, e.g. String({})
112+
* yields '[object Object]'. This still needs to be verified
113+
* manually. */
114+
out = String(str)
115+
if (!out.startsWith('[[')) {
116+
out = wrapInTag(out, tag)
117+
}
118+
return md.renderInline(out)
119+
}
120+
121+
return str
122+
}
123+
124+
/* Mark a plain item as an inter-settings dovecot-specific link, i.e.
125+
* [[setting,<item>]]. Don't process already marked links. */
126+
function normalizeArray(md, arr) {
127+
if (arr) {
128+
return arr.map(entry => (
129+
md.renderInline(
130+
entry.startsWith('[[')
131+
? entry
132+
: `[[setting,${entry}]]`
133+
)
134+
))
135+
}
136+
137+
return arr
138+
}
139+
140+
async function normalizeSettings(settings) {
141+
const data = normalizeArrayData(
142+
settings,
143+
['dependencies', 'seealso', 'tags', 'values_enum']
144+
)
145+
146+
const md = await getVitepressMd()
147+
148+
for (const [k, v] of Object.entries(data)) {
149+
if (!v) {
150+
delete data[k]
151+
continue
152+
}
153+
154+
/* Style default entry. */
155+
if (!!v.default) {
156+
if (['string', 'number'].includes(typeof v.default) ||
157+
v.default instanceof String)
158+
v.default = normalizeString(md, v.default, 'code')
159+
else {
160+
let out = normalizeString(md, v.default.value ?? '', 'code')
161+
if (out.length > 0)
162+
out += '<br />'
163+
if (!!v.default.text)
164+
out += `${normalizeString(md, v.default.text ?? '')}`
165+
v.default = out
166+
}
167+
}
168+
169+
/* Add list of dependencies. */
170+
v.dependencies = normalizeArray(md, v.dependencies)
171+
172+
/* Add markdown to seealso settings. */
173+
v.seealso = normalizeArray(md, v.seealso)
174+
175+
/* Plugin. */
176+
if (v.plugin) {
177+
v.plugin = [ v.plugin ].flat()
178+
v.plugin_link = v.plugin.map((x) =>
179+
md.renderInline('[[plugin,' + x + ']]')
180+
).join(', ')
181+
}
182+
183+
/* There can be multiple value entries. */
184+
if (!Array.isArray(v.values)) {
185+
v.values = [ v.values ]
186+
}
187+
188+
for (const v2 of v.values) {
189+
if (!v2) {
190+
throw new Error("Incorrect value type for " + k)
191+
}
192+
193+
if (v2.default_required && (v.default === undefined)) {
194+
throw new Error("Default value missing for " + k)
195+
}
196+
if (v2.enum_required && !v.values_enum) {
197+
throw new Error("Enum array missing for " + k)
198+
}
199+
200+
v2.url = md.renderInline(v2.url)
201+
202+
if (v2.no_default) {
203+
v.no_default = true
204+
}
205+
}
206+
207+
for (const k2 of ['added', 'changed', 'deprecated', 'removed']) {
208+
if (v[k2]) {
209+
const changes = []
210+
for (const[k3, v3] of Object.entries(v[k2])) {
211+
changes.push({
212+
text: v3 ? md.render(v3.trim()) : null,
213+
version: md.renderInline('[[' + k2 + ',' + k3 + ']]')
214+
})
215+
}
216+
v[k2] = changes
217+
}
218+
}
219+
220+
v.text = md.render(v.text.trim())
221+
}
222+
223+
return data
224+
}
225+
226+
export async function loadSettings() {
227+
return await normalizeSettings(
228+
structuredClone(loadData('settings').settings)
229+
)
230+
}

0 commit comments

Comments
 (0)