iobroker.autodoc 0.9.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +126 -0
- package/admin/autodoc.png +0 -0
- package/admin/i18n/de.json +244 -0
- package/admin/i18n/en.json +241 -0
- package/admin/i18n/es.json +229 -0
- package/admin/i18n/fr.json +235 -0
- package/admin/i18n/it.json +229 -0
- package/admin/i18n/nl.json +229 -0
- package/admin/i18n/pl.json +229 -0
- package/admin/i18n/pt.json +229 -0
- package/admin/i18n/ru.json +229 -0
- package/admin/i18n/uk.json +229 -0
- package/admin/i18n/zh-cn.json +229 -0
- package/admin/jsonConfig.json +1490 -0
- package/io-package.json +253 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/aiEnhancer.js +2114 -0
- package/lib/autoHostTopologyMermaid.js +195 -0
- package/lib/dependencyAnalyzer.js +83 -0
- package/lib/diagnosisSnapshot.js +32 -0
- package/lib/discovery.js +953 -0
- package/lib/docTemplateConfig.js +422 -0
- package/lib/documentModel.js +640 -0
- package/lib/forumCard.js +70 -0
- package/lib/guestHelpContent.js +93 -0
- package/lib/guestScriptPrivacy.js +14 -0
- package/lib/hostDisplay.js +19 -0
- package/lib/htmlRenderer.js +4108 -0
- package/lib/htmlThemePresets.js +79 -0
- package/lib/htmlToPdf.js +99 -0
- package/lib/i18n.js +1309 -0
- package/lib/markdownRenderer.js +2025 -0
- package/lib/mermaidAutodocPalette.js +165 -0
- package/lib/mermaidServerSvg.js +252 -0
- package/lib/notifier.js +124 -0
- package/lib/quickStartGuide.js +180 -0
- package/lib/roleMapper.js +90 -0
- package/lib/scriptGroups.js +78 -0
- package/lib/versionTracker.js +312 -0
- package/main.js +1368 -0
- package/package.json +88 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional documentation layout: admin chapter visibility, custom Markdown sections.
|
|
3
|
+
* See PLAN.md → Custom Templates (Phase 5).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Chapters in generated Admin HTML / Markdown (admin profile). Order matches the default render sequence
|
|
8
|
+
* (custom before changelog, same as body builder).
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_ADMIN_CHAPTER_ORDER = [
|
|
11
|
+
'manual',
|
|
12
|
+
'system',
|
|
13
|
+
'adapters',
|
|
14
|
+
'rooms',
|
|
15
|
+
'scripts',
|
|
16
|
+
'schedule',
|
|
17
|
+
'userdata',
|
|
18
|
+
'aliases',
|
|
19
|
+
'maintenance',
|
|
20
|
+
'diagnosis',
|
|
21
|
+
'troubleshooting',
|
|
22
|
+
'custom',
|
|
23
|
+
'changelog',
|
|
24
|
+
'appendices',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extra chapter IDs that are valid in admin/user hidden-chapter lists but are not standalone chapters.
|
|
29
|
+
* 'mermaidAuto' hides only the auto-generated host topology (within the manual section).
|
|
30
|
+
* 'mermaid' hides only the user-defined Mermaid diagram.
|
|
31
|
+
*/
|
|
32
|
+
const EXTRA_HIDDEN_CHAPTER_IDS = ['mermaidAuto'];
|
|
33
|
+
|
|
34
|
+
/** User/Family HTML + matching Markdown export (profile user). */
|
|
35
|
+
const USER_HTML_CHAPTER_KEYS = [
|
|
36
|
+
'manual',
|
|
37
|
+
'ai',
|
|
38
|
+
'guestHelp',
|
|
39
|
+
'atAGlance',
|
|
40
|
+
'rooms',
|
|
41
|
+
'scripts',
|
|
42
|
+
'routines',
|
|
43
|
+
'ownerPlaybook',
|
|
44
|
+
'mermaid',
|
|
45
|
+
'adapters',
|
|
46
|
+
'custom',
|
|
47
|
+
'system',
|
|
48
|
+
'troubleshooting',
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Onboarding/Guest HTML + keys that apply to Markdown (profile onboarding).
|
|
53
|
+
* Order matches the original renderOnboardingHtml sequence:
|
|
54
|
+
* welcome (always first, not in loop) → quickstart → tips → guestHelp → stats → ai → capabilities
|
|
55
|
+
* → mermaid (noop, rendered in welcome) → rooms → routines → ownerPlaybook → automations
|
|
56
|
+
* → adapters → custom → hint → system → manual
|
|
57
|
+
*/
|
|
58
|
+
const ONBOARDING_HTML_CHAPTER_KEYS = [
|
|
59
|
+
'welcome',
|
|
60
|
+
'quickstart',
|
|
61
|
+
'tips',
|
|
62
|
+
'guestHelp',
|
|
63
|
+
'stats',
|
|
64
|
+
'ai',
|
|
65
|
+
'capabilities',
|
|
66
|
+
'mermaid',
|
|
67
|
+
'rooms',
|
|
68
|
+
'routines',
|
|
69
|
+
'ownerPlaybook',
|
|
70
|
+
'automations',
|
|
71
|
+
'adapters',
|
|
72
|
+
'custom',
|
|
73
|
+
'hint',
|
|
74
|
+
'system',
|
|
75
|
+
'manual',
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const MAX_CUSTOM_SECTIONS = 12;
|
|
79
|
+
const MAX_CUSTOM_BODY_CHARS = 24000;
|
|
80
|
+
const PROFILE_SET = new Set(['admin', 'user', 'onboarding']);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
84
|
+
* @returns {string[]} allowed admin chapter ids to hide
|
|
85
|
+
*/
|
|
86
|
+
function parseAdminHiddenChapters(config) {
|
|
87
|
+
return parseHiddenJsonArray(config, 'adminHiddenChaptersJson', 'adminHiddenChapters', [
|
|
88
|
+
...DEFAULT_ADMIN_CHAPTER_ORDER,
|
|
89
|
+
...EXTRA_HIDDEN_CHAPTER_IDS,
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
95
|
+
* @returns {string[]} user-profile chapter ids to hide
|
|
96
|
+
*/
|
|
97
|
+
function parseUserHiddenChapters(config) {
|
|
98
|
+
return parseHiddenJsonArray(config, 'userHiddenChaptersJson', 'userHiddenChapters', [
|
|
99
|
+
...USER_HTML_CHAPTER_KEYS,
|
|
100
|
+
...EXTRA_HIDDEN_CHAPTER_IDS,
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
106
|
+
* @returns {string[]} onboarding chapter ids to hide
|
|
107
|
+
*/
|
|
108
|
+
function parseOnboardingHiddenChapters(config) {
|
|
109
|
+
return parseHiddenJsonArray(
|
|
110
|
+
config,
|
|
111
|
+
'onboardingHiddenChaptersJson',
|
|
112
|
+
'onboardingHiddenChapters',
|
|
113
|
+
ONBOARDING_HTML_CHAPTER_KEYS,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
119
|
+
* @param {string} jsonKey - primary JSON string field name
|
|
120
|
+
* @param {string} legacyKey - fallback field for migration
|
|
121
|
+
* @param {string[]} allowedList - whitelist of chapter id strings
|
|
122
|
+
* @returns {string[]} filtered hidden chapter ids
|
|
123
|
+
*/
|
|
124
|
+
function parseHiddenJsonArray(config, jsonKey, legacyKey, allowedList) {
|
|
125
|
+
if (!config) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
let raw = config[jsonKey];
|
|
129
|
+
if (raw === undefined || raw === null) {
|
|
130
|
+
raw = config[legacyKey];
|
|
131
|
+
}
|
|
132
|
+
let arr = [];
|
|
133
|
+
if (typeof raw === 'string') {
|
|
134
|
+
const s = raw.trim();
|
|
135
|
+
if (!s) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
arr = JSON.parse(s);
|
|
140
|
+
} catch {
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
} else if (Array.isArray(raw)) {
|
|
144
|
+
arr = raw;
|
|
145
|
+
} else {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
if (!Array.isArray(arr)) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
const allowed = new Set(allowedList);
|
|
152
|
+
return arr.map(k => String(k).trim()).filter(k => allowed.has(k));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
157
|
+
* @returns {{ title: string, bodyMarkdown: string, profiles?: string[], anchorId: string }[]} custom Markdown blocks for export
|
|
158
|
+
*/
|
|
159
|
+
function parseCustomDocSections(config) {
|
|
160
|
+
if (!config || typeof config !== 'object') {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
const raw = Reflect.get(config, 'customDocSectionsJson');
|
|
164
|
+
let arr = [];
|
|
165
|
+
if (typeof raw === 'string') {
|
|
166
|
+
const s = raw.trim();
|
|
167
|
+
if (!s) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
arr = JSON.parse(s);
|
|
172
|
+
} catch {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
} else if (Array.isArray(raw)) {
|
|
176
|
+
arr = raw;
|
|
177
|
+
} else {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
if (!Array.isArray(arr)) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
183
|
+
const out = [];
|
|
184
|
+
for (let i = 0; i < arr.length && out.length < MAX_CUSTOM_SECTIONS; i++) {
|
|
185
|
+
const row = arr[i];
|
|
186
|
+
if (!row || typeof row !== 'object') {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const title = String(row.title || '').trim();
|
|
190
|
+
const body = String(row.body || row.bodyMarkdown || '').trim();
|
|
191
|
+
if (!title || !body) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
let profiles;
|
|
195
|
+
if (Array.isArray(row.profiles) && row.profiles.length) {
|
|
196
|
+
profiles = row.profiles.map(p => String(p).trim().toLowerCase()).filter(p => PROFILE_SET.has(p));
|
|
197
|
+
if (profiles.length === 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const bodyMarkdown = body.length > MAX_CUSTOM_BODY_CHARS ? body.slice(0, MAX_CUSTOM_BODY_CHARS) : body;
|
|
202
|
+
const anchorId = `custom-doc-${out.length}`;
|
|
203
|
+
out.push({ title, bodyMarkdown, profiles, anchorId });
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @param {string} [raw] - `htmlColorScheme` config value
|
|
210
|
+
* @returns {'auto'|'light'|'dark'} Normalized theme mode for HTML shell
|
|
211
|
+
*/
|
|
212
|
+
function parseHtmlColorScheme(raw) {
|
|
213
|
+
const s = String(raw || 'auto')
|
|
214
|
+
.trim()
|
|
215
|
+
.toLowerCase();
|
|
216
|
+
if (s === 'light' || s === 'dark') {
|
|
217
|
+
return s;
|
|
218
|
+
}
|
|
219
|
+
return 'auto';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @param {string} [raw] - user CSS font stack
|
|
224
|
+
* @returns {string} sanitized `font-family` fragment or empty
|
|
225
|
+
*/
|
|
226
|
+
function sanitizeFontStack(raw) {
|
|
227
|
+
if (raw == null || !String(raw).trim()) {
|
|
228
|
+
return '';
|
|
229
|
+
}
|
|
230
|
+
return String(raw)
|
|
231
|
+
.replace(/[{}<>]/g, '')
|
|
232
|
+
.trim()
|
|
233
|
+
.slice(0, 280);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {string} [raw] - logo URL for HTML export
|
|
238
|
+
* @returns {string} safe https/same-site path or empty
|
|
239
|
+
*/
|
|
240
|
+
function sanitizeLogoUrl(raw) {
|
|
241
|
+
if (raw == null || !String(raw).trim()) {
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
const s = String(raw).trim();
|
|
245
|
+
if (/^\s*javascript:/i.test(s) || /^\s*data:/i.test(s)) {
|
|
246
|
+
return '';
|
|
247
|
+
}
|
|
248
|
+
if (/^https?:\/\//i.test(s)) {
|
|
249
|
+
return s;
|
|
250
|
+
}
|
|
251
|
+
if (s.startsWith('/') && !s.startsWith('//')) {
|
|
252
|
+
return s;
|
|
253
|
+
}
|
|
254
|
+
return '';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Merge custom chapter order with the default list (duplicates / unknown keys are ignored; missing keys are appended in default order).
|
|
259
|
+
*
|
|
260
|
+
* @param {string[]} defaultOrder - product default chapter sequence
|
|
261
|
+
* @param {string[]} userOrder - user-provided id order
|
|
262
|
+
* @returns {string[]} merged id list, unknown ids dropped
|
|
263
|
+
*/
|
|
264
|
+
function mergeChapterOrder(defaultOrder, userOrder) {
|
|
265
|
+
if (!userOrder || userOrder.length === 0) {
|
|
266
|
+
return defaultOrder.slice();
|
|
267
|
+
}
|
|
268
|
+
const seen = new Set();
|
|
269
|
+
const out = [];
|
|
270
|
+
for (const k of userOrder) {
|
|
271
|
+
if (defaultOrder.includes(k) && !seen.has(k)) {
|
|
272
|
+
out.push(k);
|
|
273
|
+
seen.add(k);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
for (const k of defaultOrder) {
|
|
277
|
+
if (!seen.has(k)) {
|
|
278
|
+
out.push(k);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return out;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
286
|
+
* @param {string} jsonKey - primary JSON string field
|
|
287
|
+
* @param {string} legacyKey - legacy field name
|
|
288
|
+
* @param {string[]} allowedList - valid chapter ids
|
|
289
|
+
* @param {string[]} defaultOrder - fallback when unset or invalid
|
|
290
|
+
* @returns {string[]} final chapter id order
|
|
291
|
+
*/
|
|
292
|
+
function parseChapterOrderJson(config, jsonKey, legacyKey, allowedList, defaultOrder) {
|
|
293
|
+
if (!config) {
|
|
294
|
+
return defaultOrder.slice();
|
|
295
|
+
}
|
|
296
|
+
let raw = config[jsonKey];
|
|
297
|
+
if (raw === undefined || raw === null) {
|
|
298
|
+
raw = config[legacyKey];
|
|
299
|
+
}
|
|
300
|
+
let arr = [];
|
|
301
|
+
if (typeof raw === 'string') {
|
|
302
|
+
const s = raw.trim();
|
|
303
|
+
if (!s) {
|
|
304
|
+
return defaultOrder.slice();
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
arr = JSON.parse(s);
|
|
308
|
+
} catch {
|
|
309
|
+
return defaultOrder.slice();
|
|
310
|
+
}
|
|
311
|
+
} else if (Array.isArray(raw)) {
|
|
312
|
+
arr = raw;
|
|
313
|
+
} else {
|
|
314
|
+
return defaultOrder.slice();
|
|
315
|
+
}
|
|
316
|
+
if (!Array.isArray(arr) || arr.length === 0) {
|
|
317
|
+
return defaultOrder.slice();
|
|
318
|
+
}
|
|
319
|
+
const allowed = new Set(allowedList);
|
|
320
|
+
const seen = new Set();
|
|
321
|
+
const user = [];
|
|
322
|
+
for (const x of arr) {
|
|
323
|
+
const k = String(x).trim();
|
|
324
|
+
if (allowed.has(k) && !seen.has(k)) {
|
|
325
|
+
user.push(k);
|
|
326
|
+
seen.add(k);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (user.length === 0) {
|
|
330
|
+
return defaultOrder.slice();
|
|
331
|
+
}
|
|
332
|
+
return mergeChapterOrder(defaultOrder, user);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
337
|
+
* @returns {string[]} admin HTML/Markdown chapter order
|
|
338
|
+
*/
|
|
339
|
+
function parseAdminChapterOrder(config) {
|
|
340
|
+
return parseChapterOrderJson(
|
|
341
|
+
config,
|
|
342
|
+
'adminChapterOrderJson',
|
|
343
|
+
'adminChapterOrder',
|
|
344
|
+
DEFAULT_ADMIN_CHAPTER_ORDER,
|
|
345
|
+
DEFAULT_ADMIN_CHAPTER_ORDER,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
351
|
+
* @returns {string[]} user HTML/Markdown chapter order
|
|
352
|
+
*/
|
|
353
|
+
function parseUserChapterOrder(config) {
|
|
354
|
+
return parseChapterOrderJson(
|
|
355
|
+
config,
|
|
356
|
+
'userChapterOrderJson',
|
|
357
|
+
'userChapterOrder',
|
|
358
|
+
USER_HTML_CHAPTER_KEYS,
|
|
359
|
+
USER_HTML_CHAPTER_KEYS,
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @param {unknown} config - raw adapter `this.config`
|
|
365
|
+
* @returns {string[]} onboarding HTML/Markdown chapter order
|
|
366
|
+
*/
|
|
367
|
+
function parseOnboardingChapterOrder(config) {
|
|
368
|
+
return parseChapterOrderJson(
|
|
369
|
+
config,
|
|
370
|
+
'onboardingChapterOrderJson',
|
|
371
|
+
'onboardingChapterOrder',
|
|
372
|
+
ONBOARDING_HTML_CHAPTER_KEYS,
|
|
373
|
+
ONBOARDING_HTML_CHAPTER_KEYS,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const HTML_THEME_PRESET_IDS = new Set(['default', 'highContrast', 'warm', 'slate']);
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* @param {unknown} raw - config value (preset id)
|
|
381
|
+
* @returns {string} Preset id for HTML export
|
|
382
|
+
*/
|
|
383
|
+
function parseHtmlThemePreset(raw) {
|
|
384
|
+
const s = String(raw == null ? 'default' : raw)
|
|
385
|
+
.trim()
|
|
386
|
+
.toLowerCase()
|
|
387
|
+
.replace(/[\s_-]+/g, '');
|
|
388
|
+
const map = {
|
|
389
|
+
default: 'default',
|
|
390
|
+
highcontrast: 'highContrast',
|
|
391
|
+
warm: 'warm',
|
|
392
|
+
slate: 'slate',
|
|
393
|
+
};
|
|
394
|
+
if (map[s] !== undefined) {
|
|
395
|
+
return map[s];
|
|
396
|
+
}
|
|
397
|
+
const rawId = String(raw == null ? '' : raw).trim();
|
|
398
|
+
if (HTML_THEME_PRESET_IDS.has(rawId)) {
|
|
399
|
+
return rawId;
|
|
400
|
+
}
|
|
401
|
+
return 'default';
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
module.exports = {
|
|
405
|
+
DEFAULT_ADMIN_CHAPTER_ORDER,
|
|
406
|
+
USER_HTML_CHAPTER_KEYS,
|
|
407
|
+
ONBOARDING_HTML_CHAPTER_KEYS,
|
|
408
|
+
parseAdminHiddenChapters,
|
|
409
|
+
parseUserHiddenChapters,
|
|
410
|
+
parseOnboardingHiddenChapters,
|
|
411
|
+
parseCustomDocSections,
|
|
412
|
+
parseHtmlColorScheme,
|
|
413
|
+
parseAdminChapterOrder,
|
|
414
|
+
parseUserChapterOrder,
|
|
415
|
+
parseOnboardingChapterOrder,
|
|
416
|
+
mergeChapterOrder,
|
|
417
|
+
parseHtmlThemePreset,
|
|
418
|
+
sanitizeFontStack,
|
|
419
|
+
sanitizeLogoUrl,
|
|
420
|
+
MAX_CUSTOM_SECTIONS,
|
|
421
|
+
MAX_CUSTOM_BODY_CHARS,
|
|
422
|
+
};
|