slackblock 1.0.1 → 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,33 +1,55 @@
1
- // src/utils/get-type.ts
2
- var getType = (element) => {
3
- if (typeof element === "string") {
4
- return "string";
5
- }
6
- if (element === null || element === void 0 || typeof element === "boolean") {
7
- return "null";
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;
8
14
  }
9
- if (Array.isArray(element)) {
10
- throw new TypeError("Cannot type arrays");
15
+ };
16
+
17
+ // src/utils/validation-context.ts
18
+ var context = {
19
+ mode: "warn",
20
+ path: []
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;
11
36
  }
12
- const { type } = element;
13
- if (typeof type === "string") {
14
- return type;
37
+ const path = getPath();
38
+ if (context.mode === "warn") {
39
+ console.warn(`[slackblock] ${path}: ${message}`);
40
+ return;
15
41
  }
16
- const { slackType, displayName, name } = type;
17
- return slackType || displayName || name || type;
42
+ throw new SlackblockValidationError(message, path, rule);
18
43
  };
19
- var get_type_default = getType;
20
44
 
21
45
  // src/utils/validation.ts
22
- var warn = (message) => {
23
- console.warn(message);
24
- };
46
+ var toKebab = (name) => name.replaceAll(/([A-Z])/g, "-$1").toLowerCase();
25
47
  var warnIfTooLong = (name, value, max) => {
26
48
  if (!value) {
27
49
  return;
28
50
  }
29
51
  if (value.length > max) {
30
- warn(`${name} exceeds ${max} characters.`);
52
+ report(`${name} exceeds ${max} characters.`, "value-too-long");
31
53
  }
32
54
  };
33
55
  var warnIfTooMany = (name, values, max) => {
@@ -35,20 +57,18 @@ var warnIfTooMany = (name, values, max) => {
35
57
  return;
36
58
  }
37
59
  if (values.length > max) {
38
- 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`);
39
66
  }
40
67
  };
41
68
 
42
69
  // src/transformers/block/text.ts
43
70
  var transformText = (element) => {
44
- const {
45
- props: {
46
- plainText,
47
- children,
48
- emoji,
49
- verbatim
50
- }
51
- } = element;
71
+ const { plainText, children, emoji, verbatim } = element.props;
52
72
  const res = {
53
73
  type: plainText ? "plain_text" : "mrkdwn",
54
74
  text: children
@@ -66,40 +86,116 @@ var transformText = (element) => {
66
86
  };
67
87
  var text_default = transformText;
68
88
 
69
- // src/transformers/block/confirmation.tsx
70
- import React2 from "react";
89
+ // src/utils/get-type.ts
90
+ var getType = (element) => {
91
+ var _a, _b;
92
+ if (typeof element === "string") {
93
+ return "string";
94
+ }
95
+ if (element === null || element === void 0 || typeof element === "boolean") {
96
+ return "null";
97
+ }
98
+ if (Array.isArray(element)) {
99
+ throw new TypeError("Cannot type arrays");
100
+ }
101
+ const { type } = element;
102
+ if (typeof type === "string") {
103
+ return type;
104
+ }
105
+ const { slackType, displayName, name } = type;
106
+ return (_b = (_a = slackType != null ? slackType : displayName) != null ? _a : name) != null ? _b : type;
107
+ };
108
+ var get_type_default = getType;
109
+
110
+ // src/transformers/registry.ts
111
+ var Transformers = {};
112
+ var registry_default = Transformers;
113
+
114
+ // src/transformers/transform.ts
115
+ var transform = (element) => {
116
+ const type = get_type_default(element);
117
+ if (!registry_default[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();
126
+ }
127
+ };
71
128
 
72
129
  // src/components/block/text.tsx
73
- import React from "react";
74
- var Text = class extends React.Component {
130
+ var Text = class {
75
131
  };
76
- 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
+ }
77
170
 
78
171
  // src/transformers/block/confirmation.tsx
79
172
  var transformConfirmation = (child) => {
80
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);
81
177
  const res = {
82
- title: transform(/* @__PURE__ */ React2.createElement(Text, { plainText: true }, title)),
83
- text: transform(children),
84
- confirm: transform(/* @__PURE__ */ React2.createElement(Text, { plainText: true }, confirm)),
85
- 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 }))
86
182
  };
87
183
  return res;
88
184
  };
89
185
  var confirmation_default = transformConfirmation;
90
186
 
91
187
  // src/transformers/block/button.tsx
92
- import React3 from "react";
93
188
  var transformButton = (child) => {
94
189
  const { actionId, children, url, value, style, confirm, accessibilityLabel } = child.props;
95
- warnIfTooLong("Button action_id", actionId, 255);
190
+ requireField("actionId", actionId);
191
+ warnIfTooLong("Button action_id", actionId, MAX_ACTION_ID_LENGTH);
96
192
  if (typeof children === "string") {
97
- warnIfTooLong("Button text", children, 75);
193
+ warnIfTooLong("Button text", children, MAX_BUTTON_TEXT);
98
194
  }
99
- warnIfTooLong("Button value", value, 2e3);
195
+ warnIfTooLong("Button value", value, MAX_BUTTON_VALUE);
100
196
  const res = {
101
197
  type: "button",
102
- text: transform(/* @__PURE__ */ React3.createElement(Text, { plainText: true }, children)),
198
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children })),
103
199
  action_id: actionId
104
200
  };
105
201
  if (url) {
@@ -132,7 +228,7 @@ var transformImage = (child) => {
132
228
  };
133
229
  var image_default = transformImage;
134
230
 
135
- // src/transformers/layout/container.ts
231
+ // src/utils/normalize-children.ts
136
232
  var normalizeChildren = (children) => {
137
233
  const result = [];
138
234
  const stack = Array.isArray(children) ? [...children] : [children];
@@ -149,24 +245,20 @@ var normalizeChildren = (children) => {
149
245
  }
150
246
  return result;
151
247
  };
248
+ var normalize_children_default = normalizeChildren;
249
+
250
+ // src/transformers/layout/container.ts
152
251
  var transformContainer = (child) => {
153
252
  const { children } = child.props;
154
- const elements = normalizeChildren(children);
253
+ const elements = normalize_children_default(children);
155
254
  return elements.map((element) => transform(element));
156
255
  };
157
256
  var container_default = transformContainer;
158
257
 
159
258
  // src/transformers/layout/section.ts
160
259
  var transformSection = (element) => {
161
- const {
162
- props: {
163
- text,
164
- blockId,
165
- children,
166
- accessory
167
- }
168
- } = element;
169
- warnIfTooLong("block_id", blockId, 255);
260
+ const { text, blockId, children, accessory } = element.props;
261
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
170
262
  const res = {
171
263
  type: "section",
172
264
  text: transform(text)
@@ -186,10 +278,11 @@ var transformSection = (element) => {
186
278
  for (const field of fields) {
187
279
  if (field) {
188
280
  const t = transform(field);
281
+ warnIfTooLong("Section field text", t.text, MAX_SECTION_FIELD_TEXT);
189
282
  res.fields.push(t);
190
283
  }
191
284
  }
192
- warnIfTooMany("Section fields", res.fields, 10);
285
+ warnIfTooMany("Section fields", res.fields, MAX_SECTION_FIELDS);
193
286
  }
194
287
  return res;
195
288
  };
@@ -198,7 +291,7 @@ var section_default = transformSection;
198
291
  // src/transformers/layout/actions.ts
199
292
  var transformActions = (child) => {
200
293
  const { children, blockId } = child.props;
201
- warnIfTooLong("block_id", blockId, 255);
294
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
202
295
  let elements = children;
203
296
  if (!Array.isArray(elements)) {
204
297
  elements = [elements];
@@ -210,7 +303,7 @@ var transformActions = (child) => {
210
303
  if (blockId) {
211
304
  res.block_id = blockId;
212
305
  }
213
- warnIfTooMany("Actions elements", res.elements, 25);
306
+ warnIfTooMany("Actions elements", res.elements, MAX_ACTIONS_ELEMENTS);
214
307
  return res;
215
308
  };
216
309
  var actions_default = transformActions;
@@ -218,7 +311,7 @@ var actions_default = transformActions;
218
311
  // src/transformers/layout/context.ts
219
312
  var transformContext = (child) => {
220
313
  const { children, blockId } = child.props;
221
- warnIfTooLong("block_id", blockId, 255);
314
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
222
315
  let elements = children;
223
316
  if (!Array.isArray(elements)) {
224
317
  elements = [elements];
@@ -230,7 +323,7 @@ var transformContext = (child) => {
230
323
  if (blockId) {
231
324
  res.block_id = blockId;
232
325
  }
233
- warnIfTooMany("Context elements", res.elements, 10);
326
+ warnIfTooMany("Context elements", res.elements, MAX_CONTEXT_ELEMENTS);
234
327
  return res;
235
328
  };
236
329
  var context_default = transformContext;
@@ -264,13 +357,14 @@ var transformFile = (child) => {
264
357
  var file_default = transformFile;
265
358
 
266
359
  // src/transformers/layout/header.tsx
267
- import React4 from "react";
268
360
  var transformHeader = (child) => {
269
361
  const { text, blockId, emoji } = child.props;
270
- 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);
271
365
  const res = {
272
366
  type: "header",
273
- text: transform(/* @__PURE__ */ React4.createElement(Text, { plainText: true, emoji }, text))
367
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, emoji, children: text }))
274
368
  };
275
369
  if (blockId) {
276
370
  res.block_id = blockId;
@@ -280,17 +374,19 @@ var transformHeader = (child) => {
280
374
  var header_default = transformHeader;
281
375
 
282
376
  // src/transformers/layout/image.tsx
283
- import React5 from "react";
284
377
  var transformImageLayout = (child) => {
285
378
  const { url, alt, title, blockId } = child.props;
286
- 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);
287
382
  const res = {
288
383
  type: "image",
289
384
  image_url: url,
290
385
  alt_text: alt
291
386
  };
292
387
  if (title) {
293
- 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 }));
294
390
  }
295
391
  if (blockId) {
296
392
  res.block_id = blockId;
@@ -300,17 +396,16 @@ var transformImageLayout = (child) => {
300
396
  var image_default2 = transformImageLayout;
301
397
 
302
398
  // src/transformers/layout/input.tsx
303
- import React6 from "react";
304
399
  var transformInput = (child) => {
305
400
  const { label, element, hint, optional, blockId } = child.props;
306
401
  warnIfTooLong("block_id", blockId, 255);
307
402
  const res = {
308
403
  type: "input",
309
- label: transform(/* @__PURE__ */ React6.createElement(Text, { plainText: true }, label)),
404
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
310
405
  element: transform(element)
311
406
  };
312
407
  if (hint) {
313
- res.hint = transform(/* @__PURE__ */ React6.createElement(Text, { plainText: true }, hint));
408
+ res.hint = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: hint }));
314
409
  }
315
410
  if (optional) {
316
411
  res.optional = true;
@@ -377,7 +472,6 @@ var transformRichText = (child) => {
377
472
  var rich_text_default = transformRichText;
378
473
 
379
474
  // src/transformers/layout/video.tsx
380
- import React7 from "react";
381
475
  var transformVideo = (child) => {
382
476
  const {
383
477
  title,
@@ -391,10 +485,10 @@ var transformVideo = (child) => {
391
485
  providerIconUrl,
392
486
  blockId
393
487
  } = child.props;
394
- warnIfTooLong("block_id", blockId, 255);
488
+ warnIfTooLong("block_id", blockId, MAX_BLOCK_ID_LENGTH);
395
489
  const res = {
396
490
  type: "video",
397
- title: transform(/* @__PURE__ */ React7.createElement(Text, { plainText: true }, title)),
491
+ title: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: title })),
398
492
  video_url: videoUrl,
399
493
  thumbnail_url: thumbnailUrl,
400
494
  alt_text: altText
@@ -403,7 +497,8 @@ var transformVideo = (child) => {
403
497
  res.title_url = titleUrl;
404
498
  }
405
499
  if (description) {
406
- 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 }));
407
502
  }
408
503
  if (authorName) {
409
504
  res.author_name = authorName;
@@ -422,7 +517,6 @@ var transformVideo = (child) => {
422
517
  var video_default = transformVideo;
423
518
 
424
519
  // src/transformers/input/text.tsx
425
- import React8 from "react";
426
520
  var transformTextInput = (child) => {
427
521
  const {
428
522
  actionId,
@@ -443,7 +537,7 @@ var transformTextInput = (child) => {
443
537
  action_id: actionId
444
538
  };
445
539
  if (placeholder) {
446
- res.placeholder = transform(/* @__PURE__ */ React8.createElement(Text, { plainText: true }, placeholder));
540
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
447
541
  }
448
542
  if (initial) {
449
543
  res.initial_value = initial;
@@ -472,7 +566,8 @@ var text_default2 = transformTextInput;
472
566
  // src/transformers/input/date-time-picker.ts
473
567
  var transformDateTimePicker = (child) => {
474
568
  const { actionId, initialDateTime, confirm, focusOnLoad } = child.props;
475
- warnIfTooLong("DateTimePicker action_id", actionId, 255);
569
+ requireField("actionId", actionId);
570
+ warnIfTooLong("DateTimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
476
571
  const res = {
477
572
  type: "datetimepicker",
478
573
  action_id: actionId
@@ -494,7 +589,6 @@ var transformDateTimePicker = (child) => {
494
589
  var date_time_picker_default = transformDateTimePicker;
495
590
 
496
591
  // src/transformers/input/date-picker.tsx
497
- import React9 from "react";
498
592
  var isValidDateString = (value) => {
499
593
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
500
594
  if (!match) {
@@ -511,20 +605,21 @@ var isValidDateString = (value) => {
511
605
  };
512
606
  var transformDatePicker = (child) => {
513
607
  const { actionId, placeholder, initialDate, confirm, focusOnLoad } = child.props;
514
- warnIfTooLong("DatePicker action_id", actionId, 255);
608
+ requireField("actionId", actionId);
609
+ warnIfTooLong("DatePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
515
610
  if (placeholder) {
516
- warnIfTooLong("DatePicker placeholder", placeholder, 150);
611
+ warnIfTooLong("DatePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
517
612
  }
518
613
  const res = {
519
614
  type: "datepicker",
520
615
  action_id: actionId
521
616
  };
522
617
  if (placeholder) {
523
- res.placeholder = transform(/* @__PURE__ */ React9.createElement(Text, { plainText: true }, placeholder));
618
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
524
619
  }
525
620
  if (initialDate) {
526
621
  if (!isValidDateString(initialDate)) {
527
- 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");
528
623
  }
529
624
  res.initial_date = initialDate;
530
625
  }
@@ -541,7 +636,8 @@ var date_picker_default = transformDatePicker;
541
636
  // src/transformers/input/checkboxes.ts
542
637
  var transformCheckboxes = (child) => {
543
638
  const { actionId, children, initialOptions, confirm, focusOnLoad } = child.props;
544
- warnIfTooLong("Checkboxes action_id", actionId, 255);
639
+ requireField("actionId", actionId);
640
+ warnIfTooLong("Checkboxes action_id", actionId, MAX_ACTION_ID_LENGTH);
545
641
  let elements = children;
546
642
  if (!Array.isArray(elements)) {
547
643
  elements = [elements];
@@ -564,11 +660,7 @@ var transformCheckboxes = (child) => {
564
660
  };
565
661
  var checkboxes_default = transformCheckboxes;
566
662
 
567
- // src/transformers/input/select.tsx
568
- import React11 from "react";
569
-
570
663
  // src/components/input/select.tsx
571
- import React10 from "react";
572
664
  var selectTypes = {
573
665
  STATIC: "static",
574
666
  EXTERNAL: "external",
@@ -576,9 +668,6 @@ var selectTypes = {
576
668
  CONVERSATION: "conversation",
577
669
  CHANNEL: "channel"
578
670
  };
579
- var Select = class extends React10.Component {
580
- };
581
- Select.slackType = "Select";
582
671
 
583
672
  // src/transformers/input/select.tsx
584
673
  var OPTION = "Option";
@@ -608,11 +697,9 @@ var assignStaticOptions = (elements, result) => {
608
697
  throw new TypeError("Only allowed types are Option OR OptionGroup");
609
698
  }
610
699
  if (elementType === OPTION) {
611
- const options = elements;
612
- result.options = options.map((element) => transform(element));
700
+ result.options = elements.map((element) => transform(element));
613
701
  } else if (elementType === OPTION_GROUP) {
614
- const optionGroups = elements;
615
- result.option_groups = optionGroups.map((element) => transform(element));
702
+ result.option_groups = elements.map((element) => transform(element));
616
703
  }
617
704
  };
618
705
  var applyInitialSelections = (type, isMulti, result, initialValues) => {
@@ -683,11 +770,13 @@ var transformSelect = (child) => {
683
770
  } = child.props;
684
771
  const type = typeProperty != null ? typeProperty : selectTypes.STATIC;
685
772
  const typeString = `${multi ? MULTI_PREFIX : ""}${types[type]}`;
686
- warnIfTooLong("Select action_id", actionId, 255);
687
- 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);
688
777
  const result = {
689
778
  type: typeString,
690
- placeholder: transform(/* @__PURE__ */ React11.createElement(Text, { plainText: true }, placeholder)),
779
+ placeholder: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder })),
691
780
  action_id: actionId
692
781
  };
693
782
  const elements = normalizeElements(children);
@@ -740,18 +829,19 @@ var transformSelect = (child) => {
740
829
  var select_default = transformSelect;
741
830
 
742
831
  // src/transformers/input/option.tsx
743
- import React12 from "react";
744
832
  var transformOption = (child) => {
745
833
  const { children: text, value, url, description } = child.props;
746
- warnIfTooLong("Option text", text, 75);
747
- warnIfTooLong("Option value", value, 75);
748
- 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);
749
839
  const res = {
750
- text: transform(/* @__PURE__ */ React12.createElement(Text, { plainText: true }, text)),
840
+ text: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: text })),
751
841
  value
752
842
  };
753
843
  if (description) {
754
- res.description = transform(/* @__PURE__ */ React12.createElement(Text, { plainText: true }, description));
844
+ res.description = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: description }));
755
845
  }
756
846
  if (url) {
757
847
  res.url = url;
@@ -761,16 +851,16 @@ var transformOption = (child) => {
761
851
  var option_default = transformOption;
762
852
 
763
853
  // src/transformers/input/option-group.tsx
764
- import React13 from "react";
765
854
  var transformOptionGroup = (child) => {
766
855
  const { label, children } = child.props;
767
- warnIfTooLong("OptionGroup label", label, 75);
856
+ warnIfTooLong("OptionGroup label", label, MAX_OPTION_GROUP_LABEL);
768
857
  let options = children;
769
858
  if (!Array.isArray(options)) {
770
859
  options = [options];
771
860
  }
861
+ warnIfTooMany("OptionGroup options", options, MAX_OPTION_GROUP_OPTIONS);
772
862
  return {
773
- label: transform(/* @__PURE__ */ React13.createElement(Text, { plainText: true }, label)),
863
+ label: transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: label })),
774
864
  options: options.map((option) => transform(option))
775
865
  };
776
866
  };
@@ -799,7 +889,8 @@ var overflow_default = transformOverflow;
799
889
  // src/transformers/input/radio-group.ts
800
890
  var transformRadioGroup = (child) => {
801
891
  const { actionId, children, initialOption, confirm, focusOnLoad } = child.props;
802
- warnIfTooLong("RadioGroup action_id", actionId, 255);
892
+ requireField("actionId", actionId);
893
+ warnIfTooLong("RadioGroup action_id", actionId, MAX_ACTION_ID_LENGTH);
803
894
  let elements = children;
804
895
  if (!Array.isArray(elements)) {
805
896
  elements = [elements];
@@ -823,7 +914,6 @@ var transformRadioGroup = (child) => {
823
914
  var radio_group_default = transformRadioGroup;
824
915
 
825
916
  // src/transformers/input/time-picker.tsx
826
- import React14 from "react";
827
917
  var isValidTimeString = (value) => {
828
918
  const match = /^(\d{2}):(\d{2})$/.exec(value);
829
919
  if (!match) {
@@ -835,20 +925,21 @@ var isValidTimeString = (value) => {
835
925
  };
836
926
  var transformTimePicker = (child) => {
837
927
  const { actionId, placeholder, initialTime, confirm, focusOnLoad } = child.props;
838
- warnIfTooLong("TimePicker action_id", actionId, 255);
928
+ requireField("actionId", actionId);
929
+ warnIfTooLong("TimePicker action_id", actionId, MAX_ACTION_ID_LENGTH);
839
930
  if (placeholder) {
840
- warnIfTooLong("TimePicker placeholder", placeholder, 150);
931
+ warnIfTooLong("TimePicker placeholder", placeholder, MAX_PLACEHOLDER_LENGTH);
841
932
  }
842
933
  const res = {
843
934
  type: "timepicker",
844
935
  action_id: actionId
845
936
  };
846
937
  if (placeholder) {
847
- res.placeholder = transform(/* @__PURE__ */ React14.createElement(Text, { plainText: true }, placeholder));
938
+ res.placeholder = transform(/* @__PURE__ */ jsx(Text, { plainText: true, children: placeholder }));
848
939
  }
849
940
  if (initialTime) {
850
941
  if (!isValidTimeString(initialTime)) {
851
- 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");
852
943
  }
853
944
  res.initial_time = initialTime;
854
945
  }
@@ -973,17 +1064,13 @@ var emoji_default = transformRichTextEmoji;
973
1064
 
974
1065
  // src/transformers/rich-text/date.ts
975
1066
  var transformRichTextDate = (child) => {
976
- const { timestamp, format, fallback, link } = child.props;
977
- const res = {
1067
+ const { timestamp, format, fallback } = child.props;
1068
+ return {
978
1069
  type: "date",
979
1070
  timestamp,
980
1071
  format,
981
1072
  fallback
982
1073
  };
983
- if (link) {
984
- res.link = link;
985
- }
986
- return res;
987
1074
  };
988
1075
  var date_default = transformRichTextDate;
989
1076
 
@@ -1008,7 +1095,7 @@ var transformRichTextUserGroup = (child) => {
1008
1095
  var user_group_default = transformRichTextUserGroup;
1009
1096
 
1010
1097
  // src/transformers/index.ts
1011
- var Transformers = {
1098
+ Object.assign(registry_default, {
1012
1099
  Container: container_default,
1013
1100
  Section: section_default,
1014
1101
  Actions: actions_default,
@@ -1046,33 +1133,9 @@ var Transformers = {
1046
1133
  RichTextDate: date_default,
1047
1134
  RichTextBroadcast: broadcast_default,
1048
1135
  RichTextUserGroup: user_group_default
1049
- };
1050
- var transformers_default = Transformers;
1051
- var transform = (element) => {
1052
- const type = get_type_default(element);
1053
- if (!Transformers[type]) {
1054
- throw new Error(`No transformer exists for type '${type}'`);
1055
- }
1056
- return Transformers[type](element);
1057
- };
1136
+ });
1058
1137
 
1059
1138
  // src/parser/index.ts
1060
- var normalizeChildren2 = (children) => {
1061
- const result = [];
1062
- const stack = Array.isArray(children) ? [...children] : [children];
1063
- while (stack.length > 0) {
1064
- const child = stack.shift();
1065
- if (child === null || child === void 0 || typeof child === "boolean") {
1066
- continue;
1067
- }
1068
- if (Array.isArray(child)) {
1069
- stack.unshift(...child);
1070
- continue;
1071
- }
1072
- result.push(child);
1073
- }
1074
- return result;
1075
- };
1076
1139
  var appendTransformed = (value, blocks) => {
1077
1140
  if (value === null || value === void 0 || typeof value === "boolean") {
1078
1141
  return;
@@ -1089,15 +1152,20 @@ var parseChildren = (children) => {
1089
1152
  if (typeof children === "string") {
1090
1153
  return { text: children };
1091
1154
  }
1092
- const normalizedChildren = normalizeChildren2(children);
1155
+ const normalizedChildren = normalize_children_default(children);
1093
1156
  const transformedBlocks = [];
1094
1157
  for (const child of normalizedChildren) {
1095
1158
  const type = get_type_default(child);
1096
- const transformer = transformers_default[type];
1159
+ const transformer = registry_default[type];
1097
1160
  if (transformer) {
1098
- appendTransformed(transformer(child), transformedBlocks);
1161
+ pushPath(type);
1162
+ try {
1163
+ appendTransformed(transformer(child), transformedBlocks);
1164
+ } finally {
1165
+ popPath();
1166
+ }
1099
1167
  } else if (type !== "null") {
1100
- console.warn(`No transformer for child type '${type}' exists and will be ignored.`);
1168
+ report(`No transformer for component type '${type}'.`, "unknown-type");
1101
1169
  }
1102
1170
  }
1103
1171
  if (transformedBlocks.length === 0) {
@@ -1108,23 +1176,14 @@ var parseChildren = (children) => {
1108
1176
  var parser_default = parseChildren;
1109
1177
 
1110
1178
  // src/renderer/index.ts
1111
- var render = (element) => {
1112
- const { props: properties = {} } = element || {};
1113
- const typeName = get_type_default(element);
1114
- if (typeName !== "Message") {
1115
- throw new TypeError("Provided top-level element must be a Message type.");
1116
- }
1117
- if (!properties.children) {
1118
- throw new Error("Cannot render a Message with no children.");
1119
- }
1120
- const json = { ...parser_default(properties.children) };
1121
- if (properties.replyTo) {
1122
- json.thread_ts = properties.replyTo;
1123
- }
1124
- if (properties.markdown !== void 0) {
1125
- json.mrkdwn = properties.markdown;
1126
- }
1127
- 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) => {
1128
1187
  if (properties.iconEmoji) {
1129
1188
  json.icon_emoji = properties.iconEmoji;
1130
1189
  }
@@ -1149,23 +1208,66 @@ var render = (element) => {
1149
1208
  if (properties.unfurlMedia !== void 0) {
1150
1209
  json.unfurl_media = properties.unfurlMedia;
1151
1210
  }
1152
- if (properties.color && json.blocks) {
1153
- json.attachments = [
1154
- {
1155
- fallback: json.text,
1156
- color: properties.color,
1157
- blocks: json.blocks
1158
- }
1159
- ];
1160
- 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.");
1161
1219
  }
1162
- if (json.blocks) {
1163
- 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();
1164
1255
  }
1165
1256
  return json;
1166
1257
  };
1167
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 })}`;
1168
1265
  export {
1169
- renderer_default as default
1266
+ SlackblockValidationError,
1267
+ blockKitBuilderUrl,
1268
+ renderer_default as default,
1269
+ escapeMrkdwn,
1270
+ renderToBlocks,
1271
+ render as renderToMessage
1170
1272
  };
1171
1273
  //# sourceMappingURL=index.mjs.map