@elastic/isomer-sdk 0.2.0 → 0.4.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 (251) hide show
  1. package/NOTICE.txt +0 -286
  2. package/THIRD_PARTY_LICENSES.md +1 -885
  3. package/dist/author/authored_fields.d.ts +37 -12
  4. package/dist/author/authored_fields.d.ts.map +1 -1
  5. package/dist/author/authored_fields.js +45 -69
  6. package/dist/author/authored_fields.js.map +1 -1
  7. package/dist/author/authoring_input.d.ts.map +1 -1
  8. package/dist/author/authoring_input.js +12 -6
  9. package/dist/author/authoring_input.js.map +1 -1
  10. package/dist/author/authoring_model.d.ts +8 -2
  11. package/dist/author/authoring_model.d.ts.map +1 -1
  12. package/dist/author/authoring_model.js +67 -23
  13. package/dist/author/authoring_model.js.map +1 -1
  14. package/dist/author/declarations.d.ts.map +1 -1
  15. package/dist/author/declarations.js +45 -34
  16. package/dist/author/declarations.js.map +1 -1
  17. package/dist/author/index.d.ts +2 -1
  18. package/dist/author/index.d.ts.map +1 -1
  19. package/dist/author/index.js +2 -1
  20. package/dist/author/index.js.map +1 -1
  21. package/dist/author/jsx_shim.d.ts +49 -30
  22. package/dist/author/jsx_shim.d.ts.map +1 -1
  23. package/dist/author/jsx_shim.js +131 -40
  24. package/dist/author/jsx_shim.js.map +1 -1
  25. package/dist/author/print_jsx.d.ts +19 -0
  26. package/dist/author/print_jsx.d.ts.map +1 -0
  27. package/dist/author/print_jsx.js +372 -0
  28. package/dist/author/print_jsx.js.map +1 -0
  29. package/dist/author/prompt.d.ts +2 -2
  30. package/dist/author/prompt.d.ts.map +1 -1
  31. package/dist/author/prompt.js +7 -2
  32. package/dist/author/prompt.js.map +1 -1
  33. package/dist/author/schema_to_typescript.d.ts.map +1 -1
  34. package/dist/author/schema_to_typescript.js +6 -3
  35. package/dist/author/schema_to_typescript.js.map +1 -1
  36. package/dist/cjs/author/authored_fields.js +47 -70
  37. package/dist/cjs/author/authored_fields.js.map +1 -1
  38. package/dist/cjs/author/authoring_input.js +12 -6
  39. package/dist/cjs/author/authoring_input.js.map +1 -1
  40. package/dist/cjs/author/authoring_model.js +69 -24
  41. package/dist/cjs/author/authoring_model.js.map +1 -1
  42. package/dist/cjs/author/declarations.js +44 -33
  43. package/dist/cjs/author/declarations.js.map +1 -1
  44. package/dist/cjs/author/index.js +5 -1
  45. package/dist/cjs/author/index.js.map +1 -1
  46. package/dist/cjs/author/jsx_shim.js +130 -39
  47. package/dist/cjs/author/jsx_shim.js.map +1 -1
  48. package/dist/cjs/author/print_jsx.js +378 -0
  49. package/dist/cjs/author/print_jsx.js.map +1 -0
  50. package/dist/cjs/author/prompt.js +7 -2
  51. package/dist/cjs/author/prompt.js.map +1 -1
  52. package/dist/cjs/author/schema_to_typescript.js +6 -3
  53. package/dist/cjs/author/schema_to_typescript.js.map +1 -1
  54. package/dist/cjs/composition/error.js +2 -0
  55. package/dist/cjs/composition/error.js.map +1 -1
  56. package/dist/cjs/composition/structured_value.js.map +1 -1
  57. package/dist/cjs/define/index.js.map +1 -1
  58. package/dist/cjs/define/primitive_module.js +10 -4
  59. package/dist/cjs/define/primitive_module.js.map +1 -1
  60. package/dist/cjs/define/slack_blocks.js.map +1 -1
  61. package/dist/cjs/entries/index.js +5 -2
  62. package/dist/cjs/entries/index.js.map +1 -1
  63. package/dist/cjs/entries/markdown.js +3 -1
  64. package/dist/cjs/entries/markdown.js.map +1 -1
  65. package/dist/cjs/entries/react.js +2 -1
  66. package/dist/cjs/entries/react.js.map +1 -1
  67. package/dist/cjs/entries/slack.js +5 -1
  68. package/dist/cjs/entries/slack.js.map +1 -1
  69. package/dist/cjs/pack/enhancements.js.map +1 -1
  70. package/dist/cjs/pack/index.js +2 -1
  71. package/dist/cjs/pack/index.js.map +1 -1
  72. package/dist/cjs/pack/primitive_pack.js +14 -4
  73. package/dist/cjs/pack/primitive_pack.js.map +1 -1
  74. package/dist/cjs/render/format_number.js +2 -1
  75. package/dist/cjs/render/format_number.js.map +1 -1
  76. package/dist/cjs/render/html/envelope.js +12 -6
  77. package/dist/cjs/render/html/envelope.js.map +1 -1
  78. package/dist/cjs/render/markdown/blocks.js +82 -0
  79. package/dist/cjs/render/markdown/blocks.js.map +1 -0
  80. package/dist/cjs/render/markdown/builder.js +6 -2
  81. package/dist/cjs/render/markdown/builder.js.map +1 -1
  82. package/dist/cjs/render/markdown/format.js +46 -24
  83. package/dist/cjs/render/markdown/format.js.map +1 -1
  84. package/dist/cjs/render/markdown/host_tags.js +67 -0
  85. package/dist/cjs/render/markdown/host_tags.js.map +1 -0
  86. package/dist/cjs/render/markdown/index.js +5 -1
  87. package/dist/cjs/render/markdown/index.js.map +1 -1
  88. package/dist/cjs/render/markdown/split.js +325 -0
  89. package/dist/cjs/render/markdown/split.js.map +1 -0
  90. package/dist/cjs/render/primitive_dispatch.js +36 -6
  91. package/dist/cjs/render/primitive_dispatch.js.map +1 -1
  92. package/dist/cjs/render/react/content.js +3 -1
  93. package/dist/cjs/render/react/content.js.map +1 -1
  94. package/dist/cjs/render/react/index.js +3 -1
  95. package/dist/cjs/render/react/index.js.map +1 -1
  96. package/dist/cjs/render/react/markdown_content.js +143 -0
  97. package/dist/cjs/render/react/markdown_content.js.map +1 -0
  98. package/dist/cjs/render/slack/blocks.js +7 -0
  99. package/dist/cjs/render/slack/blocks.js.map +1 -1
  100. package/dist/cjs/render/slack/container.js +62 -0
  101. package/dist/cjs/render/slack/container.js.map +1 -0
  102. package/dist/cjs/render/slack/envelope.js +70 -14
  103. package/dist/cjs/render/slack/envelope.js.map +1 -1
  104. package/dist/cjs/render/slack/format.js +56 -6
  105. package/dist/cjs/render/slack/format.js.map +1 -1
  106. package/dist/cjs/render/slack/index.js +7 -1
  107. package/dist/cjs/render/slack/index.js.map +1 -1
  108. package/dist/cjs/render/slack/markdown_content.js +36 -77
  109. package/dist/cjs/render/slack/markdown_content.js.map +1 -1
  110. package/dist/cjs/render/slack/unmodeled.js +38 -0
  111. package/dist/cjs/render/slack/unmodeled.js.map +1 -0
  112. package/dist/cjs/testing/conformance.js +15 -1
  113. package/dist/cjs/testing/conformance.js.map +1 -1
  114. package/dist/cjs/testing/index.js +2 -1
  115. package/dist/cjs/testing/index.js.map +1 -1
  116. package/dist/cjs/validate/json_schema.js +10 -3
  117. package/dist/cjs/validate/json_schema.js.map +1 -1
  118. package/dist/cjs/validate/url.js +2 -1
  119. package/dist/cjs/validate/url.js.map +1 -1
  120. package/dist/composition/error.d.ts +2 -0
  121. package/dist/composition/error.d.ts.map +1 -1
  122. package/dist/composition/error.js +2 -0
  123. package/dist/composition/error.js.map +1 -1
  124. package/dist/composition/structured_value.d.ts +3 -3
  125. package/dist/composition/structured_value.d.ts.map +1 -1
  126. package/dist/composition/structured_value.js.map +1 -1
  127. package/dist/define/index.d.ts +1 -1
  128. package/dist/define/index.d.ts.map +1 -1
  129. package/dist/define/index.js.map +1 -1
  130. package/dist/define/primitive_module.d.ts +14 -5
  131. package/dist/define/primitive_module.d.ts.map +1 -1
  132. package/dist/define/primitive_module.js +10 -4
  133. package/dist/define/primitive_module.js.map +1 -1
  134. package/dist/define/slack_blocks.d.ts +31 -1
  135. package/dist/define/slack_blocks.d.ts.map +1 -1
  136. package/dist/define/slack_blocks.js.map +1 -1
  137. package/dist/entries/index.d.ts +2 -2
  138. package/dist/entries/index.d.ts.map +1 -1
  139. package/dist/entries/index.js +2 -2
  140. package/dist/entries/index.js.map +1 -1
  141. package/dist/entries/markdown.d.ts +1 -1
  142. package/dist/entries/markdown.d.ts.map +1 -1
  143. package/dist/entries/markdown.js +1 -1
  144. package/dist/entries/markdown.js.map +1 -1
  145. package/dist/entries/react.d.ts +1 -1
  146. package/dist/entries/react.d.ts.map +1 -1
  147. package/dist/entries/react.js +1 -1
  148. package/dist/entries/react.js.map +1 -1
  149. package/dist/entries/slack.d.ts +1 -1
  150. package/dist/entries/slack.d.ts.map +1 -1
  151. package/dist/entries/slack.js +1 -1
  152. package/dist/entries/slack.js.map +1 -1
  153. package/dist/pack/enhancements.d.ts +4 -0
  154. package/dist/pack/enhancements.d.ts.map +1 -1
  155. package/dist/pack/enhancements.js.map +1 -1
  156. package/dist/pack/index.d.ts +1 -1
  157. package/dist/pack/index.d.ts.map +1 -1
  158. package/dist/pack/index.js +1 -1
  159. package/dist/pack/index.js.map +1 -1
  160. package/dist/pack/primitive_pack.d.ts +3 -1
  161. package/dist/pack/primitive_pack.d.ts.map +1 -1
  162. package/dist/pack/primitive_pack.js +13 -3
  163. package/dist/pack/primitive_pack.js.map +1 -1
  164. package/dist/render/format_number.d.ts.map +1 -1
  165. package/dist/render/format_number.js +2 -1
  166. package/dist/render/format_number.js.map +1 -1
  167. package/dist/render/html/envelope.js +12 -6
  168. package/dist/render/html/envelope.js.map +1 -1
  169. package/dist/render/markdown/blocks.d.ts +6 -0
  170. package/dist/render/markdown/blocks.d.ts.map +1 -0
  171. package/dist/render/markdown/blocks.js +77 -0
  172. package/dist/render/markdown/blocks.js.map +1 -0
  173. package/dist/render/markdown/builder.d.ts +3 -0
  174. package/dist/render/markdown/builder.d.ts.map +1 -1
  175. package/dist/render/markdown/builder.js +3 -1
  176. package/dist/render/markdown/builder.js.map +1 -1
  177. package/dist/render/markdown/format.d.ts +2 -0
  178. package/dist/render/markdown/format.d.ts.map +1 -1
  179. package/dist/render/markdown/format.js +42 -22
  180. package/dist/render/markdown/format.js.map +1 -1
  181. package/dist/render/markdown/host_tags.d.ts +14 -0
  182. package/dist/render/markdown/host_tags.d.ts.map +1 -0
  183. package/dist/render/markdown/host_tags.js +63 -0
  184. package/dist/render/markdown/host_tags.js.map +1 -0
  185. package/dist/render/markdown/index.d.ts +2 -0
  186. package/dist/render/markdown/index.d.ts.map +1 -1
  187. package/dist/render/markdown/index.js +2 -0
  188. package/dist/render/markdown/index.js.map +1 -1
  189. package/dist/render/markdown/split.d.ts +32 -0
  190. package/dist/render/markdown/split.d.ts.map +1 -0
  191. package/dist/render/markdown/split.js +321 -0
  192. package/dist/render/markdown/split.js.map +1 -0
  193. package/dist/render/primitive_dispatch.d.ts +4 -2
  194. package/dist/render/primitive_dispatch.d.ts.map +1 -1
  195. package/dist/render/primitive_dispatch.js +36 -6
  196. package/dist/render/primitive_dispatch.js.map +1 -1
  197. package/dist/render/react/content.d.ts +1 -1
  198. package/dist/render/react/content.d.ts.map +1 -1
  199. package/dist/render/react/content.js +3 -1
  200. package/dist/render/react/content.js.map +1 -1
  201. package/dist/render/react/index.d.ts +1 -0
  202. package/dist/render/react/index.d.ts.map +1 -1
  203. package/dist/render/react/index.js +1 -0
  204. package/dist/render/react/index.js.map +1 -1
  205. package/dist/render/react/markdown_content.d.ts +9 -0
  206. package/dist/render/react/markdown_content.d.ts.map +1 -0
  207. package/dist/render/react/markdown_content.js +139 -0
  208. package/dist/render/react/markdown_content.js.map +1 -0
  209. package/dist/render/slack/blocks.d.ts +8 -1
  210. package/dist/render/slack/blocks.d.ts.map +1 -1
  211. package/dist/render/slack/blocks.js +7 -0
  212. package/dist/render/slack/blocks.js.map +1 -1
  213. package/dist/render/slack/container.d.ts +25 -0
  214. package/dist/render/slack/container.d.ts.map +1 -0
  215. package/dist/render/slack/container.js +55 -0
  216. package/dist/render/slack/container.js.map +1 -0
  217. package/dist/render/slack/envelope.d.ts +6 -4
  218. package/dist/render/slack/envelope.d.ts.map +1 -1
  219. package/dist/render/slack/envelope.js +71 -15
  220. package/dist/render/slack/envelope.js.map +1 -1
  221. package/dist/render/slack/format.d.ts +15 -3
  222. package/dist/render/slack/format.d.ts.map +1 -1
  223. package/dist/render/slack/format.js +54 -5
  224. package/dist/render/slack/format.js.map +1 -1
  225. package/dist/render/slack/index.d.ts +4 -2
  226. package/dist/render/slack/index.d.ts.map +1 -1
  227. package/dist/render/slack/index.js +2 -0
  228. package/dist/render/slack/index.js.map +1 -1
  229. package/dist/render/slack/markdown_content.d.ts +3 -2
  230. package/dist/render/slack/markdown_content.d.ts.map +1 -1
  231. package/dist/render/slack/markdown_content.js +27 -68
  232. package/dist/render/slack/markdown_content.js.map +1 -1
  233. package/dist/render/slack/unmodeled.d.ts +16 -0
  234. package/dist/render/slack/unmodeled.d.ts.map +1 -0
  235. package/dist/render/slack/unmodeled.js +32 -0
  236. package/dist/render/slack/unmodeled.js.map +1 -0
  237. package/dist/testing/conformance.d.ts +3 -1
  238. package/dist/testing/conformance.d.ts.map +1 -1
  239. package/dist/testing/conformance.js +14 -0
  240. package/dist/testing/conformance.js.map +1 -1
  241. package/dist/testing/index.d.ts +1 -1
  242. package/dist/testing/index.d.ts.map +1 -1
  243. package/dist/testing/index.js +1 -1
  244. package/dist/testing/index.js.map +1 -1
  245. package/dist/validate/json_schema.d.ts.map +1 -1
  246. package/dist/validate/json_schema.js +10 -3
  247. package/dist/validate/json_schema.js.map +1 -1
  248. package/dist/validate/url.d.ts.map +1 -1
  249. package/dist/validate/url.js +2 -1
  250. package/dist/validate/url.js.map +1 -1
  251. package/package.json +2 -2
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
4
+ * or more contributor license agreements. Licensed under the Elastic License
5
+ * 2.0; you may not use this file except in compliance with the Elastic License
6
+ * 2.0.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.renderMarkdownContent = void 0;
10
+ // Builder content as React elements, read from the blocks the Markdown and
11
+ // Slack surfaces read. Unstyled: a pack's stylesheet owns the look.
12
+ const react_1 = require("react");
13
+ const url_1 = require("../../validate/url");
14
+ const blocks_1 = require("../markdown/blocks");
15
+ const HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
16
+ const footnoteLabel = ({ identifier, label, }) => `[^${label ?? identifier}]`;
17
+ const plainText = (node) => {
18
+ if ('value' in node) {
19
+ return node.value;
20
+ }
21
+ if (node.type === 'image') {
22
+ return node.alt ?? '';
23
+ }
24
+ if (node.type === 'footnoteReference') {
25
+ return footnoteLabel(node);
26
+ }
27
+ return 'children' in node ? node.children.map(plainText).join('') : '';
28
+ };
29
+ const keyed = (nodes) => nodes.map((node, index) => (0, react_1.createElement)(react_1.Fragment, { key: index }, node));
30
+ const inlines = (nodes) => keyed(nodes.map(inline));
31
+ const inline = (node) => {
32
+ switch (node.type) {
33
+ case 'strong':
34
+ return (0, react_1.createElement)('strong', null, ...inlines(node.children));
35
+ case 'emphasis':
36
+ return (0, react_1.createElement)('em', null, ...inlines(node.children));
37
+ case 'delete':
38
+ return (0, react_1.createElement)('del', null, ...inlines(node.children));
39
+ case 'inlineCode':
40
+ return (0, react_1.createElement)('code', null, node.value);
41
+ case 'break':
42
+ return (0, react_1.createElement)('br');
43
+ case 'link':
44
+ return (0, react_1.createElement)('a', {
45
+ href: (0, url_1.sanitizeParsedNavigationHref)(node.url) ?? url_1.BLOCKED_HREF,
46
+ ...(node.title ? { title: node.title } : {}),
47
+ }, ...inlines(node.children));
48
+ case 'image': {
49
+ const src = (0, url_1.sanitizeParsedAssetUrl)(node.url);
50
+ return src === null
51
+ ? (node.alt ?? '')
52
+ : (0, react_1.createElement)('img', {
53
+ src,
54
+ alt: node.alt ?? '',
55
+ ...(node.title ? { title: node.title } : {}),
56
+ });
57
+ }
58
+ default:
59
+ return plainText(node);
60
+ }
61
+ };
62
+ const paragraphCount = (item) => item.children.filter(({ type }) => type === 'paragraph').length;
63
+ // A spread list, a spread item, or an item with two paragraphs makes the whole list loose.
64
+ const items = (list) => {
65
+ const tight = list.spread !== true &&
66
+ !list.children.some((item) => item.spread === true || paragraphCount(item) > 1);
67
+ return list.children.map((item, index) => listItem(item, index, tight));
68
+ };
69
+ // A task item's checkbox leads its first paragraph, so a loose item keeps it on the task's line.
70
+ const listItem = (item, key, tight) => {
71
+ const checkbox = typeof item.checked === 'boolean'
72
+ ? [
73
+ (0, react_1.createElement)('input', {
74
+ type: 'checkbox',
75
+ checked: item.checked,
76
+ disabled: true,
77
+ }),
78
+ ' ',
79
+ ]
80
+ : [];
81
+ const [first, ...rest] = item.children;
82
+ const leadsWithParagraph = first?.type === 'paragraph';
83
+ const lead = leadsWithParagraph
84
+ ? [...checkbox, ...inlines(first.children)]
85
+ : checkbox;
86
+ const head = leadsWithParagraph && !tight ? [(0, react_1.createElement)('p', null, ...lead)] : lead;
87
+ const body = (leadsWithParagraph ? rest : item.children).flatMap((child) => child.type === 'paragraph' && tight
88
+ ? inlines(child.children)
89
+ : [block(child)]);
90
+ return (0, react_1.createElement)('li', { key }, ...keyed([...head, ...body]));
91
+ };
92
+ const tableRows = (table) => {
93
+ const [header, ...body] = table.children;
94
+ const cells = (row, tag) => (0, react_1.createElement)('tr', null, ...row.children.map((cell, index) => {
95
+ const align = table.align?.[index];
96
+ return (0, react_1.createElement)(tag, {
97
+ key: index,
98
+ ...(align ? { style: { textAlign: align } } : {}),
99
+ }, ...inlines(cell.children));
100
+ }));
101
+ return (0, react_1.createElement)(react_1.Fragment, null, header
102
+ ? (0, react_1.createElement)('thead', { key: 'head' }, cells(header, 'th'))
103
+ : null, body.length > 0
104
+ ? (0, react_1.createElement)('tbody', { key: 'body' }, ...body.map((row, index) => (0, react_1.createElement)(react_1.Fragment, { key: index }, cells(row, 'td'))))
105
+ : null);
106
+ };
107
+ const blocks = (nodes) => keyed(nodes.map(block));
108
+ const block = (node) => {
109
+ switch (node.type) {
110
+ case 'paragraph':
111
+ return (0, react_1.createElement)('p', null, ...inlines(node.children));
112
+ case 'heading':
113
+ return (0, react_1.createElement)(HEADINGS[node.depth - 1], null, ...inlines(node.children));
114
+ case 'blockquote':
115
+ return (0, react_1.createElement)('blockquote', null, ...blocks(node.children));
116
+ case 'list':
117
+ return (0, react_1.createElement)(node.ordered ? 'ol' : 'ul', node.ordered && node.start != null && node.start !== 1
118
+ ? { start: node.start }
119
+ : null, ...items(node));
120
+ case 'code':
121
+ return (0, react_1.createElement)('pre', null, (0, react_1.createElement)('code', node.lang ? { className: `language-${node.lang}` } : null, node.value));
122
+ case 'table':
123
+ return (0, react_1.createElement)('table', null, tableRows(node));
124
+ case 'thematicBreak':
125
+ return (0, react_1.createElement)('hr');
126
+ case 'html':
127
+ return (0, react_1.createElement)('p', null, node.value);
128
+ case 'footnoteDefinition': {
129
+ const [first, ...rest] = node.children;
130
+ return (0, react_1.createElement)(react_1.Fragment, null, (0, react_1.createElement)('p', null, `${footnoteLabel(node)}: `, ...(first?.type === 'paragraph' ? inlines(first.children) : [])), ...blocks(first?.type === 'paragraph' ? rest : node.children));
131
+ }
132
+ default:
133
+ return null;
134
+ }
135
+ };
136
+ /**
137
+ * Builder content as React elements: paragraphs, headings, lists, quotes, code, tables, and thematic breaks, with inline marks, links, and images. Source from `md.authored` is parsed as GFM, once, as the Markdown and Slack surfaces read it.
138
+ *
139
+ * Links and images follow `md`'s URL policy: a blocked link keeps its label on {@link BLOCKED_HREF}, and a blocked image degrades to its alt text.
140
+ */
141
+ const renderMarkdownContent = (content) => (0, react_1.createElement)(react_1.Fragment, null, ...blocks((0, blocks_1.resolvedMarkdownBlocks)(content)));
142
+ exports.renderMarkdownContent = renderMarkdownContent;
143
+ //# sourceMappingURL=markdown_content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown_content.js","sourceRoot":"","sources":["../../../../src/render/react/markdown_content.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\n// Builder content as React elements, read from the blocks the Markdown and\n// Slack surfaces read. Unstyled: a pack's stylesheet owns the look.\n\nimport { createElement, Fragment, type ReactNode } from 'react';\nimport type {\n FootnoteDefinition,\n List,\n ListItem,\n Nodes,\n PhrasingContent,\n RootContent,\n Table,\n} from 'mdast';\n\nimport type { MarkdownContent } from '../../define/markdown_content';\nimport {\n BLOCKED_HREF,\n sanitizeParsedAssetUrl,\n sanitizeParsedNavigationHref,\n} from '../../validate/url';\nimport { resolvedMarkdownBlocks } from '../markdown/blocks';\n\nconst HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;\n\nconst footnoteLabel = ({\n identifier,\n label,\n}: Pick<FootnoteDefinition, 'identifier' | 'label'>): string =>\n `[^${label ?? identifier}]`;\n\nconst plainText = (node: Nodes): string => {\n if ('value' in node) {\n return node.value;\n }\n if (node.type === 'image') {\n return node.alt ?? '';\n }\n if (node.type === 'footnoteReference') {\n return footnoteLabel(node);\n }\n return 'children' in node ? node.children.map(plainText).join('') : '';\n};\n\nconst keyed = (nodes: readonly ReactNode[]): ReactNode[] =>\n nodes.map((node, index) => createElement(Fragment, { key: index }, node));\n\nconst inlines = (nodes: readonly PhrasingContent[]): ReactNode[] =>\n keyed(nodes.map(inline));\n\nconst inline = (node: PhrasingContent): ReactNode => {\n switch (node.type) {\n case 'strong':\n return createElement('strong', null, ...inlines(node.children));\n case 'emphasis':\n return createElement('em', null, ...inlines(node.children));\n case 'delete':\n return createElement('del', null, ...inlines(node.children));\n case 'inlineCode':\n return createElement('code', null, node.value);\n case 'break':\n return createElement('br');\n case 'link':\n return createElement(\n 'a',\n {\n href: sanitizeParsedNavigationHref(node.url) ?? BLOCKED_HREF,\n ...(node.title ? { title: node.title } : {}),\n },\n ...inlines(node.children)\n );\n case 'image': {\n const src = sanitizeParsedAssetUrl(node.url);\n return src === null\n ? (node.alt ?? '')\n : createElement('img', {\n src,\n alt: node.alt ?? '',\n ...(node.title ? { title: node.title } : {}),\n });\n }\n default:\n return plainText(node);\n }\n};\n\nconst paragraphCount = (item: ListItem): number =>\n item.children.filter(({ type }) => type === 'paragraph').length;\n\n// A spread list, a spread item, or an item with two paragraphs makes the whole list loose.\nconst items = (list: List): ReactNode[] => {\n const tight =\n list.spread !== true &&\n !list.children.some(\n (item) => item.spread === true || paragraphCount(item) > 1\n );\n return list.children.map((item, index) => listItem(item, index, tight));\n};\n\n// A task item's checkbox leads its first paragraph, so a loose item keeps it on the task's line.\nconst listItem = (item: ListItem, key: number, tight: boolean): ReactNode => {\n const checkbox =\n typeof item.checked === 'boolean'\n ? [\n createElement('input', {\n type: 'checkbox',\n checked: item.checked,\n disabled: true,\n }),\n ' ',\n ]\n : [];\n const [first, ...rest] = item.children;\n const leadsWithParagraph = first?.type === 'paragraph';\n const lead = leadsWithParagraph\n ? [...checkbox, ...inlines(first.children)]\n : checkbox;\n const head =\n leadsWithParagraph && !tight ? [createElement('p', null, ...lead)] : lead;\n const body = (leadsWithParagraph ? rest : item.children).flatMap(\n (child): ReactNode[] =>\n child.type === 'paragraph' && tight\n ? inlines(child.children)\n : [block(child)]\n );\n return createElement('li', { key }, ...keyed([...head, ...body]));\n};\n\nconst tableRows = (table: Table): ReactNode => {\n const [header, ...body] = table.children;\n const cells = (row: Table['children'][number], tag: 'th' | 'td'): ReactNode =>\n createElement(\n 'tr',\n null,\n ...row.children.map((cell, index) => {\n const align = table.align?.[index];\n return createElement(\n tag,\n {\n key: index,\n ...(align ? { style: { textAlign: align } } : {}),\n },\n ...inlines(cell.children)\n );\n })\n );\n return createElement(\n Fragment,\n null,\n header\n ? createElement('thead', { key: 'head' }, cells(header, 'th'))\n : null,\n body.length > 0\n ? createElement(\n 'tbody',\n { key: 'body' },\n ...body.map((row, index) =>\n createElement(Fragment, { key: index }, cells(row, 'td'))\n )\n )\n : null\n );\n};\n\nconst blocks = (nodes: readonly RootContent[]): ReactNode[] =>\n keyed(nodes.map(block));\n\nconst block = (node: RootContent): ReactNode => {\n switch (node.type) {\n case 'paragraph':\n return createElement('p', null, ...inlines(node.children));\n case 'heading':\n return createElement(\n HEADINGS[node.depth - 1]!,\n null,\n ...inlines(node.children)\n );\n case 'blockquote':\n return createElement('blockquote', null, ...blocks(node.children));\n case 'list':\n return createElement(\n node.ordered ? 'ol' : 'ul',\n node.ordered && node.start != null && node.start !== 1\n ? { start: node.start }\n : null,\n ...items(node)\n );\n case 'code':\n return createElement(\n 'pre',\n null,\n createElement(\n 'code',\n node.lang ? { className: `language-${node.lang}` } : null,\n node.value\n )\n );\n case 'table':\n return createElement('table', null, tableRows(node));\n case 'thematicBreak':\n return createElement('hr');\n case 'html':\n return createElement('p', null, node.value);\n case 'footnoteDefinition': {\n const [first, ...rest] = node.children;\n return createElement(\n Fragment,\n null,\n createElement(\n 'p',\n null,\n `${footnoteLabel(node)}: `,\n ...(first?.type === 'paragraph' ? inlines(first.children) : [])\n ),\n ...blocks(first?.type === 'paragraph' ? rest : node.children)\n );\n }\n default:\n return null;\n }\n};\n\n/**\n * Builder content as React elements: paragraphs, headings, lists, quotes, code, tables, and thematic breaks, with inline marks, links, and images. Source from `md.authored` is parsed as GFM, once, as the Markdown and Slack surfaces read it.\n *\n * Links and images follow `md`'s URL policy: a blocked link keeps its label on {@link BLOCKED_HREF}, and a blocked image degrades to its alt text.\n */\nexport const renderMarkdownContent = (content: MarkdownContent): ReactNode =>\n createElement(\n Fragment,\n null,\n ...blocks(resolvedMarkdownBlocks(content) as RootContent[])\n );\n"]}
@@ -12,7 +12,14 @@ exports.SLACK_LIMITS = void 0;
12
12
  * cannot silently trip Slack's validation.
13
13
  */
14
14
  exports.SLACK_LIMITS = {
15
+ /** Top-level blocks; a `container`'s `child_blocks` do not count. */
15
16
  blocksPerMessage: 50,
17
+ /** `container.title`, which is `plain_text`. */
18
+ containerTitleChars: 150,
19
+ /** `container.subtitle`. */
20
+ containerSubtitleChars: 150,
21
+ /** `container.child_blocks`; Slack also requires at least one. */
22
+ containerChildBlocks: 10,
16
23
  /** `section.text`. */
17
24
  sectionTextChars: 3000,
18
25
  /** One entry of `section.fields`. */
@@ -1 +1 @@
1
- {"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../../src/render/slack/blocks.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA6CH;;;GAGG;AACU,QAAA,YAAY,GAAG;IAC1B,gBAAgB,EAAE,EAAE;IACpB,sBAAsB;IACtB,gBAAgB,EAAE,IAAI;IACtB,qCAAqC;IACrC,iBAAiB,EAAE,IAAI;IACvB,uCAAuC;IACvC,mBAAmB,EAAE,IAAI;IACzB,4CAA4C;IAC5C,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,EAAE;IACpB,oCAAoC;IACpC,eAAe,EAAE,EAAE;IACnB,iBAAiB,EAAE,EAAE;IACrB,kFAAkF;IAClF,iBAAiB,EAAE,IAAI;IACvB,yEAAyE;IACzE,eAAe,EAAE,EAAE;IACnB,sDAAsD;IACtD,gBAAgB,EAAE,GAAG;IACrB,4DAA4D;IAC5D,kBAAkB,EAAE,CAAC;IACrB,4DAA4D;IAC5D,gBAAgB,EAAE,EAAE;IACpB,+EAA+E;IAC/E,qBAAqB,EAAE,GAAG;IAC1B,yDAAyD;IACzD,gBAAgB,EAAE,GAAG;IACrB,0BAA0B;IAC1B,gBAAgB,EAAE,IAAI;IACtB,6CAA6C;IAC7C,QAAQ,EAAE,IAAI;IACd,4CAA4C;IAC5C,aAAa,EAAE,GAAG;IAClB,6CAA6C;IAC7C,qBAAqB,EAAE,CAAC;IACxB;;;;;OAKG;IACH,wBAAwB,EAAE,MAAM;IAChC,wDAAwD;IACxD,SAAS,EAAE,GAAG;IACd,iDAAiD;IACjD,YAAY,EAAE,EAAE;IAChB,oDAAoD;IACpD,aAAa,EAAE,IAAI;IACnB,mDAAmD;IACnD,iBAAiB,EAAE,IAAI;IACvB,6BAA6B;IAC7B,eAAe,EAAE,IAAI;IACrB,4DAA4D;IAC5D,eAAe,EAAE,GAAG;IACpB,kEAAkE;IAClE,qBAAqB,EAAE,GAAG;IAC1B,iEAAiE;IACjE,oBAAoB,EAAE,EAAE;IACxB,+BAA+B;IAC/B,eAAe,EAAE,EAAE;IACnB,4BAA4B;IAC5B,gBAAgB,EAAE,GAAG;IACrB,+BAA+B;IAC/B,qBAAqB,EAAE,EAAE;CACjB,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nexport type {\n SlackActionElement,\n SlackActionsBlock,\n SlackBlock,\n SlackButtonElement,\n SlackCheckboxesElement,\n SlackContextBlock,\n SlackDividerBlock,\n SlackFileReference,\n SlackHeaderBlock,\n SlackHeaderLevel,\n SlackImageBlock,\n SlackImageElement,\n SlackMrkdwnTextObject,\n SlackMultiStaticSelectElement,\n SlackOptionGroup,\n SlackOptionObject,\n SlackOverflowElement,\n SlackPlainTextObject,\n SlackRadioButtonsElement,\n SlackRawTextElement,\n SlackRichTextBlock,\n SlackRichTextBlockElement,\n SlackRichTextInline,\n SlackRichTextLink,\n SlackRichTextList,\n SlackRichTextPreformatted,\n SlackRichTextQuote,\n SlackRichTextSection,\n SlackRichTextStyle,\n SlackRichTextTag,\n SlackRichTextText,\n SlackSectionAccessory,\n SlackSectionBlock,\n SlackStaticSelectElement,\n SlackTableBlock,\n SlackTableCell,\n SlackTableColumnSetting,\n SlackTagColor,\n SlackTextObject,\n SlackVideoBlock,\n} from '../../define/slack_blocks';\n\n/**\n * Slack's published surface limits, enforced by the renderer so a composition\n * cannot silently trip Slack's validation.\n */\nexport const SLACK_LIMITS = {\n blocksPerMessage: 50,\n /** `section.text`. */\n sectionTextChars: 3000,\n /** One entry of `section.fields`. */\n sectionFieldChars: 2000,\n /** One entry of `context.elements`. */\n contextElementChars: 2000,\n /** `header.text`, which is `plain_text`. */\n headerTextChars: 150,\n fieldsPerSection: 10,\n /** Elements per `context` block. */\n contextElements: 10,\n buttonsPerActions: 25,\n /** Slack truncates the top-level `text` fallback in notifications around here. */\n fallbackTextChars: 4000,\n /** `plain_text` option labels (selects, radio, checkboxes, overflow). */\n optionTextChars: 75,\n /** Options per select, or per option group of one. */\n optionsPerSelect: 100,\n /** Options per overflow menu (Slack caps overflow at 5). */\n optionsPerOverflow: 5,\n /** Options per radio button group or checkboxes element. */\n optionsPerChoice: 10,\n /** Option groups per select, each holding up to `optionsPerSelect` options. */\n optionGroupsPerSelect: 100,\n /** An option's `value`, which interactions send back. */\n optionValueChars: 150,\n /** A button's `value`. */\n buttonValueChars: 2000,\n /** A button's or overflow option's `url`. */\n urlChars: 3000,\n /** An interactive element's `action_id`. */\n actionIdChars: 255,\n /** Max indent level for `rich_text_list`. */\n richTextListMaxIndent: 8,\n /**\n * Characters across every table cell in one message. Slack publishes the\n * same 10,000 figure per table and per message, so the message-wide\n * aggregate is the binding one.\n * https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\n tableCellCharsPerMessage: 10_000,\n /** Rows per `table` block (includes the header row). */\n tableRows: 100,\n /** Cells per `table` row / columns per table. */\n tableColumns: 20,\n /** `image`/image-element `image_url` max length. */\n imageUrlChars: 3000,\n /** `image`/image-element `alt_text` max length. */\n imageAltTextChars: 2000,\n /** `image` block `title`. */\n imageTitleChars: 2000,\n /** `video` block `title`; Slack requires fewer than 200. */\n videoTitleChars: 199,\n /** `video` block `description`; Slack requires fewer than 200. */\n videoDescriptionChars: 199,\n /** `video` block `author_name`; Slack requires fewer than 50. */\n videoAuthorNameChars: 49,\n /** `button` element `text`. */\n buttonTextChars: 75,\n /** Select `placeholder`. */\n placeholderChars: 150,\n /** `option_groups[].label`. */\n optionGroupLabelChars: 75,\n} as const;\n"]}
1
+ {"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../../src/render/slack/blocks.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA+CH;;;GAGG;AACU,QAAA,YAAY,GAAG;IAC1B,qEAAqE;IACrE,gBAAgB,EAAE,EAAE;IACpB,gDAAgD;IAChD,mBAAmB,EAAE,GAAG;IACxB,4BAA4B;IAC5B,sBAAsB,EAAE,GAAG;IAC3B,kEAAkE;IAClE,oBAAoB,EAAE,EAAE;IACxB,sBAAsB;IACtB,gBAAgB,EAAE,IAAI;IACtB,qCAAqC;IACrC,iBAAiB,EAAE,IAAI;IACvB,uCAAuC;IACvC,mBAAmB,EAAE,IAAI;IACzB,4CAA4C;IAC5C,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,EAAE;IACpB,oCAAoC;IACpC,eAAe,EAAE,EAAE;IACnB,iBAAiB,EAAE,EAAE;IACrB,kFAAkF;IAClF,iBAAiB,EAAE,IAAI;IACvB,yEAAyE;IACzE,eAAe,EAAE,EAAE;IACnB,sDAAsD;IACtD,gBAAgB,EAAE,GAAG;IACrB,4DAA4D;IAC5D,kBAAkB,EAAE,CAAC;IACrB,4DAA4D;IAC5D,gBAAgB,EAAE,EAAE;IACpB,+EAA+E;IAC/E,qBAAqB,EAAE,GAAG;IAC1B,yDAAyD;IACzD,gBAAgB,EAAE,GAAG;IACrB,0BAA0B;IAC1B,gBAAgB,EAAE,IAAI;IACtB,6CAA6C;IAC7C,QAAQ,EAAE,IAAI;IACd,4CAA4C;IAC5C,aAAa,EAAE,GAAG;IAClB,6CAA6C;IAC7C,qBAAqB,EAAE,CAAC;IACxB;;;;;OAKG;IACH,wBAAwB,EAAE,MAAM;IAChC,wDAAwD;IACxD,SAAS,EAAE,GAAG;IACd,iDAAiD;IACjD,YAAY,EAAE,EAAE;IAChB,oDAAoD;IACpD,aAAa,EAAE,IAAI;IACnB,mDAAmD;IACnD,iBAAiB,EAAE,IAAI;IACvB,6BAA6B;IAC7B,eAAe,EAAE,IAAI;IACrB,4DAA4D;IAC5D,eAAe,EAAE,GAAG;IACpB,kEAAkE;IAClE,qBAAqB,EAAE,GAAG;IAC1B,iEAAiE;IACjE,oBAAoB,EAAE,EAAE;IACxB,+BAA+B;IAC/B,eAAe,EAAE,EAAE;IACnB,4BAA4B;IAC5B,gBAAgB,EAAE,GAAG;IACrB,+BAA+B;IAC/B,qBAAqB,EAAE,EAAE;CACjB,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nexport type {\n SlackActionElement,\n SlackActionsBlock,\n SlackBlock,\n SlackButtonElement,\n SlackCheckboxesElement,\n SlackContainerBlock,\n SlackContainerChildBlock,\n SlackContextBlock,\n SlackDividerBlock,\n SlackFileReference,\n SlackHeaderBlock,\n SlackHeaderLevel,\n SlackImageBlock,\n SlackImageElement,\n SlackMrkdwnTextObject,\n SlackMultiStaticSelectElement,\n SlackOptionGroup,\n SlackOptionObject,\n SlackOverflowElement,\n SlackPlainTextObject,\n SlackRadioButtonsElement,\n SlackRawTextElement,\n SlackRichTextBlock,\n SlackRichTextBlockElement,\n SlackRichTextInline,\n SlackRichTextLink,\n SlackRichTextList,\n SlackRichTextPreformatted,\n SlackRichTextQuote,\n SlackRichTextSection,\n SlackRichTextStyle,\n SlackRichTextTag,\n SlackRichTextText,\n SlackSectionAccessory,\n SlackSectionBlock,\n SlackStaticSelectElement,\n SlackTableBlock,\n SlackTableCell,\n SlackTableColumnSetting,\n SlackTagColor,\n SlackTextObject,\n SlackVideoBlock,\n} from '../../define/slack_blocks';\n\n/**\n * Slack's published surface limits, enforced by the renderer so a composition\n * cannot silently trip Slack's validation.\n */\nexport const SLACK_LIMITS = {\n /** Top-level blocks; a `container`'s `child_blocks` do not count. */\n blocksPerMessage: 50,\n /** `container.title`, which is `plain_text`. */\n containerTitleChars: 150,\n /** `container.subtitle`. */\n containerSubtitleChars: 150,\n /** `container.child_blocks`; Slack also requires at least one. */\n containerChildBlocks: 10,\n /** `section.text`. */\n sectionTextChars: 3000,\n /** One entry of `section.fields`. */\n sectionFieldChars: 2000,\n /** One entry of `context.elements`. */\n contextElementChars: 2000,\n /** `header.text`, which is `plain_text`. */\n headerTextChars: 150,\n fieldsPerSection: 10,\n /** Elements per `context` block. */\n contextElements: 10,\n buttonsPerActions: 25,\n /** Slack truncates the top-level `text` fallback in notifications around here. */\n fallbackTextChars: 4000,\n /** `plain_text` option labels (selects, radio, checkboxes, overflow). */\n optionTextChars: 75,\n /** Options per select, or per option group of one. */\n optionsPerSelect: 100,\n /** Options per overflow menu (Slack caps overflow at 5). */\n optionsPerOverflow: 5,\n /** Options per radio button group or checkboxes element. */\n optionsPerChoice: 10,\n /** Option groups per select, each holding up to `optionsPerSelect` options. */\n optionGroupsPerSelect: 100,\n /** An option's `value`, which interactions send back. */\n optionValueChars: 150,\n /** A button's `value`. */\n buttonValueChars: 2000,\n /** A button's or overflow option's `url`. */\n urlChars: 3000,\n /** An interactive element's `action_id`. */\n actionIdChars: 255,\n /** Max indent level for `rich_text_list`. */\n richTextListMaxIndent: 8,\n /**\n * Characters across every table cell in one message. Slack publishes the\n * same 10,000 figure per table and per message, so the message-wide\n * aggregate is the binding one.\n * https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\n tableCellCharsPerMessage: 10_000,\n /** Rows per `table` block (includes the header row). */\n tableRows: 100,\n /** Cells per `table` row / columns per table. */\n tableColumns: 20,\n /** `image`/image-element `image_url` max length. */\n imageUrlChars: 3000,\n /** `image`/image-element `alt_text` max length. */\n imageAltTextChars: 2000,\n /** `image` block `title`. */\n imageTitleChars: 2000,\n /** `video` block `title`; Slack requires fewer than 200. */\n videoTitleChars: 199,\n /** `video` block `description`; Slack requires fewer than 200. */\n videoDescriptionChars: 199,\n /** `video` block `author_name`; Slack requires fewer than 50. */\n videoAuthorNameChars: 49,\n /** `button` element `text`. */\n buttonTextChars: 75,\n /** Select `placeholder`. */\n placeholderChars: 150,\n /** `option_groups[].label`. */\n optionGroupLabelChars: 75,\n} as const;\n"]}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
4
+ * or more contributor license agreements. Licensed under the Elastic License
5
+ * 2.0; you may not use this file except in compliance with the Elastic License
6
+ * 2.0.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.slackContainer = exports.containerWithChildren = exports.unwrapContainer = exports.isContainer = void 0;
10
+ const blocks_1 = require("./blocks");
11
+ const format_1 = require("./format");
12
+ const unmodeled_1 = require("./unmodeled");
13
+ /** A container Isomer fits, as opposed to one passed through `unmodeledSlackBlock`. */
14
+ const isContainer = (block) => block.type === 'container' && !(0, unmodeled_1.isUnmodeledSlackBlock)(block);
15
+ exports.isContainer = isContainer;
16
+ /** A container as the blocks it holds, led by its title and subtitle. */
17
+ const unwrapContainer = ({ title, rich_text_title, subtitle, child_blocks }, level) => [
18
+ ...(rich_text_title
19
+ ? [rich_text_title]
20
+ : title
21
+ ? [
22
+ {
23
+ type: 'header',
24
+ text: title,
25
+ ...(level === undefined ? {} : { level }),
26
+ },
27
+ ]
28
+ : []),
29
+ ...(subtitle ? [{ type: 'context', elements: [subtitle] }] : []),
30
+ ...child_blocks,
31
+ ];
32
+ exports.unwrapContainer = unwrapContainer;
33
+ /**
34
+ * `container` holding `children`, with any nested container unwrapped, since
35
+ * Slack rejects one. A container left with no children, or more than
36
+ * `containerChildBlocks`, is unwrapped itself.
37
+ */
38
+ const containerWithChildren = (container, children, level) => {
39
+ const child_blocks = children.flatMap((child) => (0, exports.isContainer)(child) ? (0, exports.unwrapContainer)(child) : [child]);
40
+ const refitted = { ...container, child_blocks };
41
+ return child_blocks.length === 0 ||
42
+ child_blocks.length > blocks_1.SLACK_LIMITS.containerChildBlocks
43
+ ? (0, exports.unwrapContainer)(refitted, level)
44
+ : [refitted];
45
+ };
46
+ exports.containerWithChildren = containerWithChildren;
47
+ /**
48
+ * A titled section as one Block Kit `container`, from its title and the
49
+ * blocks its body rendered to, typically through `scope.renderSlack`.
50
+ *
51
+ * A nested container among `children` is unwrapped to its title and blocks.
52
+ * With no children, or more than `SLACK_LIMITS.containerChildBlocks`, the
53
+ * section falls back to a `header` at `fallbackLevel` followed by the blocks.
54
+ */
55
+ const slackContainer = (title, children, { fallbackLevel, ...fields } = {}) => (0, exports.containerWithChildren)({
56
+ type: 'container',
57
+ title: { type: 'plain_text', text: (0, format_1.formatHeaderText)(title), emoji: true },
58
+ ...fields,
59
+ child_blocks: [],
60
+ }, children, fallbackLevel);
61
+ exports.slackContainer = slackContainer;
62
+ //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../../../../src/render/slack/container.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,qCAMkB;AAClB,qCAA4C;AAC5C,2CAAoD;AAgBpD,uFAAuF;AAChF,MAAM,WAAW,GAAG,CAAC,KAAiB,EAAgC,EAAE,CAC7E,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,IAAA,iCAAqB,EAAC,KAAK,CAAC,CAAC;AADjD,QAAA,WAAW,eACsC;AAE9D,yEAAyE;AAClE,MAAM,eAAe,GAAG,CAC7B,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAuB,EACvE,KAAwB,EACI,EAAE,CAAC;IAC/B,GAAG,CAAC,eAAe;QACjB,CAAC,CAAC,CAAC,eAAe,CAAC;QACnB,CAAC,CAAC,KAAK;YACL,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,QAAiB;oBACvB,IAAI,EAAE,KAAK;oBACX,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;iBAC1C;aACF;YACH,CAAC,CAAC,EAAE,CAAC;IACT,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAkB,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,GAAG,YAAY;CAChB,CAAC;AAjBW,QAAA,eAAe,mBAiB1B;AAEF;;;;GAIG;AACI,MAAM,qBAAqB,GAAG,CACnC,SAA8B,EAC9B,QAA+B,EAC/B,KAAwB,EACV,EAAE;IAChB,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC9C,IAAA,mBAAW,EAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAA,uBAAe,EAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CACtD,CAAC;IACF,MAAM,QAAQ,GAAG,EAAE,GAAG,SAAS,EAAE,YAAY,EAAE,CAAC;IAChD,OAAO,YAAY,CAAC,MAAM,KAAK,CAAC;QAC9B,YAAY,CAAC,MAAM,GAAG,qBAAY,CAAC,oBAAoB;QACvD,CAAC,CAAC,IAAA,uBAAe,EAAC,QAAQ,EAAE,KAAK,CAAC;QAClC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AACjB,CAAC,CAAC;AAbW,QAAA,qBAAqB,yBAahC;AAEF;;;;;;;GAOG;AACI,MAAM,cAAc,GAAG,CAC5B,KAAa,EACb,QAA+B,EAC/B,EAAE,aAAa,EAAE,GAAG,MAAM,KAA4B,EAAE,EAC1C,EAAE,CAChB,IAAA,6BAAqB,EACnB;IACE,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAA,yBAAgB,EAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;IACzE,GAAG,MAAM;IACT,YAAY,EAAE,EAAE;CACjB,EACD,QAAQ,EACR,aAAa,CACd,CAAC;AAdS,QAAA,cAAc,kBAcvB","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nimport {\n SLACK_LIMITS,\n type SlackBlock,\n type SlackContainerBlock,\n type SlackContainerChildBlock,\n type SlackHeaderLevel,\n} from './blocks';\nimport { formatHeaderText } from './format';\nimport { isUnmodeledSlackBlock } from './unmodeled';\n\n/** Options for {@link slackContainer}: the container's optional fields, and the level of the `header` it falls back to. */\nexport type SlackContainerOptions = Partial<\n Pick<\n SlackContainerBlock,\n | 'block_id'\n | 'subtitle'\n | 'icon'\n | 'width'\n | 'is_collapsible'\n | 'default_collapsed'\n | 'has_header_divider'\n >\n> & { fallbackLevel?: SlackHeaderLevel };\n\n/** A container Isomer fits, as opposed to one passed through `unmodeledSlackBlock`. */\nexport const isContainer = (block: SlackBlock): block is SlackContainerBlock =>\n block.type === 'container' && !isUnmodeledSlackBlock(block);\n\n/** A container as the blocks it holds, led by its title and subtitle. */\nexport const unwrapContainer = (\n { title, rich_text_title, subtitle, child_blocks }: SlackContainerBlock,\n level?: SlackHeaderLevel\n): SlackContainerChildBlock[] => [\n ...(rich_text_title\n ? [rich_text_title]\n : title\n ? [\n {\n type: 'header' as const,\n text: title,\n ...(level === undefined ? {} : { level }),\n },\n ]\n : []),\n ...(subtitle ? [{ type: 'context' as const, elements: [subtitle] }] : []),\n ...child_blocks,\n];\n\n/**\n * `container` holding `children`, with any nested container unwrapped, since\n * Slack rejects one. A container left with no children, or more than\n * `containerChildBlocks`, is unwrapped itself.\n */\nexport const containerWithChildren = (\n container: SlackContainerBlock,\n children: readonly SlackBlock[],\n level?: SlackHeaderLevel\n): SlackBlock[] => {\n const child_blocks = children.flatMap((child) =>\n isContainer(child) ? unwrapContainer(child) : [child]\n );\n const refitted = { ...container, child_blocks };\n return child_blocks.length === 0 ||\n child_blocks.length > SLACK_LIMITS.containerChildBlocks\n ? unwrapContainer(refitted, level)\n : [refitted];\n};\n\n/**\n * A titled section as one Block Kit `container`, from its title and the\n * blocks its body rendered to, typically through `scope.renderSlack`.\n *\n * A nested container among `children` is unwrapped to its title and blocks.\n * With no children, or more than `SLACK_LIMITS.containerChildBlocks`, the\n * section falls back to a `header` at `fallbackLevel` followed by the blocks.\n */\nexport const slackContainer = (\n title: string,\n children: readonly SlackBlock[],\n { fallbackLevel, ...fields }: SlackContainerOptions = {}\n): SlackBlock[] =>\n containerWithChildren(\n {\n type: 'container',\n title: { type: 'plain_text', text: formatHeaderText(title), emoji: true },\n ...fields,\n child_blocks: [],\n },\n children,\n fallbackLevel\n );\n"]}
@@ -10,7 +10,9 @@ exports.renderSlackEnvelope = void 0;
10
10
  const envelope_1 = require("../text/envelope");
11
11
  const assets_1 = require("./assets");
12
12
  const blocks_1 = require("./blocks");
13
+ const container_1 = require("./container");
13
14
  const format_1 = require("./format");
15
+ const unmodeled_1 = require("./unmodeled");
14
16
  /**
15
17
  * The composition as a `chat.postMessage` payload: notification `text`, blocks,
16
18
  * and the images the host must upload first.
@@ -20,8 +22,9 @@ const format_1 = require("./format");
20
22
  * fitted to Slack's limits — text is clamped, blocks past a count limit and
21
23
  * `rich_text` elements past a section's limit split, tables past a table limit
22
24
  * or the message's cell budget become rich text, spacers and then whole blocks
23
- * are dropped — so the output is always postable. `assets` stays empty
24
- * unless `collectAssets` is set.
25
+ * are dropped — so the output is always postable, except for a block from
26
+ * `unmodeledSlackBlock` or of a type Isomer does not model, which passes
27
+ * through unfitted. `assets` stays empty unless `collectAssets` is set.
25
28
  */
26
29
  const renderSlackEnvelope = (composition, dispatcher, options = {}) => {
27
30
  const blocks = [];
@@ -31,15 +34,17 @@ const renderSlackEnvelope = (composition, dispatcher, options = {}) => {
31
34
  const collector = options.collectAssets
32
35
  ? (0, assets_1.createSlackAssetCollector)(options.assetPrefix === undefined ? {} : { prefix: options.assetPrefix })
33
36
  : undefined;
34
- const { heading = true } = options;
37
+ const { heading = true, baseUrl } = options;
38
+ (0, format_1.assertSlackBaseUrl)(baseUrl);
35
39
  if (heading && composition.title) {
36
40
  blocks.push(headerBlock(composition.title, 1));
37
41
  }
38
42
  if (heading && composition.subtitle) {
39
43
  blocks.push(contextBlock([(0, format_1.escapeMrkdwn)(composition.subtitle)]));
40
44
  }
45
+ const linkOptions = baseUrl === undefined ? {} : { baseUrl };
41
46
  for (const node of composition.body) {
42
- blocks.push(...dispatcher.renderSlack(node, collector).flatMap(fitBlock));
47
+ blocks.push(...dispatcher.renderSlack(node, collector, linkOptions).flatMap(fitBlock));
43
48
  }
44
49
  // Split after the rhythm, so the fragments of one block read as one.
45
50
  const rhythm = applySectionRhythm(coalesceFieldSections(enforceTableLimits(blocks))).flatMap(splitBlockCounts);
@@ -159,7 +164,12 @@ const chunks = (items, size) => Array.from({ length: Math.ceil(items.length / si
159
164
  // Splits a block past a count limit into blocks of its type. Only the first
160
165
  // keeps a `block_id`, which Slack requires to be unique.
161
166
  const splitBlockCounts = (block) => {
167
+ if ((0, unmodeled_1.isUnmodeledSlackBlock)(block)) {
168
+ return [block];
169
+ }
162
170
  switch (block.type) {
171
+ case 'container':
172
+ return (0, container_1.containerWithChildren)(block, block.child_blocks.flatMap(splitBlockCounts));
163
173
  case 'context':
164
174
  return chunks(block.elements, blocks_1.SLACK_LIMITS.contextElements).map((elements, index) => index === 0 ? { ...block, elements } : { type: 'context', elements });
165
175
  case 'actions':
@@ -208,7 +218,39 @@ const fitImageUrls = (block) => {
208
218
  return [block];
209
219
  }
210
220
  };
211
- const fitBlock = (block) => fitImageUrls(block).map(clampBlockText);
221
+ const fitBlock = (block) => {
222
+ if ((0, unmodeled_1.isUnmodeledSlackBlock)(block)) {
223
+ return [block];
224
+ }
225
+ return block.type === 'container'
226
+ ? fitContainer(block)
227
+ : fitImageUrls(block).map(clampBlockText);
228
+ };
229
+ const fitContainer = (container) => {
230
+ const { title, rich_text_title, subtitle, icon, child_blocks } = container;
231
+ const fitted = {
232
+ ...container,
233
+ ...(title && {
234
+ title: clampText(title, blocks_1.SLACK_LIMITS.containerTitleChars),
235
+ }),
236
+ ...(rich_text_title && {
237
+ rich_text_title: {
238
+ ...rich_text_title,
239
+ elements: rich_text_title.elements.flatMap(splitRichTextElement),
240
+ },
241
+ }),
242
+ ...(subtitle && {
243
+ subtitle: clampText(subtitle, blocks_1.SLACK_LIMITS.containerSubtitleChars),
244
+ }),
245
+ };
246
+ if (icon && fitsImageUrl(icon)) {
247
+ fitted.icon = clampAlt(icon);
248
+ }
249
+ else {
250
+ delete fitted.icon;
251
+ }
252
+ return (0, container_1.containerWithChildren)(fitted, child_blocks.flatMap(fitBlock));
253
+ };
212
254
  // Pack renderers build their own blocks, and one overlong text makes Slack
213
255
  // reject the whole message.
214
256
  const clampBlockText = (block) => {
@@ -271,11 +313,15 @@ const clampBlockText = (block) => {
271
313
  };
272
314
  const collectSlackFileRefs = (blocks) => {
273
315
  const refs = new Set();
274
- for (const block of blocks) {
316
+ const visit = (block) => {
275
317
  if (block.type === 'image' && block.slack_file?.ref !== undefined) {
276
318
  refs.add(block.slack_file.ref);
277
319
  }
278
- }
320
+ else if ((0, container_1.isContainer)(block)) {
321
+ block.child_blocks.forEach(visit);
322
+ }
323
+ };
324
+ blocks.forEach(visit);
279
325
  return refs;
280
326
  };
281
327
  const headerBlock = (title, level) => ({
@@ -297,16 +343,20 @@ const slackSpacerBlock = () => ({
297
343
  type: 'section',
298
344
  text: { type: 'mrkdwn', text: SLACK_SPACER_TEXT },
299
345
  });
300
- const isSpacer = (block) => block.type === 'section' &&
346
+ const isSpacer = (block) => !(0, unmodeled_1.isUnmodeledSlackBlock)(block) &&
347
+ block.type === 'section' &&
301
348
  block.text?.type === 'mrkdwn' &&
302
349
  block.text.text === SLACK_SPACER_TEXT &&
303
350
  block.fields === undefined &&
304
351
  block.accessory === undefined;
305
- const isFieldsOnly = (block) => block.type === 'section' &&
352
+ const isFieldsOnly = (block) => !(0, unmodeled_1.isUnmodeledSlackBlock)(block) &&
353
+ block.type === 'section' &&
306
354
  (block.fields?.length ?? 0) > 0 &&
307
355
  block.text === undefined &&
308
356
  block.accessory === undefined;
309
- const isContent = (block) => block.type !== 'header' &&
357
+ // A container sets itself apart, so no spacer goes beside it.
358
+ const isContent = (block) => block.type !== 'container' &&
359
+ block.type !== 'header' &&
310
360
  block.type !== 'divider' &&
311
361
  block.type !== 'actions' &&
312
362
  block.type !== 'context' &&
@@ -335,7 +385,9 @@ const coalesceFieldSections = (blocks) => {
335
385
  out.push({ type: 'section', fields });
336
386
  continue;
337
387
  }
338
- out.push(block);
388
+ out.push(...((0, container_1.isContainer)(block)
389
+ ? (0, container_1.containerWithChildren)(block, coalesceFieldSections(block.child_blocks))
390
+ : [block]));
339
391
  index += 1;
340
392
  }
341
393
  return out;
@@ -520,8 +572,11 @@ const fitsTableShape = ({ rows }) => rows.length > 0 &&
520
572
  // kept ones left.
521
573
  const enforceTableLimits = (blocks) => {
522
574
  let spent = 0;
523
- return blocks.flatMap((block) => {
524
- if (block.type !== 'table') {
575
+ const fit = (block) => {
576
+ if ((0, container_1.isContainer)(block)) {
577
+ return (0, container_1.containerWithChildren)(block, block.child_blocks.flatMap(fit));
578
+ }
579
+ if (block.type !== 'table' || (0, unmodeled_1.isUnmodeledSlackBlock)(block)) {
525
580
  return [block];
526
581
  }
527
582
  const cost = tableCharCount(block);
@@ -531,7 +586,8 @@ const enforceTableLimits = (blocks) => {
531
586
  return [block];
532
587
  }
533
588
  return degradeTable(block);
534
- });
589
+ };
590
+ return blocks.flatMap(fit);
535
591
  };
536
592
  const enforceBlockBudget = (blocks) => {
537
593
  if (blocks.length <= blocks_1.SLACK_LIMITS.blocksPerMessage) {