@gooddata/sdk-model 11.57.0-alpha.4 → 11.57.0-alpha.6

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.
@@ -1,208 +0,0 @@
1
- // (C) 2026 GoodData Corporation
2
- /**
3
- * Prefix of the report variables brand kit images resolve; custom report variables must not
4
- * use it.
5
- *
6
- * @alpha
7
- */
8
- export const ReportsBrandKitImageVariablePrefix = "image_";
9
- /**
10
- * Name of the report variable resolving the brand kit image with the given id.
11
- *
12
- * @alpha
13
- */
14
- export function reportsBrandKitImageVariable(imageId) {
15
- return `${ReportsBrandKitImageVariablePrefix}${imageId}`;
16
- }
17
- const imageIdPattern = /^[a-zA-Z0-9_]+$/;
18
- const HEX_COLOR = /^#(?<digits>[0-9a-f]{3,8})$/i;
19
- // Either the comma form or the space form, not a mixture of the two, and an alpha that is an
20
- // actual number: `rgb(1, 2 3)` and `rgba(1,2,3,.)` are no more colors than a word would be.
21
- const RGB_NUMBER = String.raw `\d{1,3}`;
22
- const RGB_ALPHA = String.raw `(?:\d+(?:\.\d+)?|\.\d+)%?`;
23
- const RGB_COLOR = new RegExp(String.raw `^rgba?\(\s*(?:` +
24
- String.raw `(?<r>${RGB_NUMBER})\s*,\s*(?<g>${RGB_NUMBER})\s*,\s*(?<b>${RGB_NUMBER})(?:\s*,\s*${RGB_ALPHA})?` +
25
- String.raw `|` +
26
- String.raw `(?<rs>${RGB_NUMBER})\s+(?<gs>${RGB_NUMBER})\s+(?<bs>${RGB_NUMBER})(?:\s*/\s*${RGB_ALPHA})?` +
27
- String.raw `)\s*\)$`, "i");
28
- // Alpha is dropped from a 4- or 8-digit hex and from rgba(): a palette fill is opaque rgb.
29
- function fromHexDigits(digits) {
30
- const short = digits.length === 3 || digits.length === 4;
31
- if (!short && digits.length !== 6 && digits.length !== 8) {
32
- return undefined;
33
- }
34
- const width = short ? 1 : 2;
35
- const channel = (index) => {
36
- const part = digits.slice(index * width, index * width + width);
37
- return Number.parseInt(short ? part + part : part, 16);
38
- };
39
- return { r: channel(0), g: channel(1), b: channel(2) };
40
- }
41
- /**
42
- * Reads one of {@link IReportsBrandKitColors.chart} as rgb channels, or undefined where the value is
43
- * not one of the notations those colors are stated in.
44
- *
45
- * @remarks
46
- * Chart colors become palette entries rather than CSS declarations, so unlike the rest of the kit
47
- * they are held to what this reads: hex (3, 4, 6 or 8 digits) and `rgb()`/`rgba()`. The sanitizer
48
- * drops what this cannot read, so a stored kit never carries a chart color the palette would
49
- * silently ignore.
50
- *
51
- * @alpha
52
- */
53
- export function parseReportsBrandChartColor(color) {
54
- const trimmed = color.trim();
55
- const hex = HEX_COLOR.exec(trimmed);
56
- if (hex?.groups) {
57
- return fromHexDigits(hex.groups["digits"]);
58
- }
59
- const rgb = RGB_COLOR.exec(trimmed);
60
- if (rgb?.groups) {
61
- // One of the two forms matched, so each channel sits in exactly one of the two group sets.
62
- const channels = [
63
- ["r", "rs"],
64
- ["g", "gs"],
65
- ["b", "bs"],
66
- ].map(([comma, space]) => Number(rgb.groups[comma] ?? rgb.groups[space]));
67
- return channels.every((value) => value <= 255)
68
- ? { r: channels[0], g: channels[1], b: channels[2] }
69
- : undefined;
70
- }
71
- return undefined;
72
- }
73
- // Brand assets are fetched over the network and drawn into reports; a url of any other scheme
74
- // (javascript:, data:, a relative path) does not describe an externally hosted asset and is dropped
75
- // rather than reaching an element's src or a @font-face rule.
76
- function sanitizedAssetUrl(value) {
77
- const url = sanitizedString(value);
78
- if (url === undefined) {
79
- return undefined;
80
- }
81
- try {
82
- const { protocol } = new URL(url);
83
- return protocol === "https:" || protocol === "http:" ? url : undefined;
84
- }
85
- catch {
86
- return undefined;
87
- }
88
- }
89
- function sanitizedString(value) {
90
- return typeof value === "string" && value.trim() !== "" ? value : undefined;
91
- }
92
- function withDefined(parts) {
93
- const defined = Object.fromEntries(Object.entries(parts).filter(([, value]) => value !== undefined));
94
- return Object.keys(defined).length > 0 ? defined : undefined;
95
- }
96
- function sanitizedColors(value) {
97
- if (typeof value !== "object" || value === null) {
98
- return undefined;
99
- }
100
- const colors = value;
101
- const chart = Array.isArray(colors.chart)
102
- ? colors.chart
103
- .map(sanitizedString)
104
- .filter((color) => color !== undefined && parseReportsBrandChartColor(color) !== undefined)
105
- : undefined;
106
- return withDefined({
107
- brand: sanitizedString(colors.brand),
108
- chart: chart !== undefined && chart.length > 0 ? chart : undefined,
109
- ink: sanitizedString(colors.ink),
110
- inkMuted: sanitizedString(colors.inkMuted),
111
- paper: sanitizedString(colors.paper),
112
- paperAlt: sanitizedString(colors.paperAlt),
113
- });
114
- }
115
- function sanitizedFontFace(value) {
116
- if (typeof value !== "object" || value === null) {
117
- return undefined;
118
- }
119
- const { family, url, weight, style } = value;
120
- const sanitizedFamily = sanitizedString(family);
121
- const sanitizedUrl = sanitizedAssetUrl(url);
122
- if (sanitizedFamily === undefined || sanitizedUrl === undefined) {
123
- return undefined;
124
- }
125
- return withDefined({
126
- family: sanitizedFamily,
127
- url: sanitizedUrl,
128
- weight: typeof weight === "number" && weight >= 1 && weight <= 1000 ? weight : undefined,
129
- style: style === "normal" || style === "italic" ? style : undefined,
130
- });
131
- }
132
- function sanitizedFonts(value) {
133
- if (!Array.isArray(value)) {
134
- return undefined;
135
- }
136
- const fonts = value
137
- .map(sanitizedFontFace)
138
- .filter((font) => font !== undefined);
139
- return fonts.length > 0 ? fonts : undefined;
140
- }
141
- function sanitizedTypography(value) {
142
- if (typeof value !== "object" || value === null) {
143
- return undefined;
144
- }
145
- const typography = value;
146
- return withDefined({
147
- fontFamily: sanitizedString(typography.fontFamily),
148
- fonts: sanitizedFonts(typography.fonts),
149
- });
150
- }
151
- function sanitizedImages(value) {
152
- if (!Array.isArray(value)) {
153
- return undefined;
154
- }
155
- const seen = new Set();
156
- const images = [];
157
- for (const entry of value) {
158
- if (typeof entry !== "object" || entry === null) {
159
- continue;
160
- }
161
- const { id, url, description } = entry;
162
- if (typeof id !== "string" || !imageIdPattern.test(id) || seen.has(id)) {
163
- continue;
164
- }
165
- const sanitizedUrl = sanitizedAssetUrl(url);
166
- if (sanitizedUrl === undefined) {
167
- continue;
168
- }
169
- seen.add(id);
170
- images.push(withDefined({ id, url: sanitizedUrl, description: sanitizedString(description) }));
171
- }
172
- return images.length > 0 ? images : undefined;
173
- }
174
- function sanitizedAssets(value) {
175
- if (typeof value !== "object" || value === null) {
176
- return undefined;
177
- }
178
- const assets = value;
179
- return withDefined({
180
- logo: sanitizedAssetUrl(assets.logo),
181
- logoInverse: sanitizedAssetUrl(assets.logoInverse),
182
- images: sanitizedImages(assets.images),
183
- });
184
- }
185
- /**
186
- * Reads a stored brand kit from free-form JSON, keeping the parts that are valid and dropping
187
- * everything else.
188
- *
189
- * @remarks
190
- * The setting content is not schema-validated by the backend, so every consumer must go
191
- * through this. Returns undefined only when the value is not a version "1" brand kit at all;
192
- * a kit whose sections are absent or entirely invalid comes back empty, which the type permits
193
- * and a workspace that has not filled its kit in yet carries.
194
- *
195
- * @alpha
196
- */
197
- export function sanitizeReportsBrandKit(value) {
198
- if (typeof value !== "object" || value?.version !== "1") {
199
- return undefined;
200
- }
201
- const kit = value;
202
- const parts = withDefined({
203
- colors: sanitizedColors(kit.colors),
204
- typography: sanitizedTypography(kit.typography),
205
- assets: sanitizedAssets(kit.assets),
206
- });
207
- return { version: "1", ...parts };
208
- }