@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.
- package/NOTICE.txt +0 -286
- package/THIRD_PARTY_LICENSES.md +1 -885
- package/dist/author/authored_fields.d.ts +37 -12
- package/dist/author/authored_fields.d.ts.map +1 -1
- package/dist/author/authored_fields.js +45 -69
- package/dist/author/authored_fields.js.map +1 -1
- package/dist/author/authoring_input.d.ts.map +1 -1
- package/dist/author/authoring_input.js +12 -6
- package/dist/author/authoring_input.js.map +1 -1
- package/dist/author/authoring_model.d.ts +8 -2
- package/dist/author/authoring_model.d.ts.map +1 -1
- package/dist/author/authoring_model.js +67 -23
- package/dist/author/authoring_model.js.map +1 -1
- package/dist/author/declarations.d.ts.map +1 -1
- package/dist/author/declarations.js +45 -34
- package/dist/author/declarations.js.map +1 -1
- package/dist/author/index.d.ts +2 -1
- package/dist/author/index.d.ts.map +1 -1
- package/dist/author/index.js +2 -1
- package/dist/author/index.js.map +1 -1
- package/dist/author/jsx_shim.d.ts +49 -30
- package/dist/author/jsx_shim.d.ts.map +1 -1
- package/dist/author/jsx_shim.js +131 -40
- package/dist/author/jsx_shim.js.map +1 -1
- package/dist/author/print_jsx.d.ts +19 -0
- package/dist/author/print_jsx.d.ts.map +1 -0
- package/dist/author/print_jsx.js +372 -0
- package/dist/author/print_jsx.js.map +1 -0
- package/dist/author/prompt.d.ts +2 -2
- package/dist/author/prompt.d.ts.map +1 -1
- package/dist/author/prompt.js +7 -2
- package/dist/author/prompt.js.map +1 -1
- package/dist/author/schema_to_typescript.d.ts.map +1 -1
- package/dist/author/schema_to_typescript.js +6 -3
- package/dist/author/schema_to_typescript.js.map +1 -1
- package/dist/cjs/author/authored_fields.js +47 -70
- package/dist/cjs/author/authored_fields.js.map +1 -1
- package/dist/cjs/author/authoring_input.js +12 -6
- package/dist/cjs/author/authoring_input.js.map +1 -1
- package/dist/cjs/author/authoring_model.js +69 -24
- package/dist/cjs/author/authoring_model.js.map +1 -1
- package/dist/cjs/author/declarations.js +44 -33
- package/dist/cjs/author/declarations.js.map +1 -1
- package/dist/cjs/author/index.js +5 -1
- package/dist/cjs/author/index.js.map +1 -1
- package/dist/cjs/author/jsx_shim.js +130 -39
- package/dist/cjs/author/jsx_shim.js.map +1 -1
- package/dist/cjs/author/print_jsx.js +378 -0
- package/dist/cjs/author/print_jsx.js.map +1 -0
- package/dist/cjs/author/prompt.js +7 -2
- package/dist/cjs/author/prompt.js.map +1 -1
- package/dist/cjs/author/schema_to_typescript.js +6 -3
- package/dist/cjs/author/schema_to_typescript.js.map +1 -1
- package/dist/cjs/composition/error.js +2 -0
- package/dist/cjs/composition/error.js.map +1 -1
- package/dist/cjs/composition/structured_value.js.map +1 -1
- package/dist/cjs/define/index.js.map +1 -1
- package/dist/cjs/define/primitive_module.js +10 -4
- package/dist/cjs/define/primitive_module.js.map +1 -1
- package/dist/cjs/define/slack_blocks.js.map +1 -1
- package/dist/cjs/entries/index.js +5 -2
- package/dist/cjs/entries/index.js.map +1 -1
- package/dist/cjs/entries/markdown.js +3 -1
- package/dist/cjs/entries/markdown.js.map +1 -1
- package/dist/cjs/entries/react.js +2 -1
- package/dist/cjs/entries/react.js.map +1 -1
- package/dist/cjs/entries/slack.js +5 -1
- package/dist/cjs/entries/slack.js.map +1 -1
- package/dist/cjs/pack/enhancements.js.map +1 -1
- package/dist/cjs/pack/index.js +2 -1
- package/dist/cjs/pack/index.js.map +1 -1
- package/dist/cjs/pack/primitive_pack.js +14 -4
- package/dist/cjs/pack/primitive_pack.js.map +1 -1
- package/dist/cjs/render/format_number.js +2 -1
- package/dist/cjs/render/format_number.js.map +1 -1
- package/dist/cjs/render/html/envelope.js +12 -6
- package/dist/cjs/render/html/envelope.js.map +1 -1
- package/dist/cjs/render/markdown/blocks.js +82 -0
- package/dist/cjs/render/markdown/blocks.js.map +1 -0
- package/dist/cjs/render/markdown/builder.js +6 -2
- package/dist/cjs/render/markdown/builder.js.map +1 -1
- package/dist/cjs/render/markdown/format.js +46 -24
- package/dist/cjs/render/markdown/format.js.map +1 -1
- package/dist/cjs/render/markdown/host_tags.js +67 -0
- package/dist/cjs/render/markdown/host_tags.js.map +1 -0
- package/dist/cjs/render/markdown/index.js +5 -1
- package/dist/cjs/render/markdown/index.js.map +1 -1
- package/dist/cjs/render/markdown/split.js +325 -0
- package/dist/cjs/render/markdown/split.js.map +1 -0
- package/dist/cjs/render/primitive_dispatch.js +36 -6
- package/dist/cjs/render/primitive_dispatch.js.map +1 -1
- package/dist/cjs/render/react/content.js +3 -1
- package/dist/cjs/render/react/content.js.map +1 -1
- package/dist/cjs/render/react/index.js +3 -1
- package/dist/cjs/render/react/index.js.map +1 -1
- package/dist/cjs/render/react/markdown_content.js +143 -0
- package/dist/cjs/render/react/markdown_content.js.map +1 -0
- package/dist/cjs/render/slack/blocks.js +7 -0
- package/dist/cjs/render/slack/blocks.js.map +1 -1
- package/dist/cjs/render/slack/container.js +62 -0
- package/dist/cjs/render/slack/container.js.map +1 -0
- package/dist/cjs/render/slack/envelope.js +70 -14
- package/dist/cjs/render/slack/envelope.js.map +1 -1
- package/dist/cjs/render/slack/format.js +56 -6
- package/dist/cjs/render/slack/format.js.map +1 -1
- package/dist/cjs/render/slack/index.js +7 -1
- package/dist/cjs/render/slack/index.js.map +1 -1
- package/dist/cjs/render/slack/markdown_content.js +36 -77
- package/dist/cjs/render/slack/markdown_content.js.map +1 -1
- package/dist/cjs/render/slack/unmodeled.js +38 -0
- package/dist/cjs/render/slack/unmodeled.js.map +1 -0
- package/dist/cjs/testing/conformance.js +15 -1
- package/dist/cjs/testing/conformance.js.map +1 -1
- package/dist/cjs/testing/index.js +2 -1
- package/dist/cjs/testing/index.js.map +1 -1
- package/dist/cjs/validate/json_schema.js +10 -3
- package/dist/cjs/validate/json_schema.js.map +1 -1
- package/dist/cjs/validate/url.js +2 -1
- package/dist/cjs/validate/url.js.map +1 -1
- package/dist/composition/error.d.ts +2 -0
- package/dist/composition/error.d.ts.map +1 -1
- package/dist/composition/error.js +2 -0
- package/dist/composition/error.js.map +1 -1
- package/dist/composition/structured_value.d.ts +3 -3
- package/dist/composition/structured_value.d.ts.map +1 -1
- package/dist/composition/structured_value.js.map +1 -1
- package/dist/define/index.d.ts +1 -1
- package/dist/define/index.d.ts.map +1 -1
- package/dist/define/index.js.map +1 -1
- package/dist/define/primitive_module.d.ts +14 -5
- package/dist/define/primitive_module.d.ts.map +1 -1
- package/dist/define/primitive_module.js +10 -4
- package/dist/define/primitive_module.js.map +1 -1
- package/dist/define/slack_blocks.d.ts +31 -1
- package/dist/define/slack_blocks.d.ts.map +1 -1
- package/dist/define/slack_blocks.js.map +1 -1
- package/dist/entries/index.d.ts +2 -2
- package/dist/entries/index.d.ts.map +1 -1
- package/dist/entries/index.js +2 -2
- package/dist/entries/index.js.map +1 -1
- package/dist/entries/markdown.d.ts +1 -1
- package/dist/entries/markdown.d.ts.map +1 -1
- package/dist/entries/markdown.js +1 -1
- package/dist/entries/markdown.js.map +1 -1
- package/dist/entries/react.d.ts +1 -1
- package/dist/entries/react.d.ts.map +1 -1
- package/dist/entries/react.js +1 -1
- package/dist/entries/react.js.map +1 -1
- package/dist/entries/slack.d.ts +1 -1
- package/dist/entries/slack.d.ts.map +1 -1
- package/dist/entries/slack.js +1 -1
- package/dist/entries/slack.js.map +1 -1
- package/dist/pack/enhancements.d.ts +4 -0
- package/dist/pack/enhancements.d.ts.map +1 -1
- package/dist/pack/enhancements.js.map +1 -1
- package/dist/pack/index.d.ts +1 -1
- package/dist/pack/index.d.ts.map +1 -1
- package/dist/pack/index.js +1 -1
- package/dist/pack/index.js.map +1 -1
- package/dist/pack/primitive_pack.d.ts +3 -1
- package/dist/pack/primitive_pack.d.ts.map +1 -1
- package/dist/pack/primitive_pack.js +13 -3
- package/dist/pack/primitive_pack.js.map +1 -1
- package/dist/render/format_number.d.ts.map +1 -1
- package/dist/render/format_number.js +2 -1
- package/dist/render/format_number.js.map +1 -1
- package/dist/render/html/envelope.js +12 -6
- package/dist/render/html/envelope.js.map +1 -1
- package/dist/render/markdown/blocks.d.ts +6 -0
- package/dist/render/markdown/blocks.d.ts.map +1 -0
- package/dist/render/markdown/blocks.js +77 -0
- package/dist/render/markdown/blocks.js.map +1 -0
- package/dist/render/markdown/builder.d.ts +3 -0
- package/dist/render/markdown/builder.d.ts.map +1 -1
- package/dist/render/markdown/builder.js +3 -1
- package/dist/render/markdown/builder.js.map +1 -1
- package/dist/render/markdown/format.d.ts +2 -0
- package/dist/render/markdown/format.d.ts.map +1 -1
- package/dist/render/markdown/format.js +42 -22
- package/dist/render/markdown/format.js.map +1 -1
- package/dist/render/markdown/host_tags.d.ts +14 -0
- package/dist/render/markdown/host_tags.d.ts.map +1 -0
- package/dist/render/markdown/host_tags.js +63 -0
- package/dist/render/markdown/host_tags.js.map +1 -0
- package/dist/render/markdown/index.d.ts +2 -0
- package/dist/render/markdown/index.d.ts.map +1 -1
- package/dist/render/markdown/index.js +2 -0
- package/dist/render/markdown/index.js.map +1 -1
- package/dist/render/markdown/split.d.ts +32 -0
- package/dist/render/markdown/split.d.ts.map +1 -0
- package/dist/render/markdown/split.js +321 -0
- package/dist/render/markdown/split.js.map +1 -0
- package/dist/render/primitive_dispatch.d.ts +4 -2
- package/dist/render/primitive_dispatch.d.ts.map +1 -1
- package/dist/render/primitive_dispatch.js +36 -6
- package/dist/render/primitive_dispatch.js.map +1 -1
- package/dist/render/react/content.d.ts +1 -1
- package/dist/render/react/content.d.ts.map +1 -1
- package/dist/render/react/content.js +3 -1
- package/dist/render/react/content.js.map +1 -1
- package/dist/render/react/index.d.ts +1 -0
- package/dist/render/react/index.d.ts.map +1 -1
- package/dist/render/react/index.js +1 -0
- package/dist/render/react/index.js.map +1 -1
- package/dist/render/react/markdown_content.d.ts +9 -0
- package/dist/render/react/markdown_content.d.ts.map +1 -0
- package/dist/render/react/markdown_content.js +139 -0
- package/dist/render/react/markdown_content.js.map +1 -0
- package/dist/render/slack/blocks.d.ts +8 -1
- package/dist/render/slack/blocks.d.ts.map +1 -1
- package/dist/render/slack/blocks.js +7 -0
- package/dist/render/slack/blocks.js.map +1 -1
- package/dist/render/slack/container.d.ts +25 -0
- package/dist/render/slack/container.d.ts.map +1 -0
- package/dist/render/slack/container.js +55 -0
- package/dist/render/slack/container.js.map +1 -0
- package/dist/render/slack/envelope.d.ts +6 -4
- package/dist/render/slack/envelope.d.ts.map +1 -1
- package/dist/render/slack/envelope.js +71 -15
- package/dist/render/slack/envelope.js.map +1 -1
- package/dist/render/slack/format.d.ts +15 -3
- package/dist/render/slack/format.d.ts.map +1 -1
- package/dist/render/slack/format.js +54 -5
- package/dist/render/slack/format.js.map +1 -1
- package/dist/render/slack/index.d.ts +4 -2
- package/dist/render/slack/index.d.ts.map +1 -1
- package/dist/render/slack/index.js +2 -0
- package/dist/render/slack/index.js.map +1 -1
- package/dist/render/slack/markdown_content.d.ts +3 -2
- package/dist/render/slack/markdown_content.d.ts.map +1 -1
- package/dist/render/slack/markdown_content.js +27 -68
- package/dist/render/slack/markdown_content.js.map +1 -1
- package/dist/render/slack/unmodeled.d.ts +16 -0
- package/dist/render/slack/unmodeled.d.ts.map +1 -0
- package/dist/render/slack/unmodeled.js +32 -0
- package/dist/render/slack/unmodeled.js.map +1 -0
- package/dist/testing/conformance.d.ts +3 -1
- package/dist/testing/conformance.d.ts.map +1 -1
- package/dist/testing/conformance.js +14 -0
- package/dist/testing/conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/validate/json_schema.d.ts.map +1 -1
- package/dist/validate/json_schema.js +10 -3
- package/dist/validate/json_schema.js.map +1 -1
- package/dist/validate/url.d.ts.map +1 -1
- package/dist/validate/url.js +2 -1
- package/dist/validate/url.js.map +1 -1
- package/package.json +2 -2
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import { renderTextEnvelope } from '../text/envelope.js';
|
|
8
8
|
import { createSlackAssetCollector, } from './assets.js';
|
|
9
9
|
import { SLACK_LIMITS, } from './blocks.js';
|
|
10
|
-
import {
|
|
10
|
+
import { containerWithChildren, isContainer } from './container.js';
|
|
11
|
+
import { assertSlackBaseUrl, clampMrkdwn, clampSlackText, cutSlackValue, escapeMrkdwn, formatHeaderText, italic, } from './format.js';
|
|
12
|
+
import { isUnmodeledSlackBlock } from './unmodeled.js';
|
|
11
13
|
/**
|
|
12
14
|
* The composition as a `chat.postMessage` payload: notification `text`, blocks,
|
|
13
15
|
* and the images the host must upload first.
|
|
@@ -17,8 +19,9 @@ import { clampMrkdwn, clampSlackText, cutSlackValue, escapeMrkdwn, formatHeaderT
|
|
|
17
19
|
* fitted to Slack's limits — text is clamped, blocks past a count limit and
|
|
18
20
|
* `rich_text` elements past a section's limit split, tables past a table limit
|
|
19
21
|
* or the message's cell budget become rich text, spacers and then whole blocks
|
|
20
|
-
* are dropped — so the output is always postable
|
|
21
|
-
*
|
|
22
|
+
* are dropped — so the output is always postable, except for a block from
|
|
23
|
+
* `unmodeledSlackBlock` or of a type Isomer does not model, which passes
|
|
24
|
+
* through unfitted. `assets` stays empty unless `collectAssets` is set.
|
|
22
25
|
*/
|
|
23
26
|
export const renderSlackEnvelope = (composition, dispatcher, options = {}) => {
|
|
24
27
|
const blocks = [];
|
|
@@ -28,15 +31,17 @@ export const renderSlackEnvelope = (composition, dispatcher, options = {}) => {
|
|
|
28
31
|
const collector = options.collectAssets
|
|
29
32
|
? createSlackAssetCollector(options.assetPrefix === undefined ? {} : { prefix: options.assetPrefix })
|
|
30
33
|
: undefined;
|
|
31
|
-
const { heading = true } = options;
|
|
34
|
+
const { heading = true, baseUrl } = options;
|
|
35
|
+
assertSlackBaseUrl(baseUrl);
|
|
32
36
|
if (heading && composition.title) {
|
|
33
37
|
blocks.push(headerBlock(composition.title, 1));
|
|
34
38
|
}
|
|
35
39
|
if (heading && composition.subtitle) {
|
|
36
40
|
blocks.push(contextBlock([escapeMrkdwn(composition.subtitle)]));
|
|
37
41
|
}
|
|
42
|
+
const linkOptions = baseUrl === undefined ? {} : { baseUrl };
|
|
38
43
|
for (const node of composition.body) {
|
|
39
|
-
blocks.push(...dispatcher.renderSlack(node, collector).flatMap(fitBlock));
|
|
44
|
+
blocks.push(...dispatcher.renderSlack(node, collector, linkOptions).flatMap(fitBlock));
|
|
40
45
|
}
|
|
41
46
|
// Split after the rhythm, so the fragments of one block read as one.
|
|
42
47
|
const rhythm = applySectionRhythm(coalesceFieldSections(enforceTableLimits(blocks))).flatMap(splitBlockCounts);
|
|
@@ -155,7 +160,12 @@ const chunks = (items, size) => Array.from({ length: Math.ceil(items.length / si
|
|
|
155
160
|
// Splits a block past a count limit into blocks of its type. Only the first
|
|
156
161
|
// keeps a `block_id`, which Slack requires to be unique.
|
|
157
162
|
const splitBlockCounts = (block) => {
|
|
163
|
+
if (isUnmodeledSlackBlock(block)) {
|
|
164
|
+
return [block];
|
|
165
|
+
}
|
|
158
166
|
switch (block.type) {
|
|
167
|
+
case 'container':
|
|
168
|
+
return containerWithChildren(block, block.child_blocks.flatMap(splitBlockCounts));
|
|
159
169
|
case 'context':
|
|
160
170
|
return chunks(block.elements, SLACK_LIMITS.contextElements).map((elements, index) => index === 0 ? { ...block, elements } : { type: 'context', elements });
|
|
161
171
|
case 'actions':
|
|
@@ -204,7 +214,39 @@ const fitImageUrls = (block) => {
|
|
|
204
214
|
return [block];
|
|
205
215
|
}
|
|
206
216
|
};
|
|
207
|
-
const fitBlock = (block) =>
|
|
217
|
+
const fitBlock = (block) => {
|
|
218
|
+
if (isUnmodeledSlackBlock(block)) {
|
|
219
|
+
return [block];
|
|
220
|
+
}
|
|
221
|
+
return block.type === 'container'
|
|
222
|
+
? fitContainer(block)
|
|
223
|
+
: fitImageUrls(block).map(clampBlockText);
|
|
224
|
+
};
|
|
225
|
+
const fitContainer = (container) => {
|
|
226
|
+
const { title, rich_text_title, subtitle, icon, child_blocks } = container;
|
|
227
|
+
const fitted = {
|
|
228
|
+
...container,
|
|
229
|
+
...(title && {
|
|
230
|
+
title: clampText(title, SLACK_LIMITS.containerTitleChars),
|
|
231
|
+
}),
|
|
232
|
+
...(rich_text_title && {
|
|
233
|
+
rich_text_title: {
|
|
234
|
+
...rich_text_title,
|
|
235
|
+
elements: rich_text_title.elements.flatMap(splitRichTextElement),
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
...(subtitle && {
|
|
239
|
+
subtitle: clampText(subtitle, SLACK_LIMITS.containerSubtitleChars),
|
|
240
|
+
}),
|
|
241
|
+
};
|
|
242
|
+
if (icon && fitsImageUrl(icon)) {
|
|
243
|
+
fitted.icon = clampAlt(icon);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
delete fitted.icon;
|
|
247
|
+
}
|
|
248
|
+
return containerWithChildren(fitted, child_blocks.flatMap(fitBlock));
|
|
249
|
+
};
|
|
208
250
|
// Pack renderers build their own blocks, and one overlong text makes Slack
|
|
209
251
|
// reject the whole message.
|
|
210
252
|
const clampBlockText = (block) => {
|
|
@@ -267,11 +309,15 @@ const clampBlockText = (block) => {
|
|
|
267
309
|
};
|
|
268
310
|
const collectSlackFileRefs = (blocks) => {
|
|
269
311
|
const refs = new Set();
|
|
270
|
-
|
|
312
|
+
const visit = (block) => {
|
|
271
313
|
if (block.type === 'image' && block.slack_file?.ref !== undefined) {
|
|
272
314
|
refs.add(block.slack_file.ref);
|
|
273
315
|
}
|
|
274
|
-
|
|
316
|
+
else if (isContainer(block)) {
|
|
317
|
+
block.child_blocks.forEach(visit);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
blocks.forEach(visit);
|
|
275
321
|
return refs;
|
|
276
322
|
};
|
|
277
323
|
const headerBlock = (title, level) => ({
|
|
@@ -293,16 +339,20 @@ const slackSpacerBlock = () => ({
|
|
|
293
339
|
type: 'section',
|
|
294
340
|
text: { type: 'mrkdwn', text: SLACK_SPACER_TEXT },
|
|
295
341
|
});
|
|
296
|
-
const isSpacer = (block) => block
|
|
342
|
+
const isSpacer = (block) => !isUnmodeledSlackBlock(block) &&
|
|
343
|
+
block.type === 'section' &&
|
|
297
344
|
block.text?.type === 'mrkdwn' &&
|
|
298
345
|
block.text.text === SLACK_SPACER_TEXT &&
|
|
299
346
|
block.fields === undefined &&
|
|
300
347
|
block.accessory === undefined;
|
|
301
|
-
const isFieldsOnly = (block) => block
|
|
348
|
+
const isFieldsOnly = (block) => !isUnmodeledSlackBlock(block) &&
|
|
349
|
+
block.type === 'section' &&
|
|
302
350
|
(block.fields?.length ?? 0) > 0 &&
|
|
303
351
|
block.text === undefined &&
|
|
304
352
|
block.accessory === undefined;
|
|
305
|
-
|
|
353
|
+
// A container sets itself apart, so no spacer goes beside it.
|
|
354
|
+
const isContent = (block) => block.type !== 'container' &&
|
|
355
|
+
block.type !== 'header' &&
|
|
306
356
|
block.type !== 'divider' &&
|
|
307
357
|
block.type !== 'actions' &&
|
|
308
358
|
block.type !== 'context' &&
|
|
@@ -331,7 +381,9 @@ const coalesceFieldSections = (blocks) => {
|
|
|
331
381
|
out.push({ type: 'section', fields });
|
|
332
382
|
continue;
|
|
333
383
|
}
|
|
334
|
-
out.push(block)
|
|
384
|
+
out.push(...(isContainer(block)
|
|
385
|
+
? containerWithChildren(block, coalesceFieldSections(block.child_blocks))
|
|
386
|
+
: [block]));
|
|
335
387
|
index += 1;
|
|
336
388
|
}
|
|
337
389
|
return out;
|
|
@@ -516,8 +568,11 @@ const fitsTableShape = ({ rows }) => rows.length > 0 &&
|
|
|
516
568
|
// kept ones left.
|
|
517
569
|
const enforceTableLimits = (blocks) => {
|
|
518
570
|
let spent = 0;
|
|
519
|
-
|
|
520
|
-
if (block
|
|
571
|
+
const fit = (block) => {
|
|
572
|
+
if (isContainer(block)) {
|
|
573
|
+
return containerWithChildren(block, block.child_blocks.flatMap(fit));
|
|
574
|
+
}
|
|
575
|
+
if (block.type !== 'table' || isUnmodeledSlackBlock(block)) {
|
|
521
576
|
return [block];
|
|
522
577
|
}
|
|
523
578
|
const cost = tableCharCount(block);
|
|
@@ -527,7 +582,8 @@ const enforceTableLimits = (blocks) => {
|
|
|
527
582
|
return [block];
|
|
528
583
|
}
|
|
529
584
|
return degradeTable(block);
|
|
530
|
-
}
|
|
585
|
+
};
|
|
586
|
+
return blocks.flatMap(fit);
|
|
531
587
|
};
|
|
532
588
|
const enforceBlockBudget = (blocks) => {
|
|
533
589
|
if (blocks.length <= SLACK_LIMITS.blocksPerMessage) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/render/slack/envelope.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\nimport type { Composition } from '../../composition/composition';\nimport type { PrimitiveNode } from '../../define/primitive_module';\nimport type { MarkdownEnvelopeDispatcher } from '../markdown/envelope';\nimport { renderTextEnvelope } from '../text/envelope';\n\nimport {\n createSlackAssetCollector,\n type SlackAssetCollector,\n type SlackAssetRequest,\n} from './assets';\nimport {\n SLACK_LIMITS,\n type SlackActionElement,\n type SlackBlock,\n type SlackContextBlock,\n type SlackHeaderBlock,\n type SlackMrkdwnTextObject,\n type SlackOptionObject,\n type SlackRichTextBlockElement,\n type SlackRichTextInline,\n type SlackRichTextSection,\n type SlackRichTextText,\n type SlackSectionBlock,\n type SlackTableBlock,\n type SlackTableCell,\n type SlackTextObject,\n} from './blocks';\nimport {\n clampMrkdwn,\n clampSlackText,\n cutSlackValue,\n escapeMrkdwn,\n formatHeaderText,\n italic,\n} from './format';\n\n/**\n * Adds Block Kit to {@link MarkdownEnvelopeDispatcher}.\n *\n * `renderSlack` may return no blocks, in which case the node contributes\n * nothing — the envelope spreads what it is given and does not degrade. That is\n * the dispatcher's job: it renders the node's markdown instead. The markdown\n * renderer is what that fallback reads, so it stays required even for a pack\n * with full Slack coverage.\n */\nexport interface SlackEnvelopeDispatcher<\n TNode extends PrimitiveNode,\n> extends MarkdownEnvelopeDispatcher<TNode> {\n /** `collector` is absent unless the caller opted into asset collection, so a renderer must still degrade an image it cannot upload. */\n renderSlack(\n node: TNode,\n collector?: SlackAssetCollector\n ): readonly SlackBlock[];\n}\n\n/** Options for {@link renderSlackEnvelope}. */\nexport interface SlackEnvelopeOptions {\n /** Renders the composition's title and subtitle, in the blocks and the fallback `text`. Defaults to `true`. Pass `false` when the host already shows the title, or the body opens with its own. */\n heading?: boolean;\n /** Fallback `text` summary shown in notifications and previews, as `mrkdwn`; defaults to the text render, escaped. */\n text?: string;\n /** Whether to collect image upload requests alongside the blocks. */\n collectAssets?: boolean;\n /** Prefix for allocated asset refs; defaults to `asset`. Distinct prefixes keep merged inventories unique. */\n assetPrefix?: string;\n}\n\n/** What {@link renderSlackEnvelope} returns: one `chat.postMessage` payload. */\nexport interface SlackEnvelopeResult {\n /** Fallback text for the message. */\n text: string;\n /** Block Kit blocks, fitted to Slack's limits. */\n blocks: SlackBlock[];\n /** Images referenced by `blocks` that the host must upload first. */\n assets: SlackAssetRequest[];\n}\n\n/**\n * The composition as a `chat.postMessage` payload: notification `text`, blocks,\n * and the images the host must upload first.\n *\n * Degradation for a node with no `slack` renderer is the dispatcher's, which\n * has to own it to reach a child nested inside a container. The result is\n * fitted to Slack's limits — text is clamped, blocks past a count limit and\n * `rich_text` elements past a section's limit split, tables past a table limit\n * or the message's cell budget become rich text, spacers and then whole blocks\n * are dropped — so the output is always postable. `assets` stays empty\n * unless `collectAssets` is set.\n */\nexport const renderSlackEnvelope = <TNode extends PrimitiveNode>(\n composition: Composition<TNode>,\n dispatcher: SlackEnvelopeDispatcher<TNode>,\n options: SlackEnvelopeOptions = {}\n): SlackEnvelopeResult => {\n const blocks: SlackBlock[] = [];\n // The collector is opt-in: without it, charts keep their markdown/text\n // degradation and non-reachable images degrade to a link/text section, so\n // default output is safe for callers that cannot upload files.\n const collector = options.collectAssets\n ? createSlackAssetCollector(\n options.assetPrefix === undefined ? {} : { prefix: options.assetPrefix }\n )\n : undefined;\n\n const { heading = true } = options;\n if (heading && composition.title) {\n blocks.push(headerBlock(composition.title, 1));\n }\n if (heading && composition.subtitle) {\n blocks.push(contextBlock([escapeMrkdwn(composition.subtitle)]));\n }\n for (const node of composition.body) {\n blocks.push(...dispatcher.renderSlack(node, collector).flatMap(fitBlock));\n }\n\n // Split after the rhythm, so the fragments of one block read as one.\n const rhythm = applySectionRhythm(\n coalesceFieldSections(enforceTableLimits(blocks))\n ).flatMap(splitBlockCounts);\n const budgeted = enforceBlockBudget(rhythm);\n // Only ask the host to upload assets whose placeholder block survived the\n // budget; blocks elided by `enforceBlockBudget` are never posted, so\n // uploading their files would be wasted (and orphaned) work.\n const keptRefs = collectSlackFileRefs(budgeted);\n\n return {\n text: clampMrkdwn(\n options.text ??\n escapeMrkdwn(renderTextEnvelope(composition, dispatcher, { heading })),\n SLACK_LIMITS.fallbackTextChars\n ),\n blocks: budgeted,\n assets: collector\n ? collector.requests.filter((request) => keptRefs.has(request.ref))\n : [],\n };\n};\n\nconst clampText = <TText extends SlackTextObject>(\n text: TText,\n max: number\n): TText =>\n text.text.length <= max\n ? text\n : {\n ...text,\n text: (text.type === 'mrkdwn' ? clampMrkdwn : clampSlackText)(\n text.text,\n max\n ),\n };\n\nconst fitsImageUrl = ({ image_url }: { image_url?: string }): boolean =>\n image_url === undefined || image_url.length <= SLACK_LIMITS.imageUrlChars;\n\nconst clampAlt = <TImage extends { alt_text: string }>(\n image: TImage\n): TImage =>\n image.alt_text.length <= SLACK_LIMITS.imageAltTextChars\n ? image\n : {\n ...image,\n alt_text: clampSlackText(\n image.alt_text,\n SLACK_LIMITS.imageAltTextChars\n ),\n };\n\n// A cut URL would point somewhere else, so one past the limit is dropped.\nconst withoutLongUrl = <T extends { url?: string }>(element: T): T => {\n if (\n element.url === undefined ||\n element.url.length <= SLACK_LIMITS.urlChars\n ) {\n return element;\n }\n const { url: _dropped, ...rest } = element;\n return rest as T;\n};\n\nconst optionValue = (value: string): string =>\n cutSlackValue(value, SLACK_LIMITS.optionValueChars);\n\nconst clampOption = (option: SlackOptionObject): SlackOptionObject =>\n withoutLongUrl({\n ...option,\n text: clampText(option.text, SLACK_LIMITS.optionTextChars),\n value: optionValue(option.value),\n ...(option.description && {\n description: clampText(option.description, SLACK_LIMITS.optionTextChars),\n }),\n });\n\nconst clampControl = (element: SlackActionElement): SlackActionElement => {\n const actionId =\n element.action_id === undefined\n ? {}\n : {\n action_id: cutSlackValue(\n element.action_id,\n SLACK_LIMITS.actionIdChars\n ),\n };\n if (element.type === 'button') {\n return withoutLongUrl({\n ...element,\n ...actionId,\n text: clampText(element.text, SLACK_LIMITS.buttonTextChars),\n ...(element.value !== undefined && {\n value: cutSlackValue(element.value, SLACK_LIMITS.buttonValueChars),\n }),\n });\n }\n const menu = { ...element, ...actionId };\n const maxOptions =\n menu.type === 'overflow'\n ? SLACK_LIMITS.optionsPerOverflow\n : menu.type === 'radio_buttons' || menu.type === 'checkboxes'\n ? SLACK_LIMITS.optionsPerChoice\n : SLACK_LIMITS.optionsPerSelect;\n if (menu.options) {\n menu.options = menu.options.slice(0, maxOptions).map(clampOption);\n }\n if ('placeholder' in menu && menu.placeholder) {\n menu.placeholder = clampText(\n menu.placeholder,\n SLACK_LIMITS.placeholderChars\n );\n }\n if ('option_groups' in menu && menu.option_groups) {\n menu.option_groups = menu.option_groups\n .slice(0, SLACK_LIMITS.optionGroupsPerSelect)\n .map((group) => ({\n ...group,\n label: clampText(group.label, SLACK_LIMITS.optionGroupLabelChars),\n options: group.options.slice(0, maxOptions).map(clampOption),\n }));\n }\n // Slack requires an initial option to equal one it emits, so each is\n // replaced by the emitted option of the same value, or dropped.\n const emitted = new Map(\n [\n ...(menu.options ?? []),\n ...(('option_groups' in menu && menu.option_groups) || []).flatMap(\n ({ options }) => options\n ),\n ].map((option) => [option.value, option])\n );\n if ('initial_option' in menu && menu.initial_option) {\n const match = emitted.get(optionValue(menu.initial_option.value));\n if (match) {\n menu.initial_option = match;\n } else {\n delete menu.initial_option;\n }\n }\n if ('initial_options' in menu && menu.initial_options) {\n const matches = menu.initial_options.flatMap(({ value }) => {\n const match = emitted.get(optionValue(value));\n return match ? [match] : [];\n });\n if (matches.length > 0) {\n menu.initial_options = matches;\n } else {\n delete menu.initial_options;\n }\n }\n return menu;\n};\n\nconst chunks = <T>(items: readonly T[], size: number): T[][] =>\n Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>\n items.slice(index * size, (index + 1) * size)\n );\n\n// Splits a block past a count limit into blocks of its type. Only the first\n// keeps a `block_id`, which Slack requires to be unique.\nconst splitBlockCounts = (block: SlackBlock): SlackBlock[] => {\n switch (block.type) {\n case 'context':\n return chunks(block.elements, SLACK_LIMITS.contextElements).map(\n (elements, index) =>\n index === 0 ? { ...block, elements } : { type: 'context', elements }\n );\n case 'actions':\n return chunks(block.elements, SLACK_LIMITS.buttonsPerActions).map(\n (elements, index) =>\n index === 0 ? { ...block, elements } : { type: 'actions', elements }\n );\n case 'section': {\n if (\n !block.fields ||\n block.fields.length <= SLACK_LIMITS.fieldsPerSection\n ) {\n return [block];\n }\n return chunks(block.fields, SLACK_LIMITS.fieldsPerSection).map(\n (fields, index) =>\n index === 0 ? { ...block, fields } : { type: 'section', fields }\n );\n }\n default:\n return [block];\n }\n};\n\n// An image whose URL Slack would reject leaves its alt text.\nconst fitImageUrls = (block: SlackBlock): SlackBlock[] => {\n switch (block.type) {\n case 'image':\n return fitsImageUrl(block)\n ? [block]\n : block.alt_text\n ? [contextBlock([escapeMrkdwn(block.alt_text)])]\n : [];\n case 'context':\n return [\n {\n ...block,\n elements: block.elements.flatMap((element) =>\n element.type !== 'image' || fitsImageUrl(element)\n ? [element]\n : element.alt_text\n ? [{ type: 'mrkdwn', text: escapeMrkdwn(element.alt_text) }]\n : []\n ),\n },\n ];\n case 'section': {\n if (block.accessory?.type !== 'image' || fitsImageUrl(block.accessory)) {\n return [block];\n }\n const { accessory, ...rest } = block;\n return accessory.alt_text\n ? [rest, contextBlock([escapeMrkdwn(accessory.alt_text)])]\n : [rest];\n }\n default:\n return [block];\n }\n};\n\nconst fitBlock = (block: SlackBlock): SlackBlock[] =>\n fitImageUrls(block).map(clampBlockText);\n\n// Pack renderers build their own blocks, and one overlong text makes Slack\n// reject the whole message.\nconst clampBlockText = (block: SlackBlock): SlackBlock => {\n switch (block.type) {\n case 'header':\n return {\n ...block,\n text: clampText(block.text, SLACK_LIMITS.headerTextChars),\n };\n case 'section':\n return {\n ...block,\n ...(block.text && {\n text: clampText(block.text, SLACK_LIMITS.sectionTextChars),\n }),\n ...(block.fields && {\n fields: block.fields.map((field) =>\n clampText(field, SLACK_LIMITS.sectionFieldChars)\n ),\n }),\n ...(block.accessory && {\n accessory:\n block.accessory.type === 'image'\n ? clampAlt(block.accessory)\n : clampControl(block.accessory),\n }),\n };\n case 'rich_text':\n return {\n ...block,\n elements: block.elements.flatMap(splitRichTextElement),\n };\n case 'context':\n return {\n ...block,\n elements: block.elements.map((element) =>\n element.type === 'image'\n ? clampAlt(element)\n : clampText(element, SLACK_LIMITS.contextElementChars)\n ),\n };\n case 'image':\n return {\n ...clampAlt(block),\n ...(block.title && {\n title: clampText(block.title, SLACK_LIMITS.imageTitleChars),\n }),\n };\n case 'video':\n return {\n ...block,\n title: clampText(block.title, SLACK_LIMITS.videoTitleChars),\n ...(block.description && {\n description: clampText(\n block.description,\n SLACK_LIMITS.videoDescriptionChars\n ),\n }),\n ...(block.author_name !== undefined && {\n author_name: clampSlackText(\n block.author_name,\n SLACK_LIMITS.videoAuthorNameChars\n ),\n }),\n };\n case 'actions':\n return { ...block, elements: block.elements.map(clampControl) };\n default:\n return block;\n }\n};\n\nconst collectSlackFileRefs = (\n blocks: readonly SlackBlock[]\n): ReadonlySet<string> => {\n const refs = new Set<string>();\n for (const block of blocks) {\n if (block.type === 'image' && block.slack_file?.ref !== undefined) {\n refs.add(block.slack_file.ref);\n }\n }\n return refs;\n};\n\nconst headerBlock = (\n title: string,\n level?: SlackHeaderBlock['level']\n): SlackHeaderBlock => ({\n type: 'header',\n text: { type: 'plain_text', text: formatHeaderText(title), emoji: true },\n ...(level !== undefined ? { level } : {}),\n});\n\nconst contextBlock = (lines: ReadonlyArray<string>): SlackContextBlock => ({\n type: 'context',\n elements: lines\n .filter((line): line is string => line !== undefined && line.length > 0)\n .map((text) => ({\n type: 'mrkdwn',\n text: clampMrkdwn(text, SLACK_LIMITS.contextElementChars),\n })),\n});\n\nconst SLACK_SPACER_TEXT = ' ';\n\nconst slackSpacerBlock = (): SlackSectionBlock => ({\n type: 'section',\n text: { type: 'mrkdwn', text: SLACK_SPACER_TEXT },\n});\n\nconst isSpacer = (block: SlackBlock): boolean =>\n block.type === 'section' &&\n block.text?.type === 'mrkdwn' &&\n block.text.text === SLACK_SPACER_TEXT &&\n block.fields === undefined &&\n block.accessory === undefined;\n\nconst isFieldsOnly = (\n block: SlackBlock\n): block is SlackSectionBlock & { fields: SlackMrkdwnTextObject[] } =>\n block.type === 'section' &&\n (block.fields?.length ?? 0) > 0 &&\n block.text === undefined &&\n block.accessory === undefined;\n\nconst isContent = (block: SlackBlock): boolean =>\n block.type !== 'header' &&\n block.type !== 'divider' &&\n block.type !== 'actions' &&\n block.type !== 'context' &&\n !isSpacer(block);\n\n// Consecutive 1-field sections pack into Slack's two-column `fields` grid.\n// A section that already has 2+ fields is a finished batch (e.g. a\n// description list) and is left alone.\nconst coalesceFieldSections = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n const out: SlackBlock[] = [];\n let index = 0;\n while (index < blocks.length) {\n const block = blocks[index]!;\n if (isFieldsOnly(block) && block.fields?.length === 1) {\n const fields = [...block.fields];\n index += 1;\n while (index < blocks.length) {\n const next = blocks[index]!;\n if (\n !isFieldsOnly(next) ||\n next.fields.length !== 1 ||\n fields.length >= SLACK_LIMITS.fieldsPerSection\n ) {\n break;\n }\n fields.push(...next.fields);\n index += 1;\n }\n out.push({ type: 'section', fields });\n continue;\n }\n out.push(block);\n index += 1;\n }\n return out;\n};\n\n// Divider before every section heading (and trailing actions) after the\n// composition title; spacer after each content run except a table already\n// about to be followed by a divider. Consecutive field-only sections are\n// not spaced — they read as one grid.\nconst applySectionRhythm = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n if (blocks.length === 0) {\n return [];\n }\n const out: SlackBlock[] = [];\n for (let index = 0; index < blocks.length; index += 1) {\n const block = blocks[index]!;\n const prev = out[out.length - 1];\n const needsDividerBefore =\n (block.type === 'header' && out.length > 0) || block.type === 'actions';\n if (needsDividerBefore && prev && prev.type !== 'divider') {\n if (isContent(prev) && prev.type !== 'table') {\n out.push(slackSpacerBlock());\n }\n out.push({ type: 'divider' });\n }\n out.push(block);\n if (isContent(block) && index + 1 < blocks.length) {\n const next = blocks[index + 1]!;\n if (isContent(next) && !(isFieldsOnly(block) && isFieldsOnly(next))) {\n out.push(slackSpacerBlock());\n }\n }\n }\n return out;\n};\n\nconst truncateWithNotice = (blocks: SlackBlock[]): SlackBlock[] => {\n const kept = blocks.slice(0, SLACK_LIMITS.blocksPerMessage - 1);\n const dropped = blocks.length - kept.length;\n kept.push(\n contextBlock([\n italic(`+${dropped} more blocks elided to fit Slack's limit.`),\n ])\n );\n return kept;\n};\n\nconst richTextInlineText = (inline: SlackRichTextInline): string =>\n inline.type === 'link' ? (inline.text ?? inline.url) : inline.text;\n\nconst richTextElementText = (element: SlackRichTextBlockElement): string =>\n element.type === 'rich_text_list'\n ? element.elements.map(richTextElementText).join('')\n : element.elements.map(richTextInlineText).join('');\n\nconst tableCellText = (cell: SlackTableCell): string =>\n cell.type === 'raw_text'\n ? cell.text\n : cell.elements.map(richTextElementText).join('');\n\nconst tableCharCount = (block: SlackTableBlock): number =>\n block.rows.reduce(\n (total, row) =>\n total + row.reduce((sum, cell) => sum + tableCellText(cell).length, 0),\n 0\n );\n\nconst textRun = (text: string): SlackRichTextText => ({ type: 'text', text });\n\nconst richSection = (\n elements: SlackRichTextInline[]\n): SlackRichTextSection => ({ type: 'rich_text_section', elements });\n\nconst rowBreak = (): SlackRichTextSection => richSection([textRun('\\n')]);\n\nconst cellElements = (\n cell: SlackTableCell | undefined\n): SlackRichTextBlockElement[] => {\n if (cell?.type === 'rich_text') {\n return cell.elements.filter(({ elements }) => elements.length > 0);\n }\n return cell?.text ? [richSection([textRun(cell.text)])] : [];\n};\n\nconst boldInline = (inline: SlackRichTextInline): SlackRichTextInline => ({\n ...inline,\n style: { ...inline.style, bold: true },\n});\n\nconst boldElement = (\n element: SlackRichTextBlockElement\n): SlackRichTextBlockElement =>\n element.type === 'rich_text_list'\n ? {\n ...element,\n elements: element.elements.map((item) => ({\n ...item,\n elements: item.elements.map(boldInline),\n })),\n }\n : { ...element, elements: element.elements.map(boldInline) };\n\nconst isBlank = (cell: SlackTableCell | undefined): boolean =>\n cell === undefined || tableCellText(cell).trim() === '';\n\n// A one-section heading leads its cell as `heading: `; any other heading keeps\n// its blocks, bold, above the cell. A blank heading leaves the cell alone.\nconst columnElements = (\n heading: SlackTableCell | undefined,\n cell: SlackTableCell | undefined\n): SlackRichTextBlockElement[] => {\n const body = cellElements(cell);\n if (isBlank(heading)) {\n return body;\n }\n const head = cellElements(heading);\n const [only] = head;\n if (head.length !== 1 || only?.type !== 'rich_text_section') {\n return [...head.map(boldElement), ...body];\n }\n const lead = [...only.elements.map(boldInline), textRun(': ')];\n const [first, ...rest] = body;\n return first?.type === 'rich_text_section'\n ? [richSection([...lead, ...first.elements]), ...rest]\n : [richSection(lead), ...body];\n};\n\nconst endsLine = (element: SlackRichTextBlockElement): boolean =>\n /[\\n\\r\\u2028\\u2029]$/u.test(richTextElementText(element));\n\n// Slack runs adjacent sections together, so a section followed by another ends\n// its line unless its rendered text already does.\nconst breakSections = (\n elements: readonly SlackRichTextBlockElement[]\n): SlackRichTextBlockElement[] =>\n elements.map((element, index) =>\n element.type === 'rich_text_section' &&\n elements[index + 1]?.type === 'rich_text_section' &&\n !endsLine(element)\n ? richSection([...element.elements, textRun('\\n')])\n : element\n );\n\n// Graphemes, and the code points of any grapheme past `max`.\nconst textUnits = (text: string, max: number): string[] =>\n Array.from(\n new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text),\n ({ segment }) => (segment.length > max ? Array.from(segment) : [segment])\n ).flat();\n\n/**\n * A section, quote, or preformatted element past `sectionTextChars` as adjacent ones of its type, with nothing added between them; a list comes back as is.\n * A link or tag no longer than that stays whole; anything longer splits at grapheme boundaries into inlines of its own type, a link's label (or URL) across links to the same URL.\n */\nconst splitRichTextElement = (\n element: SlackRichTextBlockElement\n): SlackRichTextBlockElement[] => {\n const max = SLACK_LIMITS.sectionTextChars;\n if (\n element.type === 'rich_text_list' ||\n richTextElementText(element).length <= max\n ) {\n return [element];\n }\n const chunks: SlackRichTextInline[][] = [];\n let chunk: SlackRichTextInline[] = [];\n let room: number = max;\n const flush = (): void => {\n if (chunk.length > 0) {\n chunks.push(chunk);\n }\n chunk = [];\n room = max;\n };\n for (const inline of element.elements) {\n const whole = richTextInlineText(inline);\n if (inline.type !== 'text' && whole.length <= max) {\n if (whole.length > room) {\n flush();\n }\n chunk.push(inline);\n room -= whole.length;\n continue;\n }\n let text = '';\n for (const unit of textUnits(whole, max)) {\n if (text.length + unit.length > room) {\n if (text) {\n chunk.push({ ...inline, text });\n }\n flush();\n text = '';\n }\n text += unit;\n }\n if (text) {\n chunk.push({ ...inline, text });\n room -= text.length;\n }\n }\n flush();\n return chunks.map((elements) => ({ ...element, elements }));\n};\n\n// A table Slack would reject is replaced by one `rich_text` block. Each row's\n// columns run `heading: cell` to the wider of the header and the row, and a\n// blank section parts the rows. A cell keeps its inlines, styles, and blocks; a\n// table whose rows past the header have no cells prints its headings, and one\n// with nothing to print is dropped.\nconst degradeTable = ({\n rows: [header = [], ...body],\n}: SlackTableBlock): SlackBlock[] => {\n const rows = body.filter((row) => row.length > 0);\n const pieces =\n rows.length === 0\n ? [\n header\n .filter((heading) => !isBlank(heading))\n .flatMap((heading) => cellElements(heading).map(boldElement)),\n ]\n : rows.map((row) =>\n Array.from(\n { length: Math.max(header.length, row.length) },\n (_, column) => columnElements(header[column], row[column])\n ).flat()\n );\n const elements = pieces\n .filter((piece) => piece.length > 0)\n .flatMap((piece, index) => (index > 0 ? [rowBreak(), ...piece] : piece));\n return elements.length === 0\n ? []\n : [\n {\n type: 'rich_text',\n elements: breakSections(elements).flatMap(splitRichTextElement),\n },\n ];\n};\n\nconst fitsTableShape = ({ rows }: SlackTableBlock): boolean =>\n rows.length > 0 &&\n rows.length <= SLACK_LIMITS.tableRows &&\n rows.every(\n (row) => row.length > 0 && row.length <= SLACK_LIMITS.tableColumns\n );\n\n// Slack counts table cell characters across the whole message, not per block,\n// so a composition whose tables individually fit can still be rejected. In\n// document order, a table is kept if its shape fits and its cells fit what the\n// kept ones left.\nconst enforceTableLimits = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n let spent = 0;\n return blocks.flatMap((block) => {\n if (block.type !== 'table') {\n return [block];\n }\n const cost = tableCharCount(block);\n if (\n fitsTableShape(block) &&\n spent + cost <= SLACK_LIMITS.tableCellCharsPerMessage\n ) {\n spent += cost;\n return [block];\n }\n return degradeTable(block);\n });\n};\n\nconst enforceBlockBudget = (blocks: SlackBlock[]): SlackBlock[] => {\n if (blocks.length <= SLACK_LIMITS.blocksPerMessage) {\n return blocks;\n }\n const trimmed = [...blocks];\n for (\n let index = trimmed.length - 1;\n index >= 0 && trimmed.length > SLACK_LIMITS.blocksPerMessage;\n index -= 1\n ) {\n if (isSpacer(trimmed[index]!)) {\n trimmed.splice(index, 1);\n }\n }\n if (trimmed.length <= SLACK_LIMITS.blocksPerMessage) {\n return trimmed;\n }\n return truncateWithNotice(trimmed);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../../src/render/slack/envelope.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\nimport type { Composition } from '../../composition/composition';\nimport type { PrimitiveNode } from '../../define/primitive_module';\nimport type { MarkdownEnvelopeDispatcher } from '../markdown/envelope';\nimport { renderTextEnvelope } from '../text/envelope';\n\nimport {\n createSlackAssetCollector,\n type SlackAssetCollector,\n type SlackAssetRequest,\n} from './assets';\nimport {\n SLACK_LIMITS,\n type SlackActionElement,\n type SlackBlock,\n type SlackContainerBlock,\n type SlackContextBlock,\n type SlackHeaderBlock,\n type SlackMrkdwnTextObject,\n type SlackOptionObject,\n type SlackRichTextBlockElement,\n type SlackRichTextInline,\n type SlackRichTextSection,\n type SlackRichTextText,\n type SlackSectionBlock,\n type SlackTableBlock,\n type SlackTableCell,\n type SlackTextObject,\n} from './blocks';\nimport { containerWithChildren, isContainer } from './container';\nimport {\n assertSlackBaseUrl,\n clampMrkdwn,\n clampSlackText,\n cutSlackValue,\n escapeMrkdwn,\n formatHeaderText,\n italic,\n type SlackLinkOptions,\n} from './format';\nimport { isUnmodeledSlackBlock } from './unmodeled';\n\n/**\n * Adds Block Kit to {@link MarkdownEnvelopeDispatcher}.\n *\n * `renderSlack` may return no blocks, in which case the node contributes\n * nothing — the envelope spreads what it is given and does not degrade. That is\n * the dispatcher's job: it renders the node's markdown instead. The markdown\n * renderer is what that fallback reads, so it stays required even for a pack\n * with full Slack coverage.\n */\nexport interface SlackEnvelopeDispatcher<\n TNode extends PrimitiveNode,\n> extends MarkdownEnvelopeDispatcher<TNode> {\n /** `collector` is absent unless the caller opted into asset collection, so a renderer must still degrade an image it cannot upload. */\n renderSlack(\n node: TNode,\n collector?: SlackAssetCollector,\n options?: SlackLinkOptions\n ): readonly SlackBlock[];\n}\n\n/** Options for {@link renderSlackEnvelope}. */\nexport interface SlackEnvelopeOptions extends SlackLinkOptions {\n /** Renders the composition's title and subtitle, in the blocks and the fallback `text`. Defaults to `true`. Pass `false` when the host already shows the title, or the body opens with its own. */\n heading?: boolean;\n /** Fallback `text` summary shown in notifications and previews, as `mrkdwn`; defaults to the text render, escaped. */\n text?: string;\n /** Whether to collect image upload requests alongside the blocks. */\n collectAssets?: boolean;\n /** Prefix for allocated asset refs; defaults to `asset`. Distinct prefixes keep merged inventories unique. */\n assetPrefix?: string;\n}\n\n/** What {@link renderSlackEnvelope} returns: one `chat.postMessage` payload. */\nexport interface SlackEnvelopeResult {\n /** Fallback text for the message. */\n text: string;\n /** Block Kit blocks, fitted to Slack's limits. */\n blocks: SlackBlock[];\n /** Images referenced by `blocks` that the host must upload first. */\n assets: SlackAssetRequest[];\n}\n\n/**\n * The composition as a `chat.postMessage` payload: notification `text`, blocks,\n * and the images the host must upload first.\n *\n * Degradation for a node with no `slack` renderer is the dispatcher's, which\n * has to own it to reach a child nested inside a container. The result is\n * fitted to Slack's limits — text is clamped, blocks past a count limit and\n * `rich_text` elements past a section's limit split, tables past a table limit\n * or the message's cell budget become rich text, spacers and then whole blocks\n * are dropped — so the output is always postable, except for a block from\n * `unmodeledSlackBlock` or of a type Isomer does not model, which passes\n * through unfitted. `assets` stays empty unless `collectAssets` is set.\n */\nexport const renderSlackEnvelope = <TNode extends PrimitiveNode>(\n composition: Composition<TNode>,\n dispatcher: SlackEnvelopeDispatcher<TNode>,\n options: SlackEnvelopeOptions = {}\n): SlackEnvelopeResult => {\n const blocks: SlackBlock[] = [];\n // The collector is opt-in: without it, charts keep their markdown/text\n // degradation and non-reachable images degrade to a link/text section, so\n // default output is safe for callers that cannot upload files.\n const collector = options.collectAssets\n ? createSlackAssetCollector(\n options.assetPrefix === undefined ? {} : { prefix: options.assetPrefix }\n )\n : undefined;\n\n const { heading = true, baseUrl } = options;\n assertSlackBaseUrl(baseUrl);\n if (heading && composition.title) {\n blocks.push(headerBlock(composition.title, 1));\n }\n if (heading && composition.subtitle) {\n blocks.push(contextBlock([escapeMrkdwn(composition.subtitle)]));\n }\n const linkOptions = baseUrl === undefined ? {} : { baseUrl };\n for (const node of composition.body) {\n blocks.push(\n ...dispatcher.renderSlack(node, collector, linkOptions).flatMap(fitBlock)\n );\n }\n\n // Split after the rhythm, so the fragments of one block read as one.\n const rhythm = applySectionRhythm(\n coalesceFieldSections(enforceTableLimits(blocks))\n ).flatMap(splitBlockCounts);\n const budgeted = enforceBlockBudget(rhythm);\n // Only ask the host to upload assets whose placeholder block survived the\n // budget; blocks elided by `enforceBlockBudget` are never posted, so\n // uploading their files would be wasted (and orphaned) work.\n const keptRefs = collectSlackFileRefs(budgeted);\n\n return {\n text: clampMrkdwn(\n options.text ??\n escapeMrkdwn(renderTextEnvelope(composition, dispatcher, { heading })),\n SLACK_LIMITS.fallbackTextChars\n ),\n blocks: budgeted,\n assets: collector\n ? collector.requests.filter((request) => keptRefs.has(request.ref))\n : [],\n };\n};\n\nconst clampText = <TText extends SlackTextObject>(\n text: TText,\n max: number\n): TText =>\n text.text.length <= max\n ? text\n : {\n ...text,\n text: (text.type === 'mrkdwn' ? clampMrkdwn : clampSlackText)(\n text.text,\n max\n ),\n };\n\nconst fitsImageUrl = ({ image_url }: { image_url?: string }): boolean =>\n image_url === undefined || image_url.length <= SLACK_LIMITS.imageUrlChars;\n\nconst clampAlt = <TImage extends { alt_text: string }>(\n image: TImage\n): TImage =>\n image.alt_text.length <= SLACK_LIMITS.imageAltTextChars\n ? image\n : {\n ...image,\n alt_text: clampSlackText(\n image.alt_text,\n SLACK_LIMITS.imageAltTextChars\n ),\n };\n\n// A cut URL would point somewhere else, so one past the limit is dropped.\nconst withoutLongUrl = <T extends { url?: string }>(element: T): T => {\n if (\n element.url === undefined ||\n element.url.length <= SLACK_LIMITS.urlChars\n ) {\n return element;\n }\n const { url: _dropped, ...rest } = element;\n return rest as T;\n};\n\nconst optionValue = (value: string): string =>\n cutSlackValue(value, SLACK_LIMITS.optionValueChars);\n\nconst clampOption = (option: SlackOptionObject): SlackOptionObject =>\n withoutLongUrl({\n ...option,\n text: clampText(option.text, SLACK_LIMITS.optionTextChars),\n value: optionValue(option.value),\n ...(option.description && {\n description: clampText(option.description, SLACK_LIMITS.optionTextChars),\n }),\n });\n\nconst clampControl = (element: SlackActionElement): SlackActionElement => {\n const actionId =\n element.action_id === undefined\n ? {}\n : {\n action_id: cutSlackValue(\n element.action_id,\n SLACK_LIMITS.actionIdChars\n ),\n };\n if (element.type === 'button') {\n return withoutLongUrl({\n ...element,\n ...actionId,\n text: clampText(element.text, SLACK_LIMITS.buttonTextChars),\n ...(element.value !== undefined && {\n value: cutSlackValue(element.value, SLACK_LIMITS.buttonValueChars),\n }),\n });\n }\n const menu = { ...element, ...actionId };\n const maxOptions =\n menu.type === 'overflow'\n ? SLACK_LIMITS.optionsPerOverflow\n : menu.type === 'radio_buttons' || menu.type === 'checkboxes'\n ? SLACK_LIMITS.optionsPerChoice\n : SLACK_LIMITS.optionsPerSelect;\n if (menu.options) {\n menu.options = menu.options.slice(0, maxOptions).map(clampOption);\n }\n if ('placeholder' in menu && menu.placeholder) {\n menu.placeholder = clampText(\n menu.placeholder,\n SLACK_LIMITS.placeholderChars\n );\n }\n if ('option_groups' in menu && menu.option_groups) {\n menu.option_groups = menu.option_groups\n .slice(0, SLACK_LIMITS.optionGroupsPerSelect)\n .map((group) => ({\n ...group,\n label: clampText(group.label, SLACK_LIMITS.optionGroupLabelChars),\n options: group.options.slice(0, maxOptions).map(clampOption),\n }));\n }\n // Slack requires an initial option to equal one it emits, so each is\n // replaced by the emitted option of the same value, or dropped.\n const emitted = new Map(\n [\n ...(menu.options ?? []),\n ...(('option_groups' in menu && menu.option_groups) || []).flatMap(\n ({ options }) => options\n ),\n ].map((option) => [option.value, option])\n );\n if ('initial_option' in menu && menu.initial_option) {\n const match = emitted.get(optionValue(menu.initial_option.value));\n if (match) {\n menu.initial_option = match;\n } else {\n delete menu.initial_option;\n }\n }\n if ('initial_options' in menu && menu.initial_options) {\n const matches = menu.initial_options.flatMap(({ value }) => {\n const match = emitted.get(optionValue(value));\n return match ? [match] : [];\n });\n if (matches.length > 0) {\n menu.initial_options = matches;\n } else {\n delete menu.initial_options;\n }\n }\n return menu;\n};\n\nconst chunks = <T>(items: readonly T[], size: number): T[][] =>\n Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>\n items.slice(index * size, (index + 1) * size)\n );\n\n// Splits a block past a count limit into blocks of its type. Only the first\n// keeps a `block_id`, which Slack requires to be unique.\nconst splitBlockCounts = (block: SlackBlock): SlackBlock[] => {\n if (isUnmodeledSlackBlock(block)) {\n return [block];\n }\n switch (block.type) {\n case 'container':\n return containerWithChildren(\n block,\n block.child_blocks.flatMap(splitBlockCounts)\n );\n case 'context':\n return chunks(block.elements, SLACK_LIMITS.contextElements).map(\n (elements, index) =>\n index === 0 ? { ...block, elements } : { type: 'context', elements }\n );\n case 'actions':\n return chunks(block.elements, SLACK_LIMITS.buttonsPerActions).map(\n (elements, index) =>\n index === 0 ? { ...block, elements } : { type: 'actions', elements }\n );\n case 'section': {\n if (\n !block.fields ||\n block.fields.length <= SLACK_LIMITS.fieldsPerSection\n ) {\n return [block];\n }\n return chunks(block.fields, SLACK_LIMITS.fieldsPerSection).map(\n (fields, index) =>\n index === 0 ? { ...block, fields } : { type: 'section', fields }\n );\n }\n default:\n return [block];\n }\n};\n\n// An image whose URL Slack would reject leaves its alt text.\nconst fitImageUrls = (block: SlackBlock): SlackBlock[] => {\n switch (block.type) {\n case 'image':\n return fitsImageUrl(block)\n ? [block]\n : block.alt_text\n ? [contextBlock([escapeMrkdwn(block.alt_text)])]\n : [];\n case 'context':\n return [\n {\n ...block,\n elements: block.elements.flatMap((element) =>\n element.type !== 'image' || fitsImageUrl(element)\n ? [element]\n : element.alt_text\n ? [{ type: 'mrkdwn', text: escapeMrkdwn(element.alt_text) }]\n : []\n ),\n },\n ];\n case 'section': {\n if (block.accessory?.type !== 'image' || fitsImageUrl(block.accessory)) {\n return [block];\n }\n const { accessory, ...rest } = block;\n return accessory.alt_text\n ? [rest, contextBlock([escapeMrkdwn(accessory.alt_text)])]\n : [rest];\n }\n default:\n return [block];\n }\n};\n\nconst fitBlock = (block: SlackBlock): SlackBlock[] => {\n if (isUnmodeledSlackBlock(block)) {\n return [block];\n }\n return block.type === 'container'\n ? fitContainer(block)\n : fitImageUrls(block).map(clampBlockText);\n};\n\nconst fitContainer = (container: SlackContainerBlock): SlackBlock[] => {\n const { title, rich_text_title, subtitle, icon, child_blocks } = container;\n const fitted: SlackContainerBlock = {\n ...container,\n ...(title && {\n title: clampText(title, SLACK_LIMITS.containerTitleChars),\n }),\n ...(rich_text_title && {\n rich_text_title: {\n ...rich_text_title,\n elements: rich_text_title.elements.flatMap(splitRichTextElement),\n },\n }),\n ...(subtitle && {\n subtitle: clampText(subtitle, SLACK_LIMITS.containerSubtitleChars),\n }),\n };\n if (icon && fitsImageUrl(icon)) {\n fitted.icon = clampAlt(icon);\n } else {\n delete fitted.icon;\n }\n return containerWithChildren(fitted, child_blocks.flatMap(fitBlock));\n};\n\n// Pack renderers build their own blocks, and one overlong text makes Slack\n// reject the whole message.\nconst clampBlockText = (block: SlackBlock): SlackBlock => {\n switch (block.type) {\n case 'header':\n return {\n ...block,\n text: clampText(block.text, SLACK_LIMITS.headerTextChars),\n };\n case 'section':\n return {\n ...block,\n ...(block.text && {\n text: clampText(block.text, SLACK_LIMITS.sectionTextChars),\n }),\n ...(block.fields && {\n fields: block.fields.map((field) =>\n clampText(field, SLACK_LIMITS.sectionFieldChars)\n ),\n }),\n ...(block.accessory && {\n accessory:\n block.accessory.type === 'image'\n ? clampAlt(block.accessory)\n : clampControl(block.accessory),\n }),\n };\n case 'rich_text':\n return {\n ...block,\n elements: block.elements.flatMap(splitRichTextElement),\n };\n case 'context':\n return {\n ...block,\n elements: block.elements.map((element) =>\n element.type === 'image'\n ? clampAlt(element)\n : clampText(element, SLACK_LIMITS.contextElementChars)\n ),\n };\n case 'image':\n return {\n ...clampAlt(block),\n ...(block.title && {\n title: clampText(block.title, SLACK_LIMITS.imageTitleChars),\n }),\n };\n case 'video':\n return {\n ...block,\n title: clampText(block.title, SLACK_LIMITS.videoTitleChars),\n ...(block.description && {\n description: clampText(\n block.description,\n SLACK_LIMITS.videoDescriptionChars\n ),\n }),\n ...(block.author_name !== undefined && {\n author_name: clampSlackText(\n block.author_name,\n SLACK_LIMITS.videoAuthorNameChars\n ),\n }),\n };\n case 'actions':\n return { ...block, elements: block.elements.map(clampControl) };\n default:\n return block;\n }\n};\n\nconst collectSlackFileRefs = (\n blocks: readonly SlackBlock[]\n): ReadonlySet<string> => {\n const refs = new Set<string>();\n const visit = (block: SlackBlock): void => {\n if (block.type === 'image' && block.slack_file?.ref !== undefined) {\n refs.add(block.slack_file.ref);\n } else if (isContainer(block)) {\n block.child_blocks.forEach(visit);\n }\n };\n blocks.forEach(visit);\n return refs;\n};\n\nconst headerBlock = (\n title: string,\n level?: SlackHeaderBlock['level']\n): SlackHeaderBlock => ({\n type: 'header',\n text: { type: 'plain_text', text: formatHeaderText(title), emoji: true },\n ...(level !== undefined ? { level } : {}),\n});\n\nconst contextBlock = (lines: ReadonlyArray<string>): SlackContextBlock => ({\n type: 'context',\n elements: lines\n .filter((line): line is string => line !== undefined && line.length > 0)\n .map((text) => ({\n type: 'mrkdwn',\n text: clampMrkdwn(text, SLACK_LIMITS.contextElementChars),\n })),\n});\n\nconst SLACK_SPACER_TEXT = ' ';\n\nconst slackSpacerBlock = (): SlackSectionBlock => ({\n type: 'section',\n text: { type: 'mrkdwn', text: SLACK_SPACER_TEXT },\n});\n\nconst isSpacer = (block: SlackBlock): boolean =>\n !isUnmodeledSlackBlock(block) &&\n block.type === 'section' &&\n block.text?.type === 'mrkdwn' &&\n block.text.text === SLACK_SPACER_TEXT &&\n block.fields === undefined &&\n block.accessory === undefined;\n\nconst isFieldsOnly = (\n block: SlackBlock\n): block is SlackSectionBlock & { fields: SlackMrkdwnTextObject[] } =>\n !isUnmodeledSlackBlock(block) &&\n block.type === 'section' &&\n (block.fields?.length ?? 0) > 0 &&\n block.text === undefined &&\n block.accessory === undefined;\n\n// A container sets itself apart, so no spacer goes beside it.\nconst isContent = (block: SlackBlock): boolean =>\n block.type !== 'container' &&\n block.type !== 'header' &&\n block.type !== 'divider' &&\n block.type !== 'actions' &&\n block.type !== 'context' &&\n !isSpacer(block);\n\n// Consecutive 1-field sections pack into Slack's two-column `fields` grid.\n// A section that already has 2+ fields is a finished batch (e.g. a\n// description list) and is left alone.\nconst coalesceFieldSections = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n const out: SlackBlock[] = [];\n let index = 0;\n while (index < blocks.length) {\n const block = blocks[index]!;\n if (isFieldsOnly(block) && block.fields?.length === 1) {\n const fields = [...block.fields];\n index += 1;\n while (index < blocks.length) {\n const next = blocks[index]!;\n if (\n !isFieldsOnly(next) ||\n next.fields.length !== 1 ||\n fields.length >= SLACK_LIMITS.fieldsPerSection\n ) {\n break;\n }\n fields.push(...next.fields);\n index += 1;\n }\n out.push({ type: 'section', fields });\n continue;\n }\n out.push(\n ...(isContainer(block)\n ? containerWithChildren(\n block,\n coalesceFieldSections(block.child_blocks)\n )\n : [block])\n );\n index += 1;\n }\n return out;\n};\n\n// Divider before every section heading (and trailing actions) after the\n// composition title; spacer after each content run except a table already\n// about to be followed by a divider. Consecutive field-only sections are\n// not spaced — they read as one grid.\nconst applySectionRhythm = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n if (blocks.length === 0) {\n return [];\n }\n const out: SlackBlock[] = [];\n for (let index = 0; index < blocks.length; index += 1) {\n const block = blocks[index]!;\n const prev = out[out.length - 1];\n const needsDividerBefore =\n (block.type === 'header' && out.length > 0) || block.type === 'actions';\n if (needsDividerBefore && prev && prev.type !== 'divider') {\n if (isContent(prev) && prev.type !== 'table') {\n out.push(slackSpacerBlock());\n }\n out.push({ type: 'divider' });\n }\n out.push(block);\n if (isContent(block) && index + 1 < blocks.length) {\n const next = blocks[index + 1]!;\n if (isContent(next) && !(isFieldsOnly(block) && isFieldsOnly(next))) {\n out.push(slackSpacerBlock());\n }\n }\n }\n return out;\n};\n\nconst truncateWithNotice = (blocks: SlackBlock[]): SlackBlock[] => {\n const kept = blocks.slice(0, SLACK_LIMITS.blocksPerMessage - 1);\n const dropped = blocks.length - kept.length;\n kept.push(\n contextBlock([\n italic(`+${dropped} more blocks elided to fit Slack's limit.`),\n ])\n );\n return kept;\n};\n\nconst richTextInlineText = (inline: SlackRichTextInline): string =>\n inline.type === 'link' ? (inline.text ?? inline.url) : inline.text;\n\nconst richTextElementText = (element: SlackRichTextBlockElement): string =>\n element.type === 'rich_text_list'\n ? element.elements.map(richTextElementText).join('')\n : element.elements.map(richTextInlineText).join('');\n\nconst tableCellText = (cell: SlackTableCell): string =>\n cell.type === 'raw_text'\n ? cell.text\n : cell.elements.map(richTextElementText).join('');\n\nconst tableCharCount = (block: SlackTableBlock): number =>\n block.rows.reduce(\n (total, row) =>\n total + row.reduce((sum, cell) => sum + tableCellText(cell).length, 0),\n 0\n );\n\nconst textRun = (text: string): SlackRichTextText => ({ type: 'text', text });\n\nconst richSection = (\n elements: SlackRichTextInline[]\n): SlackRichTextSection => ({ type: 'rich_text_section', elements });\n\nconst rowBreak = (): SlackRichTextSection => richSection([textRun('\\n')]);\n\nconst cellElements = (\n cell: SlackTableCell | undefined\n): SlackRichTextBlockElement[] => {\n if (cell?.type === 'rich_text') {\n return cell.elements.filter(({ elements }) => elements.length > 0);\n }\n return cell?.text ? [richSection([textRun(cell.text)])] : [];\n};\n\nconst boldInline = (inline: SlackRichTextInline): SlackRichTextInline => ({\n ...inline,\n style: { ...inline.style, bold: true },\n});\n\nconst boldElement = (\n element: SlackRichTextBlockElement\n): SlackRichTextBlockElement =>\n element.type === 'rich_text_list'\n ? {\n ...element,\n elements: element.elements.map((item) => ({\n ...item,\n elements: item.elements.map(boldInline),\n })),\n }\n : { ...element, elements: element.elements.map(boldInline) };\n\nconst isBlank = (cell: SlackTableCell | undefined): boolean =>\n cell === undefined || tableCellText(cell).trim() === '';\n\n// A one-section heading leads its cell as `heading: `; any other heading keeps\n// its blocks, bold, above the cell. A blank heading leaves the cell alone.\nconst columnElements = (\n heading: SlackTableCell | undefined,\n cell: SlackTableCell | undefined\n): SlackRichTextBlockElement[] => {\n const body = cellElements(cell);\n if (isBlank(heading)) {\n return body;\n }\n const head = cellElements(heading);\n const [only] = head;\n if (head.length !== 1 || only?.type !== 'rich_text_section') {\n return [...head.map(boldElement), ...body];\n }\n const lead = [...only.elements.map(boldInline), textRun(': ')];\n const [first, ...rest] = body;\n return first?.type === 'rich_text_section'\n ? [richSection([...lead, ...first.elements]), ...rest]\n : [richSection(lead), ...body];\n};\n\nconst endsLine = (element: SlackRichTextBlockElement): boolean =>\n /[\\n\\r\\u2028\\u2029]$/u.test(richTextElementText(element));\n\n// Slack runs adjacent sections together, so a section followed by another ends\n// its line unless its rendered text already does.\nconst breakSections = (\n elements: readonly SlackRichTextBlockElement[]\n): SlackRichTextBlockElement[] =>\n elements.map((element, index) =>\n element.type === 'rich_text_section' &&\n elements[index + 1]?.type === 'rich_text_section' &&\n !endsLine(element)\n ? richSection([...element.elements, textRun('\\n')])\n : element\n );\n\n// Graphemes, and the code points of any grapheme past `max`.\nconst textUnits = (text: string, max: number): string[] =>\n Array.from(\n new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text),\n ({ segment }) => (segment.length > max ? Array.from(segment) : [segment])\n ).flat();\n\n/**\n * A section, quote, or preformatted element past `sectionTextChars` as adjacent ones of its type, with nothing added between them; a list comes back as is.\n * A link or tag no longer than that stays whole; anything longer splits at grapheme boundaries into inlines of its own type, a link's label (or URL) across links to the same URL.\n */\nconst splitRichTextElement = (\n element: SlackRichTextBlockElement\n): SlackRichTextBlockElement[] => {\n const max = SLACK_LIMITS.sectionTextChars;\n if (\n element.type === 'rich_text_list' ||\n richTextElementText(element).length <= max\n ) {\n return [element];\n }\n const chunks: SlackRichTextInline[][] = [];\n let chunk: SlackRichTextInline[] = [];\n let room: number = max;\n const flush = (): void => {\n if (chunk.length > 0) {\n chunks.push(chunk);\n }\n chunk = [];\n room = max;\n };\n for (const inline of element.elements) {\n const whole = richTextInlineText(inline);\n if (inline.type !== 'text' && whole.length <= max) {\n if (whole.length > room) {\n flush();\n }\n chunk.push(inline);\n room -= whole.length;\n continue;\n }\n let text = '';\n for (const unit of textUnits(whole, max)) {\n if (text.length + unit.length > room) {\n if (text) {\n chunk.push({ ...inline, text });\n }\n flush();\n text = '';\n }\n text += unit;\n }\n if (text) {\n chunk.push({ ...inline, text });\n room -= text.length;\n }\n }\n flush();\n return chunks.map((elements) => ({ ...element, elements }));\n};\n\n// A table Slack would reject is replaced by one `rich_text` block. Each row's\n// columns run `heading: cell` to the wider of the header and the row, and a\n// blank section parts the rows. A cell keeps its inlines, styles, and blocks; a\n// table whose rows past the header have no cells prints its headings, and one\n// with nothing to print is dropped.\nconst degradeTable = ({\n rows: [header = [], ...body],\n}: SlackTableBlock): SlackBlock[] => {\n const rows = body.filter((row) => row.length > 0);\n const pieces =\n rows.length === 0\n ? [\n header\n .filter((heading) => !isBlank(heading))\n .flatMap((heading) => cellElements(heading).map(boldElement)),\n ]\n : rows.map((row) =>\n Array.from(\n { length: Math.max(header.length, row.length) },\n (_, column) => columnElements(header[column], row[column])\n ).flat()\n );\n const elements = pieces\n .filter((piece) => piece.length > 0)\n .flatMap((piece, index) => (index > 0 ? [rowBreak(), ...piece] : piece));\n return elements.length === 0\n ? []\n : [\n {\n type: 'rich_text',\n elements: breakSections(elements).flatMap(splitRichTextElement),\n },\n ];\n};\n\nconst fitsTableShape = ({ rows }: SlackTableBlock): boolean =>\n rows.length > 0 &&\n rows.length <= SLACK_LIMITS.tableRows &&\n rows.every(\n (row) => row.length > 0 && row.length <= SLACK_LIMITS.tableColumns\n );\n\n// Slack counts table cell characters across the whole message, not per block,\n// so a composition whose tables individually fit can still be rejected. In\n// document order, a table is kept if its shape fits and its cells fit what the\n// kept ones left.\nconst enforceTableLimits = (blocks: readonly SlackBlock[]): SlackBlock[] => {\n let spent = 0;\n const fit = (block: SlackBlock): SlackBlock[] => {\n if (isContainer(block)) {\n return containerWithChildren(block, block.child_blocks.flatMap(fit));\n }\n if (block.type !== 'table' || isUnmodeledSlackBlock(block)) {\n return [block];\n }\n const cost = tableCharCount(block);\n if (\n fitsTableShape(block) &&\n spent + cost <= SLACK_LIMITS.tableCellCharsPerMessage\n ) {\n spent += cost;\n return [block];\n }\n return degradeTable(block);\n };\n return blocks.flatMap(fit);\n};\n\nconst enforceBlockBudget = (blocks: SlackBlock[]): SlackBlock[] => {\n if (blocks.length <= SLACK_LIMITS.blocksPerMessage) {\n return blocks;\n }\n const trimmed = [...blocks];\n for (\n let index = trimmed.length - 1;\n index >= 0 && trimmed.length > SLACK_LIMITS.blocksPerMessage;\n index -= 1\n ) {\n if (isSpacer(trimmed[index]!)) {\n trimmed.splice(index, 1);\n }\n }\n if (trimmed.length <= SLACK_LIMITS.blocksPerMessage) {\n return trimmed;\n }\n return truncateWithNotice(trimmed);\n};\n"]}
|
|
@@ -30,12 +30,24 @@ export declare const codeBlock: (text: string) => string;
|
|
|
30
30
|
* backslash, whitespace, or non-ASCII, passes.
|
|
31
31
|
*/
|
|
32
32
|
export declare const isAbsoluteHttpUrl: (url: string) => boolean;
|
|
33
|
+
/** Where Slack output's relative links resolve. */
|
|
34
|
+
export interface SlackLinkOptions {
|
|
35
|
+
/** Absolute `http(s)` URL a relative link resolves against; without it, a relative link prints its label. */
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Throws `INVALID_BASE_URL` unless `baseUrl` is absent or an `http:` or
|
|
40
|
+
* `https:` URL with a DNS or IPv6 host and no credentials.
|
|
41
|
+
*/
|
|
42
|
+
export declare const assertSlackBaseUrl: (baseUrl: string | undefined) => void;
|
|
33
43
|
/**
|
|
34
44
|
* `href` when {@link sanitizeNavigationHref} passes it and it is an `http:` or
|
|
35
45
|
* `https:` URL with a host, or a `mailto:` of well-formed mailboxes; `null`
|
|
36
|
-
* otherwise. Slack has no page to resolve a relative URL against
|
|
46
|
+
* otherwise. Slack has no page to resolve a relative URL against, so one links
|
|
47
|
+
* only when `baseUrl` is given, resolved onto its origin; a fragment, such as
|
|
48
|
+
* `BLOCKED_HREF`, never resolves.
|
|
37
49
|
*/
|
|
38
|
-
export declare const slackLinkUrl: (href: string) => string | null;
|
|
50
|
+
export declare const slackLinkUrl: (href: string, baseUrl?: string) => string | null;
|
|
39
51
|
/**
|
|
40
52
|
* Slack mrkdwn link, `<url|label>`, or a bare `<url>` when `label` is omitted.
|
|
41
53
|
*
|
|
@@ -44,7 +56,7 @@ export declare const slackLinkUrl: (href: string) => string | null;
|
|
|
44
56
|
* early. A URL {@link slackLinkUrl} rejects degrades to plain escaped text
|
|
45
57
|
* with no link.
|
|
46
58
|
*/
|
|
47
|
-
export declare const link: (url: string, label?: string) => string;
|
|
59
|
+
export declare const link: (url: string, label?: string, baseUrl?: string) => string;
|
|
48
60
|
/**
|
|
49
61
|
* Truncates `value` to `max` UTF-16 code units at a grapheme boundary,
|
|
50
62
|
* appending an ellipsis when it had to cut. Pass a `SLACK_LIMITS` constant as
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/render/slack/format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/render/slack/format.ts"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MACuB,CAAC;AAErE,yDAAyD;AACzD,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,MAAmC,CAAC;AACxE,2DAA2D;AAC3D,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,KAAG,MAAmC,CAAC;AAC1E,kEAAkE;AAClE,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,KAAG,MAAmC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,MACG,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MACe,CAAC;AAgCzD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,KAAG,OAM/C,CAAC;AAmCF,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,6GAA6G;IAC7G,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,IAOhE,CAAC;AAoBF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,GAAG,IAWtE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,GAAI,KAAK,MAAM,EAAE,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAUpE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,KAAG,MAgB3D,CAAC;AAgBF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,KAAG,MAiBxD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,KAAK,MAAM,KAAG,MAG1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,MAI9C,CAAC"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// would parse as auto-link with no label.
|
|
15
15
|
//
|
|
16
16
|
// See https://api.slack.com/reference/surfaces/formatting
|
|
17
|
+
import { IsomerError } from '../../composition/error.js';
|
|
17
18
|
import { sanitizeNavigationHref } from '../../validate/url.js';
|
|
18
19
|
import { SLACK_LIMITS } from './blocks.js';
|
|
19
20
|
const MRKDWN_ESCAPES = {
|
|
@@ -109,17 +110,65 @@ const isMailtoUrl = (url) => {
|
|
|
109
110
|
.split(',')
|
|
110
111
|
.every((recipient) => isMailbox(decoded(recipient) ?? '')));
|
|
111
112
|
};
|
|
113
|
+
// Parsed rather than checked as written: a base is only resolved against, so
|
|
114
|
+
// a default port or an uppercase host is fine.
|
|
115
|
+
const isSlackBaseUrl = (baseUrl) => {
|
|
116
|
+
let parsed;
|
|
117
|
+
try {
|
|
118
|
+
parsed = new URL(baseUrl);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return ((parsed.protocol === 'http:' || parsed.protocol === 'https:') &&
|
|
124
|
+
parsed.username === '' &&
|
|
125
|
+
parsed.password === '' &&
|
|
126
|
+
(DNS_NAME_RE.test(parsed.hostname) || IPV6_HOST_RE.test(parsed.hostname)));
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Throws `INVALID_BASE_URL` unless `baseUrl` is absent or an `http:` or
|
|
130
|
+
* `https:` URL with a DNS or IPv6 host and no credentials.
|
|
131
|
+
*/
|
|
132
|
+
export const assertSlackBaseUrl = (baseUrl) => {
|
|
133
|
+
if (baseUrl !== undefined && !isSlackBaseUrl(baseUrl)) {
|
|
134
|
+
throw new IsomerError('INVALID_BASE_URL', `Slack baseUrl must be an absolute http or https URL without credentials, got "${baseUrl}"`);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const HAS_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
|
|
138
|
+
// A relative path resolved onto the base's origin, or `null` when it would
|
|
139
|
+
// leave that origin. A fragment, `BLOCKED_HREF` included, names a place in a
|
|
140
|
+
// document Slack does not show, so it never resolves.
|
|
141
|
+
const resolvedOnBase = (url, baseUrl) => {
|
|
142
|
+
if (url.startsWith('#') || HAS_SCHEME_RE.test(url)) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
let resolved;
|
|
146
|
+
try {
|
|
147
|
+
resolved = new URL(url, baseUrl);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
return resolved.origin === new URL(baseUrl).origin ? resolved.href : null;
|
|
153
|
+
};
|
|
112
154
|
/**
|
|
113
155
|
* `href` when {@link sanitizeNavigationHref} passes it and it is an `http:` or
|
|
114
156
|
* `https:` URL with a host, or a `mailto:` of well-formed mailboxes; `null`
|
|
115
|
-
* otherwise. Slack has no page to resolve a relative URL against
|
|
157
|
+
* otherwise. Slack has no page to resolve a relative URL against, so one links
|
|
158
|
+
* only when `baseUrl` is given, resolved onto its origin; a fragment, such as
|
|
159
|
+
* `BLOCKED_HREF`, never resolves.
|
|
116
160
|
*/
|
|
117
|
-
export const slackLinkUrl = (href) => {
|
|
161
|
+
export const slackLinkUrl = (href, baseUrl) => {
|
|
162
|
+
assertSlackBaseUrl(baseUrl);
|
|
118
163
|
const url = sanitizeNavigationHref(href);
|
|
119
164
|
if (url === null) {
|
|
120
165
|
return null;
|
|
121
166
|
}
|
|
122
|
-
|
|
167
|
+
if (isAbsoluteHttpUrl(url) || isMailtoUrl(url)) {
|
|
168
|
+
return url;
|
|
169
|
+
}
|
|
170
|
+
const resolved = baseUrl === undefined ? null : resolvedOnBase(url, baseUrl);
|
|
171
|
+
return resolved === null ? null : slackLinkUrl(resolved);
|
|
123
172
|
};
|
|
124
173
|
/**
|
|
125
174
|
* Slack mrkdwn link, `<url|label>`, or a bare `<url>` when `label` is omitted.
|
|
@@ -129,8 +178,8 @@ export const slackLinkUrl = (href) => {
|
|
|
129
178
|
* early. A URL {@link slackLinkUrl} rejects degrades to plain escaped text
|
|
130
179
|
* with no link.
|
|
131
180
|
*/
|
|
132
|
-
export const link = (url, label) => {
|
|
133
|
-
const sanitized = slackLinkUrl(url);
|
|
181
|
+
export const link = (url, label, baseUrl) => {
|
|
182
|
+
const sanitized = slackLinkUrl(url, baseUrl);
|
|
134
183
|
if (!sanitized) {
|
|
135
184
|
return escapeMrkdwn(label ?? url);
|
|
136
185
|
}
|