@bwlng/blocks 0.1.0-fork.2e294b1
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/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +971 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +3 -0
- package/dist/validation-BG2u9jAE.d.ts +450 -0
- package/dist/validation-BG2u9jAE.d.ts.map +1 -0
- package/dist/validation-DAttVLF0.js +1051 -0
- package/dist/validation-DAttVLF0.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,1051 @@
|
|
|
1
|
+
//#region src/builders.ts
|
|
2
|
+
function header(text, opts) {
|
|
3
|
+
return {
|
|
4
|
+
type: "header",
|
|
5
|
+
text,
|
|
6
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function section(text, opts) {
|
|
10
|
+
return {
|
|
11
|
+
type: "section",
|
|
12
|
+
text,
|
|
13
|
+
...opts?.accessory !== void 0 && { accessory: opts.accessory },
|
|
14
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function divider(opts) {
|
|
18
|
+
return {
|
|
19
|
+
type: "divider",
|
|
20
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function fieldsBlock(fields, opts) {
|
|
24
|
+
return {
|
|
25
|
+
type: "fields",
|
|
26
|
+
fields,
|
|
27
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function table(opts) {
|
|
31
|
+
return {
|
|
32
|
+
type: "table",
|
|
33
|
+
columns: opts.columns,
|
|
34
|
+
rows: opts.rows,
|
|
35
|
+
page_action_id: opts.pageActionId,
|
|
36
|
+
...opts.nextCursor !== void 0 && { next_cursor: opts.nextCursor },
|
|
37
|
+
...opts.emptyText !== void 0 && { empty_text: opts.emptyText },
|
|
38
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function actionsBlock(elements, opts) {
|
|
42
|
+
return {
|
|
43
|
+
type: "actions",
|
|
44
|
+
elements,
|
|
45
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function stats(items, opts) {
|
|
49
|
+
return {
|
|
50
|
+
type: "stats",
|
|
51
|
+
items,
|
|
52
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function form(opts) {
|
|
56
|
+
return {
|
|
57
|
+
type: "form",
|
|
58
|
+
fields: opts.fields,
|
|
59
|
+
submit: {
|
|
60
|
+
label: opts.submit.label,
|
|
61
|
+
action_id: opts.submit.actionId
|
|
62
|
+
},
|
|
63
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function image(opts) {
|
|
67
|
+
return {
|
|
68
|
+
type: "image",
|
|
69
|
+
url: opts.url,
|
|
70
|
+
alt: opts.alt,
|
|
71
|
+
...opts.title !== void 0 && { title: opts.title },
|
|
72
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function context(text, opts) {
|
|
76
|
+
return {
|
|
77
|
+
type: "context",
|
|
78
|
+
text,
|
|
79
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function columnsBlock(columns, opts) {
|
|
83
|
+
return {
|
|
84
|
+
type: "columns",
|
|
85
|
+
columns,
|
|
86
|
+
...opts?.blockId !== void 0 && { block_id: opts.blockId }
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function bannerBlock(opts) {
|
|
90
|
+
return {
|
|
91
|
+
type: "banner",
|
|
92
|
+
...opts.title !== void 0 && { title: opts.title },
|
|
93
|
+
...opts.description !== void 0 && { description: opts.description },
|
|
94
|
+
...opts.variant !== void 0 && { variant: opts.variant },
|
|
95
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function textInput(actionId, label, opts) {
|
|
99
|
+
return {
|
|
100
|
+
type: "text_input",
|
|
101
|
+
action_id: actionId,
|
|
102
|
+
label,
|
|
103
|
+
...opts?.placeholder !== void 0 && { placeholder: opts.placeholder },
|
|
104
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue },
|
|
105
|
+
...opts?.multiline !== void 0 && { multiline: opts.multiline }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function numberInput(actionId, label, opts) {
|
|
109
|
+
return {
|
|
110
|
+
type: "number_input",
|
|
111
|
+
action_id: actionId,
|
|
112
|
+
label,
|
|
113
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue },
|
|
114
|
+
...opts?.min !== void 0 && { min: opts.min },
|
|
115
|
+
...opts?.max !== void 0 && { max: opts.max }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function select(actionId, label, options, opts) {
|
|
119
|
+
return {
|
|
120
|
+
type: "select",
|
|
121
|
+
action_id: actionId,
|
|
122
|
+
label,
|
|
123
|
+
options,
|
|
124
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue }
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function toggle(actionId, label, opts) {
|
|
128
|
+
return {
|
|
129
|
+
type: "toggle",
|
|
130
|
+
action_id: actionId,
|
|
131
|
+
label,
|
|
132
|
+
...opts?.description !== void 0 && { description: opts.description },
|
|
133
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue }
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function button(actionId, label, opts) {
|
|
137
|
+
return {
|
|
138
|
+
type: "button",
|
|
139
|
+
action_id: actionId,
|
|
140
|
+
label,
|
|
141
|
+
...opts?.style !== void 0 && { style: opts.style },
|
|
142
|
+
...opts?.value !== void 0 && { value: opts.value },
|
|
143
|
+
...opts?.confirm !== void 0 && { confirm: opts.confirm }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function secretInput(actionId, label, opts) {
|
|
147
|
+
return {
|
|
148
|
+
type: "secret_input",
|
|
149
|
+
action_id: actionId,
|
|
150
|
+
label,
|
|
151
|
+
...opts?.placeholder !== void 0 && { placeholder: opts.placeholder },
|
|
152
|
+
...opts?.hasValue !== void 0 && { has_value: opts.hasValue }
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function checkbox(actionId, label, options, opts) {
|
|
156
|
+
return {
|
|
157
|
+
type: "checkbox",
|
|
158
|
+
action_id: actionId,
|
|
159
|
+
label,
|
|
160
|
+
options,
|
|
161
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue }
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function dateInput(actionId, label, opts) {
|
|
165
|
+
return {
|
|
166
|
+
type: "date_input",
|
|
167
|
+
action_id: actionId,
|
|
168
|
+
label,
|
|
169
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue },
|
|
170
|
+
...opts?.placeholder !== void 0 && { placeholder: opts.placeholder }
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function combobox(actionId, label, options, opts) {
|
|
174
|
+
return {
|
|
175
|
+
type: "combobox",
|
|
176
|
+
action_id: actionId,
|
|
177
|
+
label,
|
|
178
|
+
options,
|
|
179
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue },
|
|
180
|
+
...opts?.placeholder !== void 0 && { placeholder: opts.placeholder }
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function radio(actionId, label, options, opts) {
|
|
184
|
+
return {
|
|
185
|
+
type: "radio",
|
|
186
|
+
action_id: actionId,
|
|
187
|
+
label,
|
|
188
|
+
options,
|
|
189
|
+
...opts?.initialValue !== void 0 && { initial_value: opts.initialValue }
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function timeseriesChart(opts) {
|
|
193
|
+
return {
|
|
194
|
+
type: "chart",
|
|
195
|
+
config: {
|
|
196
|
+
chart_type: "timeseries",
|
|
197
|
+
series: opts.series,
|
|
198
|
+
...opts.style !== void 0 && { style: opts.style },
|
|
199
|
+
...opts.xAxisName !== void 0 && { x_axis_name: opts.xAxisName },
|
|
200
|
+
...opts.yAxisName !== void 0 && { y_axis_name: opts.yAxisName },
|
|
201
|
+
...opts.height !== void 0 && { height: opts.height },
|
|
202
|
+
...opts.gradient !== void 0 && { gradient: opts.gradient }
|
|
203
|
+
},
|
|
204
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function customChart(opts) {
|
|
208
|
+
return {
|
|
209
|
+
type: "chart",
|
|
210
|
+
config: {
|
|
211
|
+
chart_type: "custom",
|
|
212
|
+
options: opts.options,
|
|
213
|
+
...opts.height !== void 0 && { height: opts.height }
|
|
214
|
+
},
|
|
215
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function meter(opts) {
|
|
219
|
+
return {
|
|
220
|
+
type: "meter",
|
|
221
|
+
label: opts.label,
|
|
222
|
+
value: opts.value,
|
|
223
|
+
...opts.max !== void 0 && { max: opts.max },
|
|
224
|
+
...opts.min !== void 0 && { min: opts.min },
|
|
225
|
+
...opts.customValue !== void 0 && { custom_value: opts.customValue },
|
|
226
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function codeBlock(opts) {
|
|
230
|
+
return {
|
|
231
|
+
type: "code",
|
|
232
|
+
code: opts.code,
|
|
233
|
+
...opts.language !== void 0 && { language: opts.language },
|
|
234
|
+
...opts.blockId !== void 0 && { block_id: opts.blockId }
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const blocks = {
|
|
238
|
+
header,
|
|
239
|
+
section,
|
|
240
|
+
divider,
|
|
241
|
+
fields: fieldsBlock,
|
|
242
|
+
table,
|
|
243
|
+
actions: actionsBlock,
|
|
244
|
+
stats,
|
|
245
|
+
form,
|
|
246
|
+
image,
|
|
247
|
+
context,
|
|
248
|
+
columns: columnsBlock,
|
|
249
|
+
timeseriesChart,
|
|
250
|
+
customChart,
|
|
251
|
+
banner: bannerBlock,
|
|
252
|
+
meter,
|
|
253
|
+
code: codeBlock
|
|
254
|
+
};
|
|
255
|
+
const elements = {
|
|
256
|
+
textInput,
|
|
257
|
+
numberInput,
|
|
258
|
+
select,
|
|
259
|
+
toggle,
|
|
260
|
+
button,
|
|
261
|
+
secretInput,
|
|
262
|
+
checkbox,
|
|
263
|
+
combobox,
|
|
264
|
+
dateInput,
|
|
265
|
+
radio
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region src/validation.ts
|
|
270
|
+
const BLOCK_TYPES = new Set([
|
|
271
|
+
"header",
|
|
272
|
+
"section",
|
|
273
|
+
"divider",
|
|
274
|
+
"fields",
|
|
275
|
+
"table",
|
|
276
|
+
"actions",
|
|
277
|
+
"stats",
|
|
278
|
+
"form",
|
|
279
|
+
"image",
|
|
280
|
+
"context",
|
|
281
|
+
"columns",
|
|
282
|
+
"chart",
|
|
283
|
+
"banner",
|
|
284
|
+
"meter",
|
|
285
|
+
"code"
|
|
286
|
+
]);
|
|
287
|
+
const ELEMENT_TYPES = new Set([
|
|
288
|
+
"button",
|
|
289
|
+
"text_input",
|
|
290
|
+
"number_input",
|
|
291
|
+
"select",
|
|
292
|
+
"toggle",
|
|
293
|
+
"secret_input",
|
|
294
|
+
"checkbox",
|
|
295
|
+
"radio",
|
|
296
|
+
"date_input",
|
|
297
|
+
"combobox"
|
|
298
|
+
]);
|
|
299
|
+
const COLUMN_FORMATS = new Set([
|
|
300
|
+
"text",
|
|
301
|
+
"badge",
|
|
302
|
+
"relative_time",
|
|
303
|
+
"number",
|
|
304
|
+
"code"
|
|
305
|
+
]);
|
|
306
|
+
const CODE_LANGUAGES = new Set([
|
|
307
|
+
"ts",
|
|
308
|
+
"tsx",
|
|
309
|
+
"jsonc",
|
|
310
|
+
"bash",
|
|
311
|
+
"css"
|
|
312
|
+
]);
|
|
313
|
+
const BUTTON_STYLES = new Set([
|
|
314
|
+
"primary",
|
|
315
|
+
"danger",
|
|
316
|
+
"secondary"
|
|
317
|
+
]);
|
|
318
|
+
const TREND_VALUES = new Set([
|
|
319
|
+
"up",
|
|
320
|
+
"down",
|
|
321
|
+
"neutral"
|
|
322
|
+
]);
|
|
323
|
+
const BANNER_VARIANTS = new Set([
|
|
324
|
+
"default",
|
|
325
|
+
"alert",
|
|
326
|
+
"error"
|
|
327
|
+
]);
|
|
328
|
+
/**
|
|
329
|
+
* Validate option uniqueness and that initial_value references a valid option.
|
|
330
|
+
* Used by select, radio, combobox, and checkbox element validation.
|
|
331
|
+
*/
|
|
332
|
+
function validateOptionValues(options, path, errors) {
|
|
333
|
+
const seen = /* @__PURE__ */ new Set();
|
|
334
|
+
for (let i = 0; i < options.length; i++) {
|
|
335
|
+
const opt = options[i];
|
|
336
|
+
if (isRecord(opt) && typeof opt.value === "string") {
|
|
337
|
+
if (seen.has(opt.value)) errors.push({
|
|
338
|
+
path: `${path}[${i}].value`,
|
|
339
|
+
message: `Duplicate option value '${opt.value}'`
|
|
340
|
+
});
|
|
341
|
+
seen.add(opt.value);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return seen;
|
|
345
|
+
}
|
|
346
|
+
function validateInitialValueInOptions(initialValue, validValues, path, errors) {
|
|
347
|
+
if (typeof initialValue === "string" && validValues.size > 0 && !validValues.has(initialValue)) errors.push({
|
|
348
|
+
path: `${path}.initial_value`,
|
|
349
|
+
message: `initial_value '${initialValue}' does not match any option value`
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function isRecord(v) {
|
|
353
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
354
|
+
}
|
|
355
|
+
function validateConfirmDialog(value, path, errors) {
|
|
356
|
+
if (!isRecord(value)) {
|
|
357
|
+
errors.push({
|
|
358
|
+
path,
|
|
359
|
+
message: "Confirm dialog must be an object"
|
|
360
|
+
});
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (typeof value.title !== "string") errors.push({
|
|
364
|
+
path: `${path}.title`,
|
|
365
|
+
message: "Required field 'title' must be a string"
|
|
366
|
+
});
|
|
367
|
+
if (typeof value.text !== "string") errors.push({
|
|
368
|
+
path: `${path}.text`,
|
|
369
|
+
message: "Required field 'text' must be a string"
|
|
370
|
+
});
|
|
371
|
+
if (typeof value.confirm !== "string") errors.push({
|
|
372
|
+
path: `${path}.confirm`,
|
|
373
|
+
message: "Required field 'confirm' must be a string"
|
|
374
|
+
});
|
|
375
|
+
if (typeof value.deny !== "string") errors.push({
|
|
376
|
+
path: `${path}.deny`,
|
|
377
|
+
message: "Required field 'deny' must be a string"
|
|
378
|
+
});
|
|
379
|
+
if (value.style !== void 0 && value.style !== "danger") errors.push({
|
|
380
|
+
path: `${path}.style`,
|
|
381
|
+
message: "Field 'style' must be \"danger\" if provided"
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function validateElement(value, path, errors) {
|
|
385
|
+
if (!isRecord(value)) {
|
|
386
|
+
errors.push({
|
|
387
|
+
path,
|
|
388
|
+
message: "Element must be an object"
|
|
389
|
+
});
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const type = value.type;
|
|
393
|
+
if (typeof type !== "string" || !ELEMENT_TYPES.has(type)) {
|
|
394
|
+
errors.push({
|
|
395
|
+
path: `${path}.type`,
|
|
396
|
+
message: `Unknown element type '${String(type)}'. Expected one of: ${[...ELEMENT_TYPES].join(", ")}`
|
|
397
|
+
});
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (typeof value.action_id !== "string") errors.push({
|
|
401
|
+
path: `${path}.action_id`,
|
|
402
|
+
message: "Required field 'action_id' must be a string"
|
|
403
|
+
});
|
|
404
|
+
if (typeof value.label !== "string") errors.push({
|
|
405
|
+
path: `${path}.label`,
|
|
406
|
+
message: "Required field 'label' must be a string"
|
|
407
|
+
});
|
|
408
|
+
switch (type) {
|
|
409
|
+
case "button":
|
|
410
|
+
if (value.style !== void 0 && (typeof value.style !== "string" || !BUTTON_STYLES.has(value.style))) errors.push({
|
|
411
|
+
path: `${path}.style`,
|
|
412
|
+
message: `Field 'style' must be one of: ${[...BUTTON_STYLES].join(", ")}`
|
|
413
|
+
});
|
|
414
|
+
if (value.confirm !== void 0) validateConfirmDialog(value.confirm, `${path}.confirm`, errors);
|
|
415
|
+
break;
|
|
416
|
+
case "text_input":
|
|
417
|
+
if (value.placeholder !== void 0 && typeof value.placeholder !== "string") errors.push({
|
|
418
|
+
path: `${path}.placeholder`,
|
|
419
|
+
message: "Field 'placeholder' must be a string"
|
|
420
|
+
});
|
|
421
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "string") errors.push({
|
|
422
|
+
path: `${path}.initial_value`,
|
|
423
|
+
message: "Field 'initial_value' must be a string"
|
|
424
|
+
});
|
|
425
|
+
if (value.multiline !== void 0 && typeof value.multiline !== "boolean") errors.push({
|
|
426
|
+
path: `${path}.multiline`,
|
|
427
|
+
message: "Field 'multiline' must be a boolean"
|
|
428
|
+
});
|
|
429
|
+
break;
|
|
430
|
+
case "number_input":
|
|
431
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "number") errors.push({
|
|
432
|
+
path: `${path}.initial_value`,
|
|
433
|
+
message: "Field 'initial_value' must be a number"
|
|
434
|
+
});
|
|
435
|
+
if (value.min !== void 0 && typeof value.min !== "number") errors.push({
|
|
436
|
+
path: `${path}.min`,
|
|
437
|
+
message: "Field 'min' must be a number"
|
|
438
|
+
});
|
|
439
|
+
if (value.max !== void 0 && typeof value.max !== "number") errors.push({
|
|
440
|
+
path: `${path}.max`,
|
|
441
|
+
message: "Field 'max' must be a number"
|
|
442
|
+
});
|
|
443
|
+
break;
|
|
444
|
+
case "select": {
|
|
445
|
+
let selectValidValues = /* @__PURE__ */ new Set();
|
|
446
|
+
if (!Array.isArray(value.options)) errors.push({
|
|
447
|
+
path: `${path}.options`,
|
|
448
|
+
message: "Required field 'options' must be an array"
|
|
449
|
+
});
|
|
450
|
+
else if (value.options.length === 0) errors.push({
|
|
451
|
+
path: `${path}.options`,
|
|
452
|
+
message: "Field 'options' must not be empty"
|
|
453
|
+
});
|
|
454
|
+
else {
|
|
455
|
+
for (let i = 0; i < value.options.length; i++) {
|
|
456
|
+
const opt = value.options[i];
|
|
457
|
+
if (!isRecord(opt)) {
|
|
458
|
+
errors.push({
|
|
459
|
+
path: `${path}.options[${i}]`,
|
|
460
|
+
message: "Option must be an object"
|
|
461
|
+
});
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (typeof opt.label !== "string") errors.push({
|
|
465
|
+
path: `${path}.options[${i}].label`,
|
|
466
|
+
message: "Option 'label' must be a string"
|
|
467
|
+
});
|
|
468
|
+
if (typeof opt.value !== "string") errors.push({
|
|
469
|
+
path: `${path}.options[${i}].value`,
|
|
470
|
+
message: "Option 'value' must be a string"
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
selectValidValues = validateOptionValues(value.options, `${path}.options`, errors);
|
|
474
|
+
}
|
|
475
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "string") errors.push({
|
|
476
|
+
path: `${path}.initial_value`,
|
|
477
|
+
message: "Field 'initial_value' must be a string"
|
|
478
|
+
});
|
|
479
|
+
if (value.initial_value !== void 0) validateInitialValueInOptions(value.initial_value, selectValidValues, path, errors);
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
case "toggle":
|
|
483
|
+
if (value.description !== void 0 && typeof value.description !== "string") errors.push({
|
|
484
|
+
path: `${path}.description`,
|
|
485
|
+
message: "Field 'description' must be a string"
|
|
486
|
+
});
|
|
487
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "boolean") errors.push({
|
|
488
|
+
path: `${path}.initial_value`,
|
|
489
|
+
message: "Field 'initial_value' must be a boolean"
|
|
490
|
+
});
|
|
491
|
+
break;
|
|
492
|
+
case "secret_input":
|
|
493
|
+
if (value.placeholder !== void 0 && typeof value.placeholder !== "string") errors.push({
|
|
494
|
+
path: `${path}.placeholder`,
|
|
495
|
+
message: "Field 'placeholder' must be a string"
|
|
496
|
+
});
|
|
497
|
+
if (value.has_value !== void 0 && typeof value.has_value !== "boolean") errors.push({
|
|
498
|
+
path: `${path}.has_value`,
|
|
499
|
+
message: "Field 'has_value' must be a boolean"
|
|
500
|
+
});
|
|
501
|
+
break;
|
|
502
|
+
case "checkbox": {
|
|
503
|
+
let checkboxValidValues = /* @__PURE__ */ new Set();
|
|
504
|
+
if (!Array.isArray(value.options)) errors.push({
|
|
505
|
+
path: `${path}.options`,
|
|
506
|
+
message: "Required field 'options' must be an array"
|
|
507
|
+
});
|
|
508
|
+
else if (value.options.length === 0) errors.push({
|
|
509
|
+
path: `${path}.options`,
|
|
510
|
+
message: "Field 'options' must not be empty"
|
|
511
|
+
});
|
|
512
|
+
else {
|
|
513
|
+
for (let i = 0; i < value.options.length; i++) {
|
|
514
|
+
const opt = value.options[i];
|
|
515
|
+
if (!isRecord(opt)) {
|
|
516
|
+
errors.push({
|
|
517
|
+
path: `${path}.options[${i}]`,
|
|
518
|
+
message: "Option must be an object"
|
|
519
|
+
});
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
if (typeof opt.label !== "string") errors.push({
|
|
523
|
+
path: `${path}.options[${i}].label`,
|
|
524
|
+
message: "Option 'label' must be a string"
|
|
525
|
+
});
|
|
526
|
+
if (typeof opt.value !== "string") errors.push({
|
|
527
|
+
path: `${path}.options[${i}].value`,
|
|
528
|
+
message: "Option 'value' must be a string"
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
checkboxValidValues = validateOptionValues(value.options, `${path}.options`, errors);
|
|
532
|
+
}
|
|
533
|
+
if (value.initial_value !== void 0) if (!Array.isArray(value.initial_value)) errors.push({
|
|
534
|
+
path: `${path}.initial_value`,
|
|
535
|
+
message: "Field 'initial_value' must be an array of strings"
|
|
536
|
+
});
|
|
537
|
+
else for (let i = 0; i < value.initial_value.length; i++) {
|
|
538
|
+
const item = value.initial_value[i];
|
|
539
|
+
if (typeof item !== "string") {
|
|
540
|
+
errors.push({
|
|
541
|
+
path: `${path}.initial_value[${i}]`,
|
|
542
|
+
message: "Each initial_value entry must be a string"
|
|
543
|
+
});
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
if (checkboxValidValues.size > 0 && !checkboxValidValues.has(item)) errors.push({
|
|
547
|
+
path: `${path}.initial_value[${i}]`,
|
|
548
|
+
message: `initial_value '${item}' does not match any option value`
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case "radio": {
|
|
554
|
+
let radioValidValues = /* @__PURE__ */ new Set();
|
|
555
|
+
if (!Array.isArray(value.options)) errors.push({
|
|
556
|
+
path: `${path}.options`,
|
|
557
|
+
message: "Required field 'options' must be an array"
|
|
558
|
+
});
|
|
559
|
+
else if (value.options.length === 0) errors.push({
|
|
560
|
+
path: `${path}.options`,
|
|
561
|
+
message: "Field 'options' must not be empty"
|
|
562
|
+
});
|
|
563
|
+
else {
|
|
564
|
+
for (let i = 0; i < value.options.length; i++) {
|
|
565
|
+
const opt = value.options[i];
|
|
566
|
+
if (!isRecord(opt)) {
|
|
567
|
+
errors.push({
|
|
568
|
+
path: `${path}.options[${i}]`,
|
|
569
|
+
message: "Option must be an object"
|
|
570
|
+
});
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (typeof opt.label !== "string") errors.push({
|
|
574
|
+
path: `${path}.options[${i}].label`,
|
|
575
|
+
message: "Option 'label' must be a string"
|
|
576
|
+
});
|
|
577
|
+
if (typeof opt.value !== "string") errors.push({
|
|
578
|
+
path: `${path}.options[${i}].value`,
|
|
579
|
+
message: "Option 'value' must be a string"
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
radioValidValues = validateOptionValues(value.options, `${path}.options`, errors);
|
|
583
|
+
}
|
|
584
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "string") errors.push({
|
|
585
|
+
path: `${path}.initial_value`,
|
|
586
|
+
message: "Field 'initial_value' must be a string"
|
|
587
|
+
});
|
|
588
|
+
if (value.initial_value !== void 0) validateInitialValueInOptions(value.initial_value, radioValidValues, path, errors);
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
case "date_input":
|
|
592
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "string") errors.push({
|
|
593
|
+
path: `${path}.initial_value`,
|
|
594
|
+
message: "Field 'initial_value' must be a string"
|
|
595
|
+
});
|
|
596
|
+
if (value.placeholder !== void 0 && typeof value.placeholder !== "string") errors.push({
|
|
597
|
+
path: `${path}.placeholder`,
|
|
598
|
+
message: "Field 'placeholder' must be a string"
|
|
599
|
+
});
|
|
600
|
+
break;
|
|
601
|
+
case "combobox": {
|
|
602
|
+
let comboboxValidValues = /* @__PURE__ */ new Set();
|
|
603
|
+
if (!Array.isArray(value.options)) errors.push({
|
|
604
|
+
path: `${path}.options`,
|
|
605
|
+
message: "Required field 'options' must be an array"
|
|
606
|
+
});
|
|
607
|
+
else if (value.options.length === 0) errors.push({
|
|
608
|
+
path: `${path}.options`,
|
|
609
|
+
message: "Field 'options' must not be empty"
|
|
610
|
+
});
|
|
611
|
+
else {
|
|
612
|
+
for (let i = 0; i < value.options.length; i++) {
|
|
613
|
+
const opt = value.options[i];
|
|
614
|
+
if (!isRecord(opt)) {
|
|
615
|
+
errors.push({
|
|
616
|
+
path: `${path}.options[${i}]`,
|
|
617
|
+
message: "Option must be an object"
|
|
618
|
+
});
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (typeof opt.label !== "string") errors.push({
|
|
622
|
+
path: `${path}.options[${i}].label`,
|
|
623
|
+
message: "Option 'label' must be a string"
|
|
624
|
+
});
|
|
625
|
+
if (typeof opt.value !== "string") errors.push({
|
|
626
|
+
path: `${path}.options[${i}].value`,
|
|
627
|
+
message: "Option 'value' must be a string"
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
comboboxValidValues = validateOptionValues(value.options, `${path}.options`, errors);
|
|
631
|
+
}
|
|
632
|
+
if (value.initial_value !== void 0 && typeof value.initial_value !== "string") errors.push({
|
|
633
|
+
path: `${path}.initial_value`,
|
|
634
|
+
message: "Field 'initial_value' must be a string"
|
|
635
|
+
});
|
|
636
|
+
if (value.initial_value !== void 0) validateInitialValueInOptions(value.initial_value, comboboxValidValues, path, errors);
|
|
637
|
+
if (value.placeholder !== void 0 && typeof value.placeholder !== "string") errors.push({
|
|
638
|
+
path: `${path}.placeholder`,
|
|
639
|
+
message: "Field 'placeholder' must be a string"
|
|
640
|
+
});
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function validateFormField(value, path, errors) {
|
|
646
|
+
validateElement(value, path, errors);
|
|
647
|
+
if (!isRecord(value)) return;
|
|
648
|
+
if (value.condition !== void 0) {
|
|
649
|
+
const cond = value.condition;
|
|
650
|
+
if (!isRecord(cond)) errors.push({
|
|
651
|
+
path: `${path}.condition`,
|
|
652
|
+
message: "Field 'condition' must be an object"
|
|
653
|
+
});
|
|
654
|
+
else if (typeof cond.field !== "string") errors.push({
|
|
655
|
+
path: `${path}.condition.field`,
|
|
656
|
+
message: "Condition 'field' must be a string"
|
|
657
|
+
});
|
|
658
|
+
else if (!("eq" in cond) && !("neq" in cond)) errors.push({
|
|
659
|
+
path: `${path}.condition`,
|
|
660
|
+
message: "Condition must have either 'eq' or 'neq'"
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const CHART_TYPES = new Set(["timeseries", "custom"]);
|
|
665
|
+
const CHART_STYLES = new Set(["line", "bar"]);
|
|
666
|
+
function validateChartSeries(value, path, errors) {
|
|
667
|
+
if (!isRecord(value)) {
|
|
668
|
+
errors.push({
|
|
669
|
+
path,
|
|
670
|
+
message: "Chart series must be an object"
|
|
671
|
+
});
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (typeof value.name !== "string") errors.push({
|
|
675
|
+
path: `${path}.name`,
|
|
676
|
+
message: "Required field 'name' must be a string"
|
|
677
|
+
});
|
|
678
|
+
if (!Array.isArray(value.data)) errors.push({
|
|
679
|
+
path: `${path}.data`,
|
|
680
|
+
message: "Required field 'data' must be an array of [timestamp, value] tuples"
|
|
681
|
+
});
|
|
682
|
+
else for (let i = 0; i < value.data.length; i++) {
|
|
683
|
+
const point = value.data[i];
|
|
684
|
+
if (!Array.isArray(point) || point.length !== 2 || typeof point[0] !== "number" || typeof point[1] !== "number") {
|
|
685
|
+
errors.push({
|
|
686
|
+
path: `${path}.data[${i}]`,
|
|
687
|
+
message: "Each data point must be a [number, number] tuple"
|
|
688
|
+
});
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (value.color !== void 0 && typeof value.color !== "string") errors.push({
|
|
693
|
+
path: `${path}.color`,
|
|
694
|
+
message: "Field 'color' must be a string if provided"
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
function validateChartConfig(value, path, errors) {
|
|
698
|
+
if (!isRecord(value)) {
|
|
699
|
+
errors.push({
|
|
700
|
+
path,
|
|
701
|
+
message: "Required field 'config' must be an object"
|
|
702
|
+
});
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const chartType = value.chart_type;
|
|
706
|
+
if (typeof chartType !== "string" || !CHART_TYPES.has(chartType)) {
|
|
707
|
+
errors.push({
|
|
708
|
+
path: `${path}.chart_type`,
|
|
709
|
+
message: `Field 'chart_type' must be one of: ${[...CHART_TYPES].join(", ")}`
|
|
710
|
+
});
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (value.height !== void 0) {
|
|
714
|
+
if (typeof value.height !== "number") errors.push({
|
|
715
|
+
path: `${path}.height`,
|
|
716
|
+
message: "Field 'height' must be a number if provided"
|
|
717
|
+
});
|
|
718
|
+
else if (value.height <= 0) errors.push({
|
|
719
|
+
path: `${path}.height`,
|
|
720
|
+
message: "Field 'height' must be a positive number"
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
switch (chartType) {
|
|
724
|
+
case "timeseries":
|
|
725
|
+
if (value.style !== void 0 && (typeof value.style !== "string" || !CHART_STYLES.has(value.style))) errors.push({
|
|
726
|
+
path: `${path}.style`,
|
|
727
|
+
message: `Field 'style' must be one of: ${[...CHART_STYLES].join(", ")}`
|
|
728
|
+
});
|
|
729
|
+
if (!Array.isArray(value.series)) errors.push({
|
|
730
|
+
path: `${path}.series`,
|
|
731
|
+
message: "Required field 'series' must be an array"
|
|
732
|
+
});
|
|
733
|
+
else if (value.series.length === 0) errors.push({
|
|
734
|
+
path: `${path}.series`,
|
|
735
|
+
message: "Field 'series' must not be empty"
|
|
736
|
+
});
|
|
737
|
+
else for (let i = 0; i < value.series.length; i++) validateChartSeries(value.series[i], `${path}.series[${i}]`, errors);
|
|
738
|
+
if (value.x_axis_name !== void 0 && typeof value.x_axis_name !== "string") errors.push({
|
|
739
|
+
path: `${path}.x_axis_name`,
|
|
740
|
+
message: "Field 'x_axis_name' must be a string if provided"
|
|
741
|
+
});
|
|
742
|
+
if (value.y_axis_name !== void 0 && typeof value.y_axis_name !== "string") errors.push({
|
|
743
|
+
path: `${path}.y_axis_name`,
|
|
744
|
+
message: "Field 'y_axis_name' must be a string if provided"
|
|
745
|
+
});
|
|
746
|
+
if (value.gradient !== void 0 && typeof value.gradient !== "boolean") errors.push({
|
|
747
|
+
path: `${path}.gradient`,
|
|
748
|
+
message: "Field 'gradient' must be a boolean if provided"
|
|
749
|
+
});
|
|
750
|
+
break;
|
|
751
|
+
case "custom":
|
|
752
|
+
if (!isRecord(value.options)) errors.push({
|
|
753
|
+
path: `${path}.options`,
|
|
754
|
+
message: "Required field 'options' must be an object"
|
|
755
|
+
});
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
function validateBlock(value, path, errors) {
|
|
760
|
+
if (!isRecord(value)) {
|
|
761
|
+
errors.push({
|
|
762
|
+
path,
|
|
763
|
+
message: "Block must be an object"
|
|
764
|
+
});
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
const type = value.type;
|
|
768
|
+
if (typeof type !== "string" || !BLOCK_TYPES.has(type)) {
|
|
769
|
+
errors.push({
|
|
770
|
+
path: `${path}.type`,
|
|
771
|
+
message: `Unknown block type '${String(type)}'. Expected one of: ${[...BLOCK_TYPES].join(", ")}`
|
|
772
|
+
});
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (value.block_id !== void 0 && typeof value.block_id !== "string") errors.push({
|
|
776
|
+
path: `${path}.block_id`,
|
|
777
|
+
message: "Field 'block_id' must be a string if provided"
|
|
778
|
+
});
|
|
779
|
+
switch (type) {
|
|
780
|
+
case "header":
|
|
781
|
+
if (typeof value.text !== "string") errors.push({
|
|
782
|
+
path: `${path}.text`,
|
|
783
|
+
message: "Required field 'text' must be a string"
|
|
784
|
+
});
|
|
785
|
+
break;
|
|
786
|
+
case "section":
|
|
787
|
+
if (typeof value.text !== "string") errors.push({
|
|
788
|
+
path: `${path}.text`,
|
|
789
|
+
message: "Required field 'text' must be a string"
|
|
790
|
+
});
|
|
791
|
+
if (value.accessory !== void 0) validateElement(value.accessory, `${path}.accessory`, errors);
|
|
792
|
+
break;
|
|
793
|
+
case "divider": break;
|
|
794
|
+
case "fields":
|
|
795
|
+
if (!Array.isArray(value.fields)) errors.push({
|
|
796
|
+
path: `${path}.fields`,
|
|
797
|
+
message: "Required field 'fields' must be an array"
|
|
798
|
+
});
|
|
799
|
+
else for (let i = 0; i < value.fields.length; i++) {
|
|
800
|
+
const f = value.fields[i];
|
|
801
|
+
if (!isRecord(f)) {
|
|
802
|
+
errors.push({
|
|
803
|
+
path: `${path}.fields[${i}]`,
|
|
804
|
+
message: "Field entry must be an object"
|
|
805
|
+
});
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
if (typeof f.label !== "string") errors.push({
|
|
809
|
+
path: `${path}.fields[${i}].label`,
|
|
810
|
+
message: "Required field 'label' must be a string"
|
|
811
|
+
});
|
|
812
|
+
if (typeof f.value !== "string") errors.push({
|
|
813
|
+
path: `${path}.fields[${i}].value`,
|
|
814
|
+
message: "Required field 'value' must be a string"
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
break;
|
|
818
|
+
case "table":
|
|
819
|
+
if (!Array.isArray(value.columns)) errors.push({
|
|
820
|
+
path: `${path}.columns`,
|
|
821
|
+
message: "Required field 'columns' must be an array"
|
|
822
|
+
});
|
|
823
|
+
else for (let i = 0; i < value.columns.length; i++) {
|
|
824
|
+
const col = value.columns[i];
|
|
825
|
+
if (!isRecord(col)) {
|
|
826
|
+
errors.push({
|
|
827
|
+
path: `${path}.columns[${i}]`,
|
|
828
|
+
message: "Column must be an object"
|
|
829
|
+
});
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
if (typeof col.key !== "string") errors.push({
|
|
833
|
+
path: `${path}.columns[${i}].key`,
|
|
834
|
+
message: "Required field 'key' must be a string"
|
|
835
|
+
});
|
|
836
|
+
if (typeof col.label !== "string") errors.push({
|
|
837
|
+
path: `${path}.columns[${i}].label`,
|
|
838
|
+
message: "Required field 'label' must be a string"
|
|
839
|
+
});
|
|
840
|
+
if (col.format !== void 0 && (typeof col.format !== "string" || !COLUMN_FORMATS.has(col.format))) errors.push({
|
|
841
|
+
path: `${path}.columns[${i}].format`,
|
|
842
|
+
message: `Field 'format' must be one of: ${[...COLUMN_FORMATS].join(", ")}`
|
|
843
|
+
});
|
|
844
|
+
if (col.sortable !== void 0 && typeof col.sortable !== "boolean") errors.push({
|
|
845
|
+
path: `${path}.columns[${i}].sortable`,
|
|
846
|
+
message: "Field 'sortable' must be a boolean"
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
if (!Array.isArray(value.rows)) errors.push({
|
|
850
|
+
path: `${path}.rows`,
|
|
851
|
+
message: "Required field 'rows' must be an array"
|
|
852
|
+
});
|
|
853
|
+
else for (let i = 0; i < value.rows.length; i++) if (!isRecord(value.rows[i])) errors.push({
|
|
854
|
+
path: `${path}.rows[${i}]`,
|
|
855
|
+
message: "Row must be an object"
|
|
856
|
+
});
|
|
857
|
+
if (typeof value.page_action_id !== "string") errors.push({
|
|
858
|
+
path: `${path}.page_action_id`,
|
|
859
|
+
message: "Required field 'page_action_id' must be a string"
|
|
860
|
+
});
|
|
861
|
+
if (value.next_cursor !== void 0 && typeof value.next_cursor !== "string") errors.push({
|
|
862
|
+
path: `${path}.next_cursor`,
|
|
863
|
+
message: "Field 'next_cursor' must be a string if provided"
|
|
864
|
+
});
|
|
865
|
+
if (value.empty_text !== void 0 && typeof value.empty_text !== "string") errors.push({
|
|
866
|
+
path: `${path}.empty_text`,
|
|
867
|
+
message: "Field 'empty_text' must be a string if provided"
|
|
868
|
+
});
|
|
869
|
+
break;
|
|
870
|
+
case "actions":
|
|
871
|
+
if (!Array.isArray(value.elements)) errors.push({
|
|
872
|
+
path: `${path}.elements`,
|
|
873
|
+
message: "Required field 'elements' must be an array"
|
|
874
|
+
});
|
|
875
|
+
else for (let i = 0; i < value.elements.length; i++) validateElement(value.elements[i], `${path}.elements[${i}]`, errors);
|
|
876
|
+
break;
|
|
877
|
+
case "stats":
|
|
878
|
+
if (!Array.isArray(value.items)) errors.push({
|
|
879
|
+
path: `${path}.items`,
|
|
880
|
+
message: "Required field 'items' must be an array"
|
|
881
|
+
});
|
|
882
|
+
else for (let i = 0; i < value.items.length; i++) {
|
|
883
|
+
const item = value.items[i];
|
|
884
|
+
if (!isRecord(item)) {
|
|
885
|
+
errors.push({
|
|
886
|
+
path: `${path}.items[${i}]`,
|
|
887
|
+
message: "Stat item must be an object"
|
|
888
|
+
});
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
if (typeof item.label !== "string") errors.push({
|
|
892
|
+
path: `${path}.items[${i}].label`,
|
|
893
|
+
message: "Required field 'label' must be a string"
|
|
894
|
+
});
|
|
895
|
+
if (typeof item.value !== "string" && typeof item.value !== "number") errors.push({
|
|
896
|
+
path: `${path}.items[${i}].value`,
|
|
897
|
+
message: "Required field 'value' must be a string or number"
|
|
898
|
+
});
|
|
899
|
+
if (item.description !== void 0 && typeof item.description !== "string") errors.push({
|
|
900
|
+
path: `${path}.items[${i}].description`,
|
|
901
|
+
message: "Field 'description' must be a string"
|
|
902
|
+
});
|
|
903
|
+
if (item.trend !== void 0 && (typeof item.trend !== "string" || !TREND_VALUES.has(item.trend))) errors.push({
|
|
904
|
+
path: `${path}.items[${i}].trend`,
|
|
905
|
+
message: `Field 'trend' must be one of: ${[...TREND_VALUES].join(", ")}`
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
break;
|
|
909
|
+
case "form":
|
|
910
|
+
if (!Array.isArray(value.fields)) errors.push({
|
|
911
|
+
path: `${path}.fields`,
|
|
912
|
+
message: "Required field 'fields' must be an array"
|
|
913
|
+
});
|
|
914
|
+
else for (let i = 0; i < value.fields.length; i++) validateFormField(value.fields[i], `${path}.fields[${i}]`, errors);
|
|
915
|
+
if (!isRecord(value.submit)) errors.push({
|
|
916
|
+
path: `${path}.submit`,
|
|
917
|
+
message: "Required field 'submit' must be an object"
|
|
918
|
+
});
|
|
919
|
+
else {
|
|
920
|
+
if (typeof value.submit.label !== "string") errors.push({
|
|
921
|
+
path: `${path}.submit.label`,
|
|
922
|
+
message: "Required field 'label' must be a string"
|
|
923
|
+
});
|
|
924
|
+
if (typeof value.submit.action_id !== "string") errors.push({
|
|
925
|
+
path: `${path}.submit.action_id`,
|
|
926
|
+
message: "Required field 'action_id' must be a string"
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
break;
|
|
930
|
+
case "image":
|
|
931
|
+
if (typeof value.url !== "string") errors.push({
|
|
932
|
+
path: `${path}.url`,
|
|
933
|
+
message: "Required field 'url' must be a string"
|
|
934
|
+
});
|
|
935
|
+
if (typeof value.alt !== "string") errors.push({
|
|
936
|
+
path: `${path}.alt`,
|
|
937
|
+
message: "Required field 'alt' must be a string"
|
|
938
|
+
});
|
|
939
|
+
if (value.title !== void 0 && typeof value.title !== "string") errors.push({
|
|
940
|
+
path: `${path}.title`,
|
|
941
|
+
message: "Field 'title' must be a string if provided"
|
|
942
|
+
});
|
|
943
|
+
break;
|
|
944
|
+
case "context":
|
|
945
|
+
if (typeof value.text !== "string") errors.push({
|
|
946
|
+
path: `${path}.text`,
|
|
947
|
+
message: "Required field 'text' must be a string"
|
|
948
|
+
});
|
|
949
|
+
break;
|
|
950
|
+
case "columns":
|
|
951
|
+
if (!Array.isArray(value.columns)) errors.push({
|
|
952
|
+
path: `${path}.columns`,
|
|
953
|
+
message: "Required field 'columns' must be an array"
|
|
954
|
+
});
|
|
955
|
+
else if (value.columns.length < 2 || value.columns.length > 3) errors.push({
|
|
956
|
+
path: `${path}.columns`,
|
|
957
|
+
message: "Field 'columns' must contain 2-3 column arrays"
|
|
958
|
+
});
|
|
959
|
+
else for (let i = 0; i < value.columns.length; i++) {
|
|
960
|
+
const col = value.columns[i];
|
|
961
|
+
if (!Array.isArray(col)) {
|
|
962
|
+
errors.push({
|
|
963
|
+
path: `${path}.columns[${i}]`,
|
|
964
|
+
message: "Each column must be an array of blocks"
|
|
965
|
+
});
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
for (let j = 0; j < col.length; j++) validateBlock(col[j], `${path}.columns[${i}][${j}]`, errors);
|
|
969
|
+
}
|
|
970
|
+
break;
|
|
971
|
+
case "chart":
|
|
972
|
+
validateChartConfig(value.config, `${path}.config`, errors);
|
|
973
|
+
break;
|
|
974
|
+
case "meter":
|
|
975
|
+
if (typeof value.label !== "string") errors.push({
|
|
976
|
+
path: `${path}.label`,
|
|
977
|
+
message: "Required field 'label' must be a string"
|
|
978
|
+
});
|
|
979
|
+
if (typeof value.value !== "number") errors.push({
|
|
980
|
+
path: `${path}.value`,
|
|
981
|
+
message: "Required field 'value' must be a number"
|
|
982
|
+
});
|
|
983
|
+
if (value.max !== void 0 && typeof value.max !== "number") errors.push({
|
|
984
|
+
path: `${path}.max`,
|
|
985
|
+
message: "Field 'max' must be a number if provided"
|
|
986
|
+
});
|
|
987
|
+
if (value.min !== void 0 && typeof value.min !== "number") errors.push({
|
|
988
|
+
path: `${path}.min`,
|
|
989
|
+
message: "Field 'min' must be a number if provided"
|
|
990
|
+
});
|
|
991
|
+
if (typeof value.min === "number" && typeof value.max === "number" && value.min >= value.max) errors.push({
|
|
992
|
+
path,
|
|
993
|
+
message: "Field 'min' must be less than 'max'"
|
|
994
|
+
});
|
|
995
|
+
if (value.custom_value !== void 0 && typeof value.custom_value !== "string") errors.push({
|
|
996
|
+
path: `${path}.custom_value`,
|
|
997
|
+
message: "Field 'custom_value' must be a string if provided"
|
|
998
|
+
});
|
|
999
|
+
break;
|
|
1000
|
+
case "code":
|
|
1001
|
+
if (typeof value.code !== "string") errors.push({
|
|
1002
|
+
path: `${path}.code`,
|
|
1003
|
+
message: "Required field 'code' must be a string"
|
|
1004
|
+
});
|
|
1005
|
+
if (value.language !== void 0 && (typeof value.language !== "string" || !CODE_LANGUAGES.has(value.language))) errors.push({
|
|
1006
|
+
path: `${path}.language`,
|
|
1007
|
+
message: `Field 'language' must be one of: ${[...CODE_LANGUAGES].join(", ")}`
|
|
1008
|
+
});
|
|
1009
|
+
break;
|
|
1010
|
+
case "banner":
|
|
1011
|
+
if (value.title !== void 0 && typeof value.title !== "string") errors.push({
|
|
1012
|
+
path: `${path}.title`,
|
|
1013
|
+
message: "Field 'title' must be a string if provided"
|
|
1014
|
+
});
|
|
1015
|
+
if (value.description !== void 0 && typeof value.description !== "string") errors.push({
|
|
1016
|
+
path: `${path}.description`,
|
|
1017
|
+
message: "Field 'description' must be a string if provided"
|
|
1018
|
+
});
|
|
1019
|
+
if (value.title === void 0 && value.description === void 0) errors.push({
|
|
1020
|
+
path,
|
|
1021
|
+
message: "Banner must have at least 'title' or 'description'"
|
|
1022
|
+
});
|
|
1023
|
+
if (value.variant !== void 0 && (typeof value.variant !== "string" || !BANNER_VARIANTS.has(value.variant))) errors.push({
|
|
1024
|
+
path: `${path}.variant`,
|
|
1025
|
+
message: `Field 'variant' must be one of: ${[...BANNER_VARIANTS].join(", ")}`
|
|
1026
|
+
});
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function validateBlocks(blocks) {
|
|
1031
|
+
const errors = [];
|
|
1032
|
+
if (!Array.isArray(blocks)) {
|
|
1033
|
+
errors.push({
|
|
1034
|
+
path: "blocks",
|
|
1035
|
+
message: "Blocks must be an array"
|
|
1036
|
+
});
|
|
1037
|
+
return {
|
|
1038
|
+
valid: false,
|
|
1039
|
+
errors
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
for (let i = 0; i < blocks.length; i++) validateBlock(blocks[i], `blocks[${i}]`, errors);
|
|
1043
|
+
return {
|
|
1044
|
+
valid: errors.length === 0,
|
|
1045
|
+
errors
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
//#endregion
|
|
1050
|
+
export { blocks as n, elements as r, validateBlocks as t };
|
|
1051
|
+
//# sourceMappingURL=validation-DAttVLF0.js.map
|