slackblock 1.1.0 → 2.0.0-beta.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.
package/dist/index.mjs CHANGED
@@ -1,13 +1,55 @@
1
- // src/utils/validation.ts
2
- var warn = (message) => {
3
- console.warn(message);
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/errors.ts
6
+ var SlackblockValidationError = class extends Error {
7
+ constructor(message, path, rule) {
8
+ super(`${path}: ${message}`);
9
+ __publicField(this, "path");
10
+ __publicField(this, "rule");
11
+ this.name = "SlackblockValidationError";
12
+ this.path = path;
13
+ this.rule = rule;
14
+ }
15
+ };
16
+
17
+ // src/utils/validation-context.ts
18
+ var context = {
19
+ mode: "warn",
20
+ path: []
4
21
  };
22
+ var initContext = (mode) => {
23
+ context.mode = mode;
24
+ context.path = [];
25
+ };
26
+ var pushPath = (segment) => {
27
+ context.path.push(segment);
28
+ };
29
+ var popPath = () => {
30
+ context.path.pop();
31
+ };
32
+ var getPath = () => context.path.join(" > ");
33
+ var report = (message, rule) => {
34
+ if (context.mode === "off") {
35
+ return;
36
+ }
37
+ const path = getPath();
38
+ if (context.mode === "warn") {
39
+ console.warn(`[slackblock] ${path}: ${message}`);
40
+ return;
41
+ }
42
+ throw new SlackblockValidationError(message, path, rule);
43
+ };
44
+
45
+ // src/utils/validation.ts
46
+ var toKebab = (name) => name.replaceAll(/([A-Z])/g, "-$1").toLowerCase();
5
47
  var warnIfTooLong = (name, value, max) => {
6
48
  if (!value) {
7
49
  return;
8
50
  }
9
51
  if (value.length > max) {
10
- warn(`${name} exceeds ${max} characters.`);
52
+ report(`${name} exceeds ${max} characters.`, "value-too-long");
11
53
  }
12
54
  };
13
55
  var warnIfTooMany = (name, values, max) => {
@@ -15,20 +57,18 @@ var warnIfTooMany = (name, values, max) => {
15
57
  return;
16
58
  }
17
59
  if (values.length > max) {
18
- warn(`${name} exceeds ${max} items.`);
60
+ report(`${name} exceeds ${max} items.`, "too-many-items");
61
+ }
62
+ };
63
+ var requireField = (fieldName, value) => {
64
+ if (value === void 0 || value === null || value === "") {
65
+ report(`${fieldName} is required.`, `${toKebab(fieldName)}-required`);
19
66
  }
20
67
  };
21
68
 
22
69
  // src/transformers/block/text.ts
23
70
  var transformText = (element) => {
24
- const {
25
- props: {
26
- plainText,
27
- children,
28
- emoji,
29
- verbatim
30
- }
31
- } = element;
71
+ const { plainText, children, emoji, verbatim } = element.props;
32
72
  const res = {
33
73
  type: plainText ? "plain_text" : "mrkdwn",
34
74
  text: children
@@ -46,11 +86,9 @@ var transformText = (element) => {
46
86
  };
47
87
  var text_default = transformText;
48
88
 
49
- // src/transformers/block/confirmation.tsx
50
- import React2 from "react";
51
-
52
89
  // src/utils/get-type.ts
53
90
  var getType = (element) => {
91
+ var _a, _b;
54
92
  if (typeof element === "string") {
55
93
  return "string";
56
94
  }
@@ -65,7 +103,7 @@ var getType = (element) => {
65
103
  return type;
66
104
  }
67
105
  const { slackType, displayName, name } = type;
68
- return slackType || displayName || name || type;
106
+ return (_b = (_a = slackType != null ? slackType : displayName) != null ? _a : name) != null ? _b : type;
69
107
  };
70
108
  var get_type_default = getType;
71
109
 
@@ -77,42 +115,87 @@ var registry_default = Transformers;
77
115
  var transform = (element) => {
78
116
  const type = get_type_default(element);
79
117
  if (!registry_default[type]) {
80
- throw new Error(`No transformer exists for type '${type}'`);
118
+ report(`No transformer for component type '${type}'.`, "unknown-type");
119
+ return {};
120
+ }
121
+ pushPath(type);
122
+ try {
123
+ return registry_default[type](element);
124
+ } finally {
125
+ popPath();
81
126
  }
82
- return registry_default[type](element);
83
127
  };
84
128
 
85
129
  // src/components/block/text.tsx
86
- import React from "react";
87
- var Text = class extends React.Component {
130
+ var Text = class {
88
131
  };
89
- Text.slackType = "Text";
132
+ __publicField(Text, "slackType", "Text");
133
+
134
+ // src/constants/limits.ts
135
+ var MAX_BLOCKS = 50;
136
+ var MAX_HEADER_TEXT = 150;
137
+ var MAX_SECTION_FIELDS = 10;
138
+ var MAX_SECTION_FIELD_TEXT = 2e3;
139
+ var MAX_ACTIONS_ELEMENTS = 25;
140
+ var MAX_CONTEXT_ELEMENTS = 10;
141
+ var MAX_CONFIRM_TITLE = 100;
142
+ var MAX_CONFIRM_TEXT = 300;
143
+ var MAX_BUTTON_TEXT = 75;
144
+ var MAX_BUTTON_VALUE = 2e3;
145
+ var MAX_OPTION_TEXT = 75;
146
+ var MAX_OPTION_VALUE = 150;
147
+ var MAX_OPTION_DESCRIPTION = 75;
148
+ var MAX_OPTION_URL = 3e3;
149
+ var MAX_OPTION_GROUP_LABEL = 75;
150
+ var MAX_OPTION_GROUP_OPTIONS = 100;
151
+ var MAX_IMAGE_URL = 3e3;
152
+ var MAX_IMAGE_ALT_TEXT = 2e3;
153
+ var MAX_IMAGE_TITLE = 2e3;
154
+ var MAX_VIDEO_DESCRIPTION = 200;
155
+ var MAX_BLOCK_ID_LENGTH = 255;
156
+ var MAX_MESSAGE_TEXT = 4e4;
157
+ var RECOMMENDED_MESSAGE_TEXT = 4e3;
158
+ var MAX_ACTION_ID_LENGTH = 255;
159
+ var MAX_PLACEHOLDER_LENGTH = 150;
160
+
161
+ // src/jsx-runtime.ts
162
+ function jsx(type, props) {
163
+ const { children } = props;
164
+ return {
165
+ type,
166
+ props,
167
+ children: Array.isArray(children) ? children : children === void 0 ? [] : [children]
168
+ };
169
+ }
90
170
 
91
171
  // src/transformers/block/confirmation.tsx
92
172
  var transformConfirmation = (child) => {
93
173
  const { title, confirm, deny, children } = child.props;
174
+ warnIfTooLong("Confirm title", title, MAX_CONFIRM_TITLE);
175
+ const text = transform(children);
176
+ warnIfTooLong("Confirm text", text.text, MAX_CONFIRM_TEXT);
94
177
  const res = {
95
- title: transform(/* @__PURE__ */ React2.createElement(Text, { plainText: true }, title)),
96
- text: transform(children),
97
- confirm: transform(/* @__PURE__ */ React2.createElement(Text, { plainText: true }, confirm)),
98
- deny: transform(/* @__PURE__ */ React2.createElement(Text, { plainText: true }, deny))
178
+ title: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title })),
179
+ text,
180
+ confirm: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: confirm })),
181
+ deny: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: deny }))
99
182
  };
100
183
  return res;
101
184
  };
102
185
  var confirmation_default = transformConfirmation;
103
186
 
104
187
  // src/transformers/block/button.tsx
105
- import React3 from "react";
106
188
  var transformButton = (child) => {
107
189
  const { actionId, children, url, value, style, confirm, accessibilityLabel } = child.props;
108
- warnIfTooLong("Button action_id", actionId, 255);
190
+ requireField("actionId", actionId);
191
+ warnIfTooLong("Button action_id", actionId, MAX_ACTION_ID_LENGTH);
109
192
  if (typeof children === "string") {
110
- warnIfTooLong("Button text", children, 75);
193
+ warnIfTooLong("Button text", children, MAX_BUTTON_TEXT);
111
194
  }
112
- warnIfTooLong("Button value", value, 2e3);
195
+ warnIfTooLong("Button value", value, MAX_BUTTON_VALUE);
113
196
  const res = {
114
197
  type: "button",
115
- text: transform(/* @__PURE__ */ React3.createElement(Text, { plainText: true }, children)),
198
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children })),
116
199
  action_id: actionId
117
200
  };
118
201
  if (url) {
@@ -174,15 +257,8 @@ var container_default = transformContainer;
174
257
 
175
258
  // src/transformers/layout/section.ts
176
259
  var transformSection = (element) => {
177
- const {
178
- props: {
179
- text,
180
- blockId,
181
- children,
182
- accessory
183
- }
184
- } = element;
185
- warnIfTooLong("block_id", blockId, 255);
260
+ const { text, blockId, children, accessory } = element.props;
261
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
186
262
  const res = {
187
263
  type: "section",
188
264
  text: transform(text)
@@ -202,10 +278,11 @@ var transformSection = (element) => {
202
278
  for (const field of fields) {
203
279
  if (field) {
204
280
  const t = transform(field);
281
+ warnIfTooLong("Section field text", t.text, MAX_SECTION_FIELD_TEXT);
205
282
  res.fields.push(t);
206
283
  }
207
284
  }
208
- warnIfTooMany("Section fields", res.fields, 10);
285
+ warnIfTooMany("Section fields", res.fields, MAX_SECTION_FIELDS);
209
286
  }
210
287
  return res;
211
288
  };
@@ -214,7 +291,7 @@ var section_default = transformSection;
214
291
  // src/transformers/layout/actions.ts
215
292
  var transformActions = (child) => {
216
293
  const { children, blockId } = child.props;
217
- warnIfTooLong("block_id", blockId, 255);
294
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
218
295
  let elements = children;
219
296
  if (!Array.isArray(elements)) {
220
297
  elements = [elements];
@@ -226,7 +303,7 @@ var transformActions = (child) => {
226
303
  if (blockId) {
227
304
  res.block_id = blockId;
228
305
  }
229
- warnIfTooMany("Actions elements", res.elements, 25);
306
+ warnIfTooMany("Actions elements", res.elements, MAX_ACTIONS_ELEMENTS);
230
307
  return res;
231
308
  };
232
309
  var actions_default = transformActions;
@@ -234,7 +311,7 @@ var actions_default = transformActions;
234
311
  // src/transformers/layout/context.ts
235
312
  var transformContext = (child) => {
236
313
  const { children, blockId } = child.props;
237
- warnIfTooLong("block_id", blockId, 255);
314
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
238
315
  let elements = children;
239
316
  if (!Array.isArray(elements)) {
240
317
  elements = [elements];
@@ -246,7 +323,7 @@ var transformContext = (child) => {
246
323
  if (blockId) {
247
324
  res.block_id = blockId;
248
325
  }
249
- warnIfTooMany("Context elements", res.elements, 10);
326
+ warnIfTooMany("Context elements", res.elements, MAX_CONTEXT_ELEMENTS);
250
327
  return res;
251
328
  };
252
329
  var context_default = transformContext;
@@ -280,13 +357,14 @@ var transformFile = (child) => {
280
357
  var file_default = transformFile;
281
358
 
282
359
  // src/transformers/layout/header.tsx
283
- import React4 from "react";
284
360
  var transformHeader = (child) => {
285
361
  const { text, blockId, emoji } = child.props;
286
- warnIfTooLong("block_id", blockId, 255);
362
+ requireField("text", text);
363
+ warnIfTooLong("Header text", text, MAX_HEADER_TEXT);
364
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
287
365
  const res = {
288
366
  type: "header",
289
- text: transform(/* @__PURE__ */ React4.createElement(Text, { plainText: true, emoji }, text))
367
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, emoji, children: text }))
290
368
  };
291
369
  if (blockId) {
292
370
  res.block_id = blockId;
@@ -296,17 +374,19 @@ var transformHeader = (child) => {
296
374
  var header_default = transformHeader;
297
375
 
298
376
  // src/transformers/layout/image.tsx
299
- import React5 from "react";
300
377
  var transformImageLayout = (child) => {
301
378
  const { url, alt, title, blockId } = child.props;
302
- warnIfTooLong("block_id", blockId, 255);
379
+ warnIfTooLong("Image image_url", url, MAX_IMAGE_URL);
380
+ warnIfTooLong("Image alt_text", alt, MAX_IMAGE_ALT_TEXT);
381
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
303
382
  const res = {
304
383
  type: "image",
305
384
  image_url: url,
306
385
  alt_text: alt
307
386
  };
308
387
  if (title) {
309
- res.title = transform(/* @__PURE__ */ React5.createElement(Text, { plainText: true }, title));
388
+ warnIfTooLong("Image title", title, MAX_IMAGE_TITLE);
389
+ res.title = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title }));
310
390
  }
311
391
  if (blockId) {
312
392
  res.block_id = blockId;
@@ -316,17 +396,16 @@ var transformImageLayout = (child) => {
316
396
  var image_default2 = transformImageLayout;
317
397
 
318
398
  // src/transformers/layout/input.tsx
319
- import React6 from "react";
320
399
  var transformInput = (child) => {
321
400
  const { label, element, hint, optional, blockId } = child.props;
322
401
  warnIfTooLong("block_id", blockId, 255);
323
402
  const res = {
324
403
  type: "input",
325
- label: transform(/* @__PURE__ */ React6.createElement(Text, { plainText: true }, label)),
404
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
326
405
  element: transform(element)
327
406
  };
328
407
  if (hint) {
329
- res.hint = transform(/* @__PURE__ */ React6.createElement(Text, { plainText: true }, hint));
408
+ res.hint = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: hint }));
330
409
  }
331
410
  if (optional) {
332
411
  res.optional = true;
@@ -393,7 +472,6 @@ var transformRichText = (child) => {
393
472
  var rich_text_default = transformRichText;
394
473
 
395
474
  // src/transformers/layout/video.tsx
396
- import React7 from "react";
397
475
  var transformVideo = (child) => {
398
476
  const {
399
477
  title,
@@ -407,10 +485,10 @@ var transformVideo = (child) => {
407
485
  providerIconUrl,
408
486
  blockId
409
487
  } = child.props;
410
- warnIfTooLong("block_id", blockId, 255);
488
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
411
489
  const res = {
412
490
  type: "video",
413
- title: transform(/* @__PURE__ */ React7.createElement(Text, { plainText: true }, title)),
491
+ title: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title })),
414
492
  video_url: videoUrl,
415
493
  thumbnail_url: thumbnailUrl,
416
494
  alt_text: altText
@@ -419,7 +497,8 @@ var transformVideo = (child) => {
419
497
  res.title_url = titleUrl;
420
498
  }
421
499
  if (description) {
422
- res.description = transform(/* @__PURE__ */ React7.createElement(Text, { plainText: true }, description));
500
+ warnIfTooLong("Video description", description, MAX_VIDEO_DESCRIPTION);
501
+ res.description = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: description }));
423
502
  }
424
503
  if (authorName) {
425
504
  res.author_name = authorName;
@@ -438,7 +517,6 @@ var transformVideo = (child) => {
438
517
  var video_default = transformVideo;
439
518
 
440
519
  // src/transformers/input/text.tsx
441
- import React8 from "react";
442
520
  var transformTextInput = (child) => {
443
521
  const {
444
522
  actionId,
@@ -459,7 +537,7 @@ var transformTextInput = (child) => {
459
537
  action_id: actionId
460
538
  };
461
539
  if (placeholder) {
462
- res.placeholder = transform(/* @__PURE__ */ React8.createElement(Text, { plainText: true }, placeholder));
540
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
463
541
  }
464
542
  if (initial) {
465
543
  res.initial_value = initial;
@@ -488,7 +566,8 @@ var text_default2 = transformTextInput;
488
566
  // src/transformers/input/date-time-picker.ts
489
567
  var transformDateTimePicker = (child) => {
490
568
  const { actionId, initialDateTime, confirm, focusOnLoad } = child.props;
491
- warnIfTooLong("DateTimePicker action_id", actionId, 255);
569
+ requireField("actionId", actionId);
570
+ warnIfTooLong("DateTimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
492
571
  const res = {
493
572
  type: "datetimepicker",
494
573
  action_id: actionId
@@ -510,7 +589,6 @@ var transformDateTimePicker = (child) => {
510
589
  var date_time_picker_default = transformDateTimePicker;
511
590
 
512
591
  // src/transformers/input/date-picker.tsx
513
- import React9 from "react";
514
592
  var isValidDateString = (value) => {
515
593
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
516
594
  if (!match) {
@@ -527,20 +605,21 @@ var isValidDateString = (value) => {
527
605
  };
528
606
  var transformDatePicker = (child) => {
529
607
  const { actionId, placeholder, initialDate, confirm, focusOnLoad } = child.props;
530
- warnIfTooLong("DatePicker action_id", actionId, 255);
608
+ requireField("actionId", actionId);
609
+ warnIfTooLong("DatePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
531
610
  if (placeholder) {
532
- warnIfTooLong("DatePicker placeholder", placeholder, 150);
611
+ warnIfTooLong("DatePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
533
612
  }
534
613
  const res = {
535
614
  type: "datepicker",
536
615
  action_id: actionId
537
616
  };
538
617
  if (placeholder) {
539
- res.placeholder = transform(/* @__PURE__ */ React9.createElement(Text, { plainText: true }, placeholder));
618
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
540
619
  }
541
620
  if (initialDate) {
542
621
  if (!isValidDateString(initialDate)) {
543
- throw new Error("Date must be valid and in format YYYY-MM-DD.");
622
+ report("Date must be valid and in format YYYY-MM-DD.", "invalid-date-format");
544
623
  }
545
624
  res.initial_date = initialDate;
546
625
  }
@@ -557,7 +636,8 @@ var date_picker_default = transformDatePicker;
557
636
  // src/transformers/input/checkboxes.ts
558
637
  var transformCheckboxes = (child) => {
559
638
  const { actionId, children, initialOptions, confirm, focusOnLoad } = child.props;
560
- warnIfTooLong("Checkboxes action_id", actionId, 255);
639
+ requireField("actionId", actionId);
640
+ warnIfTooLong("Checkboxes action_id", actionId, MAX_ACTION_ID_LENGTH);
561
641
  let elements = children;
562
642
  if (!Array.isArray(elements)) {
563
643
  elements = [elements];
@@ -580,11 +660,7 @@ var transformCheckboxes = (child) => {
580
660
  };
581
661
  var checkboxes_default = transformCheckboxes;
582
662
 
583
- // src/transformers/input/select.tsx
584
- import React11 from "react";
585
-
586
663
  // src/components/input/select.tsx
587
- import React10 from "react";
588
664
  var selectTypes = {
589
665
  STATIC: "static",
590
666
  EXTERNAL: "external",
@@ -592,9 +668,6 @@ var selectTypes = {
592
668
  CONVERSATION: "conversation",
593
669
  CHANNEL: "channel"
594
670
  };
595
- var Select = class extends React10.Component {
596
- };
597
- Select.slackType = "Select";
598
671
 
599
672
  // src/transformers/input/select.tsx
600
673
  var OPTION = "Option";
@@ -624,11 +697,9 @@ var assignStaticOptions = (elements, result) => {
624
697
  throw new TypeError("Only allowed types are Option OR OptionGroup");
625
698
  }
626
699
  if (elementType === OPTION) {
627
- const options = elements;
628
- result.options = options.map((element) => transform(element));
700
+ result.options = elements.map((element) => transform(element));
629
701
  } else if (elementType === OPTION_GROUP) {
630
- const optionGroups = elements;
631
- result.option_groups = optionGroups.map((element) => transform(element));
702
+ result.option_groups = elements.map((element) => transform(element));
632
703
  }
633
704
  };
634
705
  var applyInitialSelections = (type, isMulti, result, initialValues) => {
@@ -699,11 +770,13 @@ var transformSelect = (child) => {
699
770
  } = child.props;
700
771
  const type = typeProperty != null ? typeProperty : selectTypes.STATIC;
701
772
  const typeString = `${multi ? MULTI_PREFIX : ""}${types[type]}`;
702
- warnIfTooLong("Select action_id", actionId, 255);
703
- warnIfTooLong("Select placeholder", placeholder, 150);
773
+ requireField("actionId", actionId);
774
+ requireField("placeholder", placeholder);
775
+ warnIfTooLong("Select action_id", actionId, MAX_ACTION_ID_LENGTH);
776
+ warnIfTooLong("Select placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
704
777
  const result = {
705
778
  type: typeString,
706
- placeholder: transform(/* @__PURE__ */ React11.createElement(Text, { plainText: true }, placeholder)),
779
+ placeholder: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder })),
707
780
  action_id: actionId
708
781
  };
709
782
  const elements = normalizeElements(children);
@@ -756,18 +829,19 @@ var transformSelect = (child) => {
756
829
  var select_default = transformSelect;
757
830
 
758
831
  // src/transformers/input/option.tsx
759
- import React12 from "react";
760
832
  var transformOption = (child) => {
761
833
  const { children: text, value, url, description } = child.props;
762
- warnIfTooLong("Option text", text, 75);
763
- warnIfTooLong("Option value", value, 75);
764
- warnIfTooLong("Option description", description, 75);
834
+ requireField("value", value);
835
+ warnIfTooLong("Option text", text, MAX_OPTION_TEXT);
836
+ warnIfTooLong("Option value", value, MAX_OPTION_VALUE);
837
+ warnIfTooLong("Option description", description, MAX_OPTION_DESCRIPTION);
838
+ warnIfTooLong("Option url", url, MAX_OPTION_URL);
765
839
  const res = {
766
- text: transform(/* @__PURE__ */ React12.createElement(Text, { plainText: true }, text)),
840
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: text })),
767
841
  value
768
842
  };
769
843
  if (description) {
770
- res.description = transform(/* @__PURE__ */ React12.createElement(Text, { plainText: true }, description));
844
+ res.description = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: description }));
771
845
  }
772
846
  if (url) {
773
847
  res.url = url;
@@ -777,16 +851,16 @@ var transformOption = (child) => {
777
851
  var option_default = transformOption;
778
852
 
779
853
  // src/transformers/input/option-group.tsx
780
- import React13 from "react";
781
854
  var transformOptionGroup = (child) => {
782
855
  const { label, children } = child.props;
783
- warnIfTooLong("OptionGroup label", label, 75);
856
+ warnIfTooLong("OptionGroup label", label, MAX_OPTION_GROUP_LABEL);
784
857
  let options = children;
785
858
  if (!Array.isArray(options)) {
786
859
  options = [options];
787
860
  }
861
+ warnIfTooMany("OptionGroup options", options, MAX_OPTION_GROUP_OPTIONS);
788
862
  return {
789
- label: transform(/* @__PURE__ */ React13.createElement(Text, { plainText: true }, label)),
863
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
790
864
  options: options.map((option) => transform(option))
791
865
  };
792
866
  };
@@ -815,7 +889,8 @@ var overflow_default = transformOverflow;
815
889
  // src/transformers/input/radio-group.ts
816
890
  var transformRadioGroup = (child) => {
817
891
  const { actionId, children, initialOption, confirm, focusOnLoad } = child.props;
818
- warnIfTooLong("RadioGroup action_id", actionId, 255);
892
+ requireField("actionId", actionId);
893
+ warnIfTooLong("RadioGroup action_id", actionId, MAX_ACTION_ID_LENGTH);
819
894
  let elements = children;
820
895
  if (!Array.isArray(elements)) {
821
896
  elements = [elements];
@@ -839,7 +914,6 @@ var transformRadioGroup = (child) => {
839
914
  var radio_group_default = transformRadioGroup;
840
915
 
841
916
  // src/transformers/input/time-picker.tsx
842
- import React14 from "react";
843
917
  var isValidTimeString = (value) => {
844
918
  const match = /^(\d{2}):(\d{2})$/.exec(value);
845
919
  if (!match) {
@@ -851,20 +925,21 @@ var isValidTimeString = (value) => {
851
925
  };
852
926
  var transformTimePicker = (child) => {
853
927
  const { actionId, placeholder, initialTime, confirm, focusOnLoad } = child.props;
854
- warnIfTooLong("TimePicker action_id", actionId, 255);
928
+ requireField("actionId", actionId);
929
+ warnIfTooLong("TimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
855
930
  if (placeholder) {
856
- warnIfTooLong("TimePicker placeholder", placeholder, 150);
931
+ warnIfTooLong("TimePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
857
932
  }
858
933
  const res = {
859
934
  type: "timepicker",
860
935
  action_id: actionId
861
936
  };
862
937
  if (placeholder) {
863
- res.placeholder = transform(/* @__PURE__ */ React14.createElement(Text, { plainText: true }, placeholder));
938
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
864
939
  }
865
940
  if (initialTime) {
866
941
  if (!isValidTimeString(initialTime)) {
867
- throw new Error("Time must be valid and in format HH:MM.");
942
+ report("Time must be valid and in format HH:MM.", "invalid-time-format");
868
943
  }
869
944
  res.initial_time = initialTime;
870
945
  }
@@ -989,17 +1064,13 @@ var emoji_default = transformRichTextEmoji;
989
1064
 
990
1065
  // src/transformers/rich-text/date.ts
991
1066
  var transformRichTextDate = (child) => {
992
- const { timestamp, format, fallback, link } = child.props;
993
- const res = {
1067
+ const { timestamp, format, fallback } = child.props;
1068
+ return {
994
1069
  type: "date",
995
1070
  timestamp,
996
1071
  format,
997
1072
  fallback
998
1073
  };
999
- if (link) {
1000
- res.link = link;
1001
- }
1002
- return res;
1003
1074
  };
1004
1075
  var date_default = transformRichTextDate;
1005
1076
 
@@ -1087,9 +1158,14 @@ var parseChildren = (children) => {
1087
1158
  const type = get_type_default(child);
1088
1159
  const transformer = registry_default[type];
1089
1160
  if (transformer) {
1090
- appendTransformed(transformer(child), transformedBlocks);
1161
+ pushPath(type);
1162
+ try {
1163
+ appendTransformed(transformer(child), transformedBlocks);
1164
+ } finally {
1165
+ popPath();
1166
+ }
1091
1167
  } else if (type !== "null") {
1092
- console.warn(`No transformer for child type '${type}' exists and will be ignored.`);
1168
+ report(`No transformer for component type '${type}'.`, "unknown-type");
1093
1169
  }
1094
1170
  }
1095
1171
  if (transformedBlocks.length === 0) {
@@ -1100,23 +1176,14 @@ var parseChildren = (children) => {
1100
1176
  var parser_default = parseChildren;
1101
1177
 
1102
1178
  // src/renderer/index.ts
1103
- var render = (element) => {
1104
- const { props: properties = {} } = element || {};
1105
- const typeName = get_type_default(element);
1106
- if (typeName !== "Message") {
1107
- throw new TypeError("Provided top-level element must be a Message type.");
1108
- }
1109
- if (!properties.children) {
1110
- throw new Error("Cannot render a Message with no children.");
1111
- }
1112
- const json = { ...parser_default(properties.children) };
1113
- if (properties.replyTo) {
1114
- json.thread_ts = properties.replyTo;
1115
- }
1116
- if (properties.markdown !== void 0) {
1117
- json.mrkdwn = properties.markdown;
1118
- }
1119
- json.text = properties.text || "";
1179
+ var renderToBlocks = (element, options) => {
1180
+ var _a, _b;
1181
+ initContext((_a = options == null ? void 0 : options.validate) != null ? _a : "warn");
1182
+ const child = typeof element === "object" && element !== null && !Array.isArray(element) && element.type === "fragment" ? element.props.children : element;
1183
+ const result = parser_default(child);
1184
+ return (_b = result.blocks) != null ? _b : [];
1185
+ };
1186
+ var applyMessageMetadata = (json, properties) => {
1120
1187
  if (properties.iconEmoji) {
1121
1188
  json.icon_emoji = properties.iconEmoji;
1122
1189
  }
@@ -1141,23 +1208,66 @@ var render = (element) => {
1141
1208
  if (properties.unfurlMedia !== void 0) {
1142
1209
  json.unfurl_media = properties.unfurlMedia;
1143
1210
  }
1144
- if (properties.color && json.blocks) {
1145
- json.attachments = [
1146
- {
1147
- fallback: json.text,
1148
- color: properties.color,
1149
- blocks: json.blocks
1150
- }
1151
- ];
1152
- delete json.blocks;
1211
+ };
1212
+ var render = (element, options) => {
1213
+ var _a, _b;
1214
+ initContext((_a = options == null ? void 0 : options.validate) != null ? _a : "warn");
1215
+ const properties = element.props;
1216
+ const typeName = get_type_default(element);
1217
+ if (typeName !== "Message") {
1218
+ throw new TypeError("Provided top-level element must be a Message type.");
1153
1219
  }
1154
- if (json.blocks) {
1155
- warnIfTooMany("Message blocks", json.blocks, 50);
1220
+ if (!properties.children) {
1221
+ throw new Error("Cannot render a Message with no children.");
1222
+ }
1223
+ pushPath("Message");
1224
+ let json;
1225
+ try {
1226
+ json = { ...parser_default(properties.children) };
1227
+ if (properties.replyTo) {
1228
+ json.thread_ts = properties.replyTo;
1229
+ }
1230
+ if (properties.markdown !== void 0) {
1231
+ json.mrkdwn = properties.markdown;
1232
+ }
1233
+ json.text = (_b = properties.text) != null ? _b : "";
1234
+ if (properties.text && properties.text.length > MAX_MESSAGE_TEXT) {
1235
+ warnIfTooLong(`Message text (Slack will truncate beyond ${MAX_MESSAGE_TEXT} chars)`, properties.text, MAX_MESSAGE_TEXT);
1236
+ } else if (properties.text) {
1237
+ warnIfTooLong("Message text (recommended max for best results)", properties.text, RECOMMENDED_MESSAGE_TEXT);
1238
+ }
1239
+ applyMessageMetadata(json, properties);
1240
+ if (properties.color && json.blocks) {
1241
+ json.attachments = [
1242
+ {
1243
+ fallback: json.text,
1244
+ color: properties.color,
1245
+ blocks: json.blocks
1246
+ }
1247
+ ];
1248
+ delete json.blocks;
1249
+ }
1250
+ if (json.blocks) {
1251
+ warnIfTooMany("Message blocks", json.blocks, MAX_BLOCKS);
1252
+ }
1253
+ } finally {
1254
+ popPath();
1156
1255
  }
1157
1256
  return json;
1158
1257
  };
1159
1258
  var renderer_default = render;
1259
+
1260
+ // src/utils/escape-mrkdwn.ts
1261
+ var escapeMrkdwn = (text) => text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll(/[*_~`]/g, "\u200B$&");
1262
+
1263
+ // src/utils/block-kit-builder.ts
1264
+ var blockKitBuilderUrl = (blocks) => `https://app.slack.com/block-kit-builder#${JSON.stringify({ blocks })}`;
1160
1265
  export {
1161
- renderer_default as default
1266
+ SlackblockValidationError,
1267
+ blockKitBuilderUrl,
1268
+ renderer_default as default,
1269
+ escapeMrkdwn,
1270
+ renderToBlocks,
1271
+ render as renderToMessage
1162
1272
  };
1163
1273
  //# sourceMappingURL=index.mjs.map