@gooddata/sdk-model 11.62.0-alpha.3 → 11.62.0

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.
Files changed (89) hide show
  1. package/esm/genAI/chat.d.ts +3 -2
  2. package/esm/genAI/chat.d.ts.map +1 -1
  3. package/esm/index.d.ts +21 -10
  4. package/esm/index.d.ts.map +1 -1
  5. package/esm/index.js +20 -10
  6. package/esm/publisher/aliases.d.ts +580 -0
  7. package/esm/publisher/aliases.d.ts.map +1 -0
  8. package/esm/publisher/aliases.js +304 -0
  9. package/esm/publisher/v1/builtinPageLayouts.d.ts +45 -0
  10. package/esm/publisher/v1/builtinPageLayouts.d.ts.map +1 -0
  11. package/esm/publisher/{builtinPageLayouts.js → v1/builtinPageLayouts.js} +14 -14
  12. package/esm/publisher/{content.d.ts → v1/content.d.ts} +14 -14
  13. package/esm/publisher/v1/content.d.ts.map +1 -0
  14. package/esm/publisher/{content.js → v1/content.js} +1 -1
  15. package/esm/publisher/{document.d.ts → v1/document.d.ts} +21 -21
  16. package/esm/publisher/v1/document.d.ts.map +1 -0
  17. package/esm/publisher/v1/document.js +35 -0
  18. package/esm/publisher/v1/factory.d.ts +65 -0
  19. package/esm/publisher/v1/factory.d.ts.map +1 -0
  20. package/esm/publisher/{factory.js → v1/factory.js} +12 -12
  21. package/esm/publisher/{layout.d.ts → v1/layout.d.ts} +13 -13
  22. package/esm/publisher/v1/layout.d.ts.map +1 -0
  23. package/esm/publisher/{layout.js → v1/layout.js} +4 -4
  24. package/esm/publisher/{pageFormat.d.ts → v1/pageFormat.d.ts} +6 -6
  25. package/esm/publisher/v1/pageFormat.d.ts.map +1 -0
  26. package/esm/publisher/{pageFormat.js → v1/pageFormat.js} +6 -6
  27. package/esm/publisher/{pageLayout.d.ts → v1/pageLayout.d.ts} +27 -27
  28. package/esm/publisher/v1/pageLayout.d.ts.map +1 -0
  29. package/esm/publisher/{pageLayout.js → v1/pageLayout.js} +18 -18
  30. package/esm/publisher/{slot.d.ts → v1/slot.d.ts} +41 -41
  31. package/esm/publisher/v1/slot.d.ts.map +1 -0
  32. package/esm/publisher/v1/slot.js +90 -0
  33. package/esm/publisher/{styling.d.ts → v1/styling.d.ts} +36 -36
  34. package/esm/publisher/v1/styling.d.ts.map +1 -0
  35. package/esm/publisher/{styling.js → v1/styling.js} +14 -14
  36. package/esm/publisher/{variables.d.ts → v1/variables.d.ts} +10 -10
  37. package/esm/publisher/v1/variables.d.ts.map +1 -0
  38. package/esm/publisher/{variables.js → v1/variables.js} +4 -4
  39. package/esm/publisher/v2/checks.d.ts +58 -0
  40. package/esm/publisher/v2/checks.d.ts.map +1 -0
  41. package/esm/publisher/v2/checks.js +100 -0
  42. package/esm/publisher/v2/content.d.ts +154 -0
  43. package/esm/publisher/v2/content.d.ts.map +1 -0
  44. package/esm/publisher/v2/content.js +34 -0
  45. package/esm/publisher/v2/document.d.ts +116 -0
  46. package/esm/publisher/v2/document.d.ts.map +1 -0
  47. package/esm/publisher/v2/document.js +47 -0
  48. package/esm/publisher/v2/factory.d.ts +69 -0
  49. package/esm/publisher/v2/factory.d.ts.map +1 -0
  50. package/esm/publisher/v2/factory.js +80 -0
  51. package/esm/publisher/v2/layout.d.ts +48 -0
  52. package/esm/publisher/v2/layout.d.ts.map +1 -0
  53. package/esm/publisher/v2/layout.js +20 -0
  54. package/esm/publisher/v2/page.d.ts +67 -0
  55. package/esm/publisher/v2/page.d.ts.map +1 -0
  56. package/esm/publisher/v2/page.js +34 -0
  57. package/esm/publisher/v2/sections.d.ts +34 -0
  58. package/esm/publisher/v2/sections.d.ts.map +1 -0
  59. package/esm/publisher/v2/sections.js +40 -0
  60. package/esm/publisher/v2/structure.d.ts +5 -0
  61. package/esm/publisher/v2/structure.d.ts.map +1 -0
  62. package/esm/publisher/v2/structure.js +533 -0
  63. package/esm/publisher/v2/style.d.ts +323 -0
  64. package/esm/publisher/v2/style.d.ts.map +1 -0
  65. package/esm/publisher/v2/style.js +22 -0
  66. package/esm/publisher/v2/validation.d.ts +26 -0
  67. package/esm/publisher/v2/validation.d.ts.map +1 -0
  68. package/esm/publisher/v2/validation.js +157 -0
  69. package/esm/publisher/v2/widget.d.ts +295 -0
  70. package/esm/publisher/v2/widget.d.ts.map +1 -0
  71. package/esm/publisher/v2/widget.js +79 -0
  72. package/esm/sdk-model.d.ts +2364 -462
  73. package/esm/settings/settings.d.ts +11 -1
  74. package/esm/settings/settings.d.ts.map +1 -1
  75. package/package.json +3 -3
  76. package/esm/publisher/builtinPageLayouts.d.ts +0 -45
  77. package/esm/publisher/builtinPageLayouts.d.ts.map +0 -1
  78. package/esm/publisher/content.d.ts.map +0 -1
  79. package/esm/publisher/document.d.ts.map +0 -1
  80. package/esm/publisher/document.js +0 -35
  81. package/esm/publisher/factory.d.ts +0 -65
  82. package/esm/publisher/factory.d.ts.map +0 -1
  83. package/esm/publisher/layout.d.ts.map +0 -1
  84. package/esm/publisher/pageFormat.d.ts.map +0 -1
  85. package/esm/publisher/pageLayout.d.ts.map +0 -1
  86. package/esm/publisher/slot.d.ts.map +0 -1
  87. package/esm/publisher/slot.js +0 -87
  88. package/esm/publisher/styling.d.ts.map +0 -1
  89. package/esm/publisher/variables.d.ts.map +0 -1
@@ -0,0 +1,533 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { isDateFilterGranularity } from "../../dateFilterConfig/index.js";
3
+ import { arrayOf, describeValue, finiteNumber, id, isFiniteNumber, isLength, isNonEmptyString, isPlainObject, joinPath, nonEmptyString, numberIn, objRef, objectOf, oneOf, opacity, optional, positive, px, required, satisfying, trueOrFalse, } from "./checks.js";
4
+ import { PublisherPageSizesV2 } from "./page.js";
5
+ import { PublisherTextStyleNamesV2, } from "./style.js";
6
+ const themeName = "[A-Za-z0-9_-]+";
7
+ const hexColor = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
8
+ const rgbColor = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?|\.\d+)\s*)?\)$/;
9
+ const themeColor = new RegExp(`^\\{theme\\.(?:colors\\.(?:backgrounds|texts|lines)\\.${themeName}|palette\\.(?:primary|success|error|warning))\\}$`);
10
+ function isColor(value) {
11
+ if (!isNonEmptyString(value)) {
12
+ return false;
13
+ }
14
+ if (hexColor.test(value) || themeColor.test(value)) {
15
+ return true;
16
+ }
17
+ const rgb = rgbColor.exec(value);
18
+ if (rgb === null) {
19
+ return false;
20
+ }
21
+ const [, red, green, blue, alpha] = rgb;
22
+ return ([red, green, blue].every((channel) => Number(channel) <= 255) &&
23
+ (alpha === undefined || Number(alpha) <= 1));
24
+ }
25
+ const color = satisfying(isColor, "a theme color reference, #rgb, #rrggbb, #rrggbbaa, or rgb() with 3 or 4 arguments");
26
+ const themeImage = new RegExp(`^\\{theme\\.(?:logo|coverImage|assets\\.(?:logos|images)\\.${themeName})\\}$`);
27
+ const themeShadow = new RegExp(`^\\{theme\\.shadows\\.${themeName}\\}$`);
28
+ const httpsUrl = /^https:\/\/\S+$/;
29
+ const imageSource = satisfying((value) => isNonEmptyString(value) && (themeImage.test(value) || httpsUrl.test(value)), "a theme image reference or an https URL");
30
+ const shadowValue = satisfying((value) => value === "none" || (isNonEmptyString(value) && themeShadow.test(value)), `"none" or a {theme.shadows.<name>} reference`);
31
+ function themeStep(group, steps) {
32
+ const refs = steps.map((step) => `{theme.${group}.${step}}`);
33
+ return satisfying((value) => isLength(value) || refs.some((ref) => ref === value), `a length of 0 or more, or one of ${refs.join(", ")}`);
34
+ }
35
+ const gap = themeStep("spacing.gap", ["compact", "normal", "spacious"]);
36
+ const padding = themeStep("spacing.padding", ["compact", "normal", "spacious"]);
37
+ const radius = themeStep("corners", ["small", "medium", "large", "full"]);
38
+ const horizontalAlign = oneOf(["left", "center", "right"]);
39
+ const verticalAlign = oneOf(["top", "center", "bottom"]);
40
+ const borderLineStyle = oneOf(["solid", "dashed", "dotted", "none"]);
41
+ const backgroundKeys = {
42
+ backgroundColor: optional(color),
43
+ backgroundOpacity: optional(opacity),
44
+ backgroundImage: optional(imageSource),
45
+ backgroundImageOpacity: optional(opacity),
46
+ backgroundFit: optional(oneOf(["cover", "contain", "fill", "tile"])),
47
+ backgroundHorizontalAlign: optional(horizontalAlign),
48
+ backgroundVerticalAlign: optional(verticalAlign),
49
+ backgroundOffset: optional(px),
50
+ backgroundOffsetTop: optional(px),
51
+ backgroundOffsetRight: optional(px),
52
+ backgroundOffsetBottom: optional(px),
53
+ backgroundOffsetLeft: optional(px),
54
+ };
55
+ const paddingKeys = {
56
+ padding: optional(padding),
57
+ paddingTop: optional(padding),
58
+ paddingRight: optional(padding),
59
+ paddingBottom: optional(padding),
60
+ paddingLeft: optional(padding),
61
+ };
62
+ const borderKeys = {
63
+ borderWidth: optional(px),
64
+ borderStyle: optional(borderLineStyle),
65
+ borderColor: optional(color),
66
+ borderTopWidth: optional(px),
67
+ borderTopStyle: optional(borderLineStyle),
68
+ borderTopColor: optional(color),
69
+ borderRightWidth: optional(px),
70
+ borderRightStyle: optional(borderLineStyle),
71
+ borderRightColor: optional(color),
72
+ borderBottomWidth: optional(px),
73
+ borderBottomStyle: optional(borderLineStyle),
74
+ borderBottomColor: optional(color),
75
+ borderLeftWidth: optional(px),
76
+ borderLeftStyle: optional(borderLineStyle),
77
+ borderLeftColor: optional(color),
78
+ };
79
+ const cornerKeys = {
80
+ borderRadius: optional(radius),
81
+ borderTopLeftRadius: optional(radius),
82
+ borderTopRightRadius: optional(radius),
83
+ borderBottomRightRadius: optional(radius),
84
+ borderBottomLeftRadius: optional(radius),
85
+ };
86
+ const shadowKeys = {
87
+ shadow: optional(shadowValue),
88
+ shadowX: optional(finiteNumber),
89
+ shadowY: optional(finiteNumber),
90
+ shadowBlur: optional(px),
91
+ shadowSpread: optional(finiteNumber),
92
+ shadowColor: optional(color),
93
+ shadowOpacity: optional(opacity),
94
+ };
95
+ const boxKeys = {
96
+ ...backgroundKeys,
97
+ ...paddingKeys,
98
+ ...borderKeys,
99
+ ...cornerKeys,
100
+ ...shadowKeys,
101
+ opacity: optional(opacity),
102
+ };
103
+ const inheritedTextKeys = {
104
+ textStyle: optional(oneOf(PublisherTextStyleNamesV2)),
105
+ textColor: optional(color),
106
+ horizontalAlign: optional(oneOf(["left", "center", "right", "justify"])),
107
+ verticalAlign: optional(verticalAlign),
108
+ };
109
+ const textKeys = {
110
+ ...inheritedTextKeys,
111
+ fontSize: optional(px),
112
+ fontWeight: optional(numberIn(1, 1000)),
113
+ fontStyle: optional(oneOf(["normal", "italic"])),
114
+ lineHeight: optional(finiteNumber),
115
+ letterSpacing: optional(finiteNumber),
116
+ textTransform: optional(oneOf(["none", "uppercase", "lowercase", "capitalize"])),
117
+ textOverflow: optional(oneOf(["shrink", "clip", "ellipsis"])),
118
+ };
119
+ const pageStyle = objectOf()({
120
+ ...backgroundKeys,
121
+ ...paddingKeys,
122
+ ...inheritedTextKeys,
123
+ gap: optional(gap),
124
+ });
125
+ const containerStyle = objectOf()({
126
+ ...boxKeys,
127
+ ...inheritedTextKeys,
128
+ gap: optional(gap),
129
+ });
130
+ const textStyle = objectOf()(textKeys);
131
+ const textWidgetStyle = objectOf()({ ...boxKeys, ...textKeys });
132
+ const imageWidgetStyle = objectOf()({
133
+ ...boxKeys,
134
+ fit: optional(oneOf(["contain", "cover", "fill"])),
135
+ horizontalAlign: optional(horizontalAlign),
136
+ verticalAlign: optional(verticalAlign),
137
+ });
138
+ const chartStyle = objectOf()({
139
+ fontSize: optional(px),
140
+ textColor: optional(color),
141
+ axisLineColor: optional(color),
142
+ axisNameColor: optional(color),
143
+ axisNameSize: optional(px),
144
+ axisValueColor: optional(color),
145
+ axisValueSize: optional(px),
146
+ gridColor: optional(color),
147
+ plotLineColor: optional(color),
148
+ legendColor: optional(color),
149
+ legendSize: optional(px),
150
+ dataLabelColor: optional(color),
151
+ dataLabelSize: optional(px),
152
+ });
153
+ const tableStyle = objectOf()({
154
+ fontSize: optional(px),
155
+ rowHeight: optional(px),
156
+ gridColor: optional(color),
157
+ valueColor: optional(color),
158
+ nullValueColor: optional(color),
159
+ headerLabelColor: optional(color),
160
+ headerBackgroundColor: optional(color),
161
+ totalValueColor: optional(color),
162
+ totalBackgroundColor: optional(color),
163
+ subtotalBackgroundColor: optional(color),
164
+ });
165
+ const headlineStyle = objectOf()({
166
+ primaryValueColor: optional(color),
167
+ primaryValueSize: optional(px),
168
+ secondaryValueColor: optional(color),
169
+ secondaryValueSize: optional(px),
170
+ positiveColor: optional(color),
171
+ negativeColor: optional(color),
172
+ });
173
+ const visualizationStyle = objectOf()({
174
+ ...boxKeys,
175
+ chart: optional(chartStyle),
176
+ table: optional(tableStyle),
177
+ headline: optional(headlineStyle),
178
+ });
179
+ const plainObject = satisfying(isPlainObject, "an object");
180
+ const objRefs = arrayOf(objRef);
181
+ const plainObjects = arrayOf(plainObject);
182
+ const attributeFilterSourceKeys = {
183
+ displayForm: required(objRef),
184
+ localIdentifier: optional(id),
185
+ title: optional(nonEmptyString),
186
+ filterElementsBy: optional(plainObjects),
187
+ filterElementsByDate: optional(plainObjects),
188
+ validateElementsBy: optional(objRefs),
189
+ };
190
+ const filterVariants = {
191
+ attributeFilter: objectOf()({
192
+ attributeFilter: required(objectOf()({
193
+ ...attributeFilterSourceKeys,
194
+ negativeSelection: required(trueOrFalse),
195
+ attributeElements: required(plainObject),
196
+ selectionMode: optional(oneOf(["single", "multi"])),
197
+ })),
198
+ }),
199
+ arbitraryAttributeFilter: objectOf()({
200
+ arbitraryAttributeFilter: required(objectOf()({
201
+ ...attributeFilterSourceKeys,
202
+ values: required(arrayOf(satisfying((value) => value === null || typeof value === "string", "a value"))),
203
+ negativeSelection: required(trueOrFalse),
204
+ })),
205
+ }),
206
+ matchAttributeFilter: objectOf()({
207
+ matchAttributeFilter: required(objectOf()({
208
+ displayForm: required(objRef),
209
+ operator: required(oneOf(["contains", "startsWith", "endsWith"])),
210
+ literal: required(nonEmptyString),
211
+ caseSensitive: optional(trueOrFalse),
212
+ negativeSelection: optional(trueOrFalse),
213
+ localIdentifier: optional(id),
214
+ title: optional(nonEmptyString),
215
+ })),
216
+ }),
217
+ dateFilter: objectOf()({
218
+ dateFilter: required(objectOf()({
219
+ type: required(oneOf(["relative", "absolute"])),
220
+ granularity: required(satisfying(isDateFilterGranularity, "a date filter granularity")),
221
+ from: optional(satisfying((value) => isNonEmptyString(value) || isFiniteNumber(value), "a date or an offset")),
222
+ to: optional(satisfying((value) => isNonEmptyString(value) || isFiniteNumber(value), "a date or an offset")),
223
+ dataSet: optional(objRef),
224
+ attribute: optional(objRef),
225
+ localIdentifier: optional(id),
226
+ boundedFilter: optional(plainObject),
227
+ emptyValueHandling: optional(oneOf(["include", "exclude", "only"])),
228
+ })),
229
+ }),
230
+ dashboardMeasureValueFilter: objectOf()({
231
+ dashboardMeasureValueFilter: required(objectOf()({
232
+ measure: required(objRef),
233
+ localIdentifier: required(id),
234
+ conditions: optional(plainObjects),
235
+ dimensionality: optional(objRefs),
236
+ title: optional(nonEmptyString),
237
+ })),
238
+ }),
239
+ };
240
+ function filterItem(value, path, issues) {
241
+ const variant = isPlainObject(value)
242
+ ? Object.keys(filterVariants).find((key) => Object.hasOwn(value, key))
243
+ : undefined;
244
+ if (variant === undefined) {
245
+ issues.push({ path, message: `Expected a dashboard filter, got ${describeValue(value)}.` });
246
+ return;
247
+ }
248
+ filterVariants[variant](value, path, issues);
249
+ }
250
+ const filters = arrayOf(filterItem);
251
+ const filterReferenceVariants = {
252
+ attributeFilterReference: objectOf()({
253
+ type: required(oneOf(["attributeFilterReference"])),
254
+ displayForm: required(objRef),
255
+ }),
256
+ dateFilterReference: objectOf()({
257
+ type: required(oneOf(["dateFilterReference"])),
258
+ dataSet: required(objRef),
259
+ }),
260
+ measureValueFilterReference: objectOf()({
261
+ type: required(oneOf(["measureValueFilterReference"])),
262
+ measure: required(objRef),
263
+ }),
264
+ };
265
+ function filterReference(value, path, issues) {
266
+ const type = isPlainObject(value) ? value["type"] : undefined;
267
+ if (typeof type === "string" && Object.hasOwn(filterReferenceVariants, type)) {
268
+ filterReferenceVariants[type](value, path, issues);
269
+ }
270
+ else {
271
+ issues.push({ path, message: `Expected a dashboard filter reference, got ${describeValue(value)}.` });
272
+ }
273
+ }
274
+ const attributeFilterConfig = objectOf()({
275
+ localIdentifier: required(id),
276
+ mode: optional(oneOf(["readonly", "hidden", "active"])),
277
+ displayAsLabel: optional(objRef),
278
+ selectionType: optional(oneOf(["list", "text", "listOrText"])),
279
+ });
280
+ const placeholder = objectOf()({
281
+ hint: optional(nonEmptyString),
282
+ required: optional(trueOrFalse),
283
+ });
284
+ const widgetKeys = {
285
+ id: required(id),
286
+ proportion: optional(positive),
287
+ placeholder: optional(placeholder),
288
+ locked: optional(trueOrFalse),
289
+ };
290
+ const widgetTitle = objectOf()({
291
+ visible: optional(trueOrFalse),
292
+ text: optional(nonEmptyString),
293
+ style: optional(textStyle),
294
+ });
295
+ const visibility = objectOf()({ visible: optional(trueOrFalse) });
296
+ const autoVisibility = objectOf()({
297
+ visible: optional(oneOf([true, false, "auto"])),
298
+ });
299
+ const axisDisplay = objectOf()({
300
+ visible: optional(trueOrFalse),
301
+ name: optional(objectOf()({
302
+ visible: optional(trueOrFalse),
303
+ position: optional(oneOf(["low", "middle", "high"])),
304
+ })),
305
+ values: optional(objectOf()({
306
+ visible: optional(trueOrFalse),
307
+ rotation: optional(numberIn(-90, 90)),
308
+ })),
309
+ min: optional(finiteNumber),
310
+ max: optional(finiteNumber),
311
+ });
312
+ const visualizationDisplay = objectOf()({
313
+ legend: optional(objectOf()({
314
+ visible: optional(trueOrFalse),
315
+ position: optional(oneOf(["auto", "top", "bottom", "left", "right"])),
316
+ })),
317
+ xAxis: optional(axisDisplay),
318
+ yAxis: optional(axisDisplay),
319
+ secondaryYAxis: optional(axisDisplay),
320
+ gridlines: optional(visibility),
321
+ dataLabels: optional(autoVisibility),
322
+ dataPoints: optional(autoVisibility),
323
+ });
324
+ const takeawayGeneration = objectOf()({
325
+ instructions: optional(nonEmptyString),
326
+ context: optional(objectOf()({
327
+ widgets: optional(arrayOf(id)),
328
+ pageTitle: optional(trueOrFalse),
329
+ filters: optional(trueOrFalse),
330
+ otherPages: optional(trueOrFalse),
331
+ })),
332
+ });
333
+ const widgets = {
334
+ title: objectOf()({
335
+ ...widgetKeys,
336
+ type: required(oneOf(["title"])),
337
+ markdown: optional(nonEmptyString),
338
+ style: optional(textWidgetStyle),
339
+ }),
340
+ heading: objectOf()({
341
+ ...widgetKeys,
342
+ type: required(oneOf(["heading"])),
343
+ markdown: optional(nonEmptyString),
344
+ level: optional(oneOf([1, 2, 3, 4, 5, 6])),
345
+ style: optional(textWidgetStyle),
346
+ }),
347
+ text: objectOf()({
348
+ ...widgetKeys,
349
+ type: required(oneOf(["text"])),
350
+ markdown: optional(nonEmptyString),
351
+ decorative: optional(trueOrFalse),
352
+ style: optional(textWidgetStyle),
353
+ }),
354
+ image: objectOf()({
355
+ ...widgetKeys,
356
+ type: required(oneOf(["image"])),
357
+ source: optional(imageSource),
358
+ altText: optional(nonEmptyString),
359
+ decorative: optional(trueOrFalse),
360
+ style: optional(imageWidgetStyle),
361
+ }),
362
+ visualization: objectOf()({
363
+ ...widgetKeys,
364
+ type: required(oneOf(["visualization"])),
365
+ visualization: optional(objectOf()({
366
+ identifier: required(nonEmptyString),
367
+ type: required(oneOf(["insight"])),
368
+ })),
369
+ title: optional(widgetTitle),
370
+ altText: optional(nonEmptyString),
371
+ dateDataSet: optional(objectOf()({
372
+ identifier: required(nonEmptyString),
373
+ type: required(oneOf(["dataSet"])),
374
+ })),
375
+ ignoreDocumentPeriod: optional(trueOrFalse),
376
+ filters: optional(filters),
377
+ ignoreDocumentFilters: optional(arrayOf(filterReference)),
378
+ display: optional(visualizationDisplay),
379
+ style: optional(visualizationStyle),
380
+ }),
381
+ takeaway: objectOf()({
382
+ ...widgetKeys,
383
+ type: required(oneOf(["takeaway"])),
384
+ title: optional(widgetTitle),
385
+ markdown: optional(nonEmptyString),
386
+ generation: optional(takeawayGeneration),
387
+ style: optional(textWidgetStyle),
388
+ }),
389
+ };
390
+ const container = objectOf()({
391
+ type: required(oneOf(["row", "column"])),
392
+ id: optional(id),
393
+ children: required(arrayOf(layoutNode)),
394
+ proportion: optional(positive),
395
+ locked: optional(trueOrFalse),
396
+ style: optional(containerStyle),
397
+ });
398
+ function layoutNode(value, path, issues) {
399
+ const type = isPlainObject(value) ? value["type"] : undefined;
400
+ if (type === "row" || type === "column") {
401
+ container(value, path, issues);
402
+ }
403
+ else if (typeof type === "string" && Object.hasOwn(widgets, type)) {
404
+ widgets[type](value, path, issues);
405
+ }
406
+ else if (isPlainObject(value)) {
407
+ issues.push({ path: joinPath(path, "type"), message: `Unknown node type ${describeValue(type)}.` });
408
+ }
409
+ else {
410
+ issues.push({ path, message: `Expected a layout node, got ${describeValue(value)}.` });
411
+ }
412
+ }
413
+ const pageBodyKeys = {
414
+ kind: optional(oneOf(["cover", "section", "content"])),
415
+ pageSize: optional(oneOf(PublisherPageSizesV2)),
416
+ notes: optional(nonEmptyString),
417
+ style: optional(pageStyle),
418
+ layout: required(layoutNode),
419
+ filters: optional(filters),
420
+ };
421
+ export const checkPageBody = objectOf()(pageBodyKeys);
422
+ const documentPage = objectOf()({
423
+ ...pageBodyKeys,
424
+ id: required(id),
425
+ visible: optional(trueOrFalse),
426
+ });
427
+ function isCalendarDate(value) {
428
+ const parts = isNonEmptyString(value) ? /^(\d{4})-(\d{2})-(\d{2})$/.exec(value) : null;
429
+ if (parts === null) {
430
+ return false;
431
+ }
432
+ const [year, month, day] = parts.slice(1).map(Number);
433
+ const date = new Date(0);
434
+ date.setUTCFullYear(year, month - 1, day);
435
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
436
+ }
437
+ const date = satisfying(isCalendarDate, "a date as YYYY-MM-DD");
438
+ const periodVariants = {
439
+ absolute: objectOf()({
440
+ type: required(oneOf(["absolute"])),
441
+ granularity: required(oneOf(["GDC.time.date"])),
442
+ from: required(date),
443
+ to: required(date),
444
+ }),
445
+ relative: objectOf()({
446
+ type: required(oneOf(["relative"])),
447
+ granularity: required(satisfying(isDateFilterGranularity, "a date filter granularity")),
448
+ from: required(satisfying(Number.isInteger, "an integer")),
449
+ to: required(satisfying(Number.isInteger, "an integer")),
450
+ }),
451
+ };
452
+ function period(value, path, issues) {
453
+ if (!isPlainObject(value)) {
454
+ issues.push({ path, message: `Expected a period, got ${describeValue(value)}.` });
455
+ return;
456
+ }
457
+ const { type } = value;
458
+ if (type === "absolute" || type === "relative") {
459
+ periodVariants[type](value, path, issues);
460
+ }
461
+ else {
462
+ issues.push({
463
+ path: joinPath(path, "type"),
464
+ message: `Expected "absolute" or "relative", got ${describeValue(type)}.`,
465
+ });
466
+ }
467
+ }
468
+ const defaults = objectOf()({
469
+ pageSize: optional(oneOf(PublisherPageSizesV2)),
470
+ takeaway: optional(objectOf()({
471
+ generation: optional(takeawayGeneration),
472
+ })),
473
+ period: optional(period),
474
+ });
475
+ const section = objectOf()({
476
+ id: required(id),
477
+ title: optional(nonEmptyString),
478
+ description: optional(nonEmptyString),
479
+ pages: required(arrayOf(documentPage)),
480
+ });
481
+ export const checkDocumentContent = objectOf()({
482
+ defaults: optional(defaults),
483
+ filters: optional(filters),
484
+ attributeFilterConfigs: optional(arrayOf(attributeFilterConfig)),
485
+ style: optional(objectOf()({ ...backgroundKeys, gap: optional(gap) })),
486
+ locale: optional(nonEmptyString),
487
+ formatLocale: optional(nonEmptyString),
488
+ pages: optional(arrayOf(documentPage)),
489
+ sections: optional(arrayOf(section)),
490
+ });
491
+ const entityKeys = {
492
+ ref: optional(objRef),
493
+ title: required(nonEmptyString),
494
+ description: optional(nonEmptyString),
495
+ tags: optional(arrayOf(nonEmptyString)),
496
+ version: required(oneOf(["2"])),
497
+ created: optional(nonEmptyString),
498
+ updated: optional(nonEmptyString),
499
+ createdBy: optional(satisfying(isPlainObject, "a user")),
500
+ updatedBy: optional(satisfying(isPlainObject, "a user")),
501
+ isLocked: optional(trueOrFalse),
502
+ };
503
+ const entities = {
504
+ document: objectOf()({
505
+ ...entityKeys,
506
+ type: required(oneOf(["document"])),
507
+ period: required(period),
508
+ content: required(checkDocumentContent),
509
+ }),
510
+ documentTemplate: objectOf()({
511
+ ...entityKeys,
512
+ type: required(oneOf(["documentTemplate"])),
513
+ content: required(checkDocumentContent),
514
+ }),
515
+ pageTemplate: objectOf()({
516
+ ...entityKeys,
517
+ type: required(oneOf(["pageTemplate"])),
518
+ content: required(checkPageBody),
519
+ isDefault: optional(trueOrFalse),
520
+ }),
521
+ };
522
+ export function checkEntity(value, path, issues) {
523
+ const type = isPlainObject(value) ? value["type"] : undefined;
524
+ if (type === "document" || type === "documentTemplate" || type === "pageTemplate") {
525
+ entities[type](value, path, issues);
526
+ }
527
+ else {
528
+ issues.push({
529
+ path: joinPath(path, "type"),
530
+ message: `Expected "document", "documentTemplate" or "pageTemplate", got ${describeValue(type)}.`,
531
+ });
532
+ }
533
+ }