@elastic/isomer-sdk 0.0.0 → 0.2.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/LICENSE.txt +93 -0
- package/NOTICE.txt +1861 -0
- package/README.md +69 -0
- package/THIRD_PARTY_LICENSES.md +957 -0
- package/dist/author/authored_fields.d.ts +153 -0
- package/dist/author/authored_fields.d.ts.map +1 -0
- package/dist/author/authored_fields.js +227 -0
- package/dist/author/authored_fields.js.map +1 -0
- package/dist/author/authoring_input.d.ts +7 -0
- package/dist/author/authoring_input.d.ts.map +1 -0
- package/dist/author/authoring_input.js +60 -0
- package/dist/author/authoring_input.js.map +1 -0
- package/dist/author/authoring_model.d.ts +27 -0
- package/dist/author/authoring_model.d.ts.map +1 -0
- package/dist/author/authoring_model.js +98 -0
- package/dist/author/authoring_model.js.map +1 -0
- package/dist/author/declarations.d.ts +13 -0
- package/dist/author/declarations.d.ts.map +1 -0
- package/dist/author/declarations.js +277 -0
- package/dist/author/declarations.js.map +1 -0
- package/dist/author/index.d.ts +7 -0
- package/dist/author/index.d.ts.map +1 -0
- package/dist/author/index.js +12 -0
- package/dist/author/index.js.map +1 -0
- package/dist/author/jsx.d.ts +21 -0
- package/dist/author/jsx.d.ts.map +1 -0
- package/dist/author/jsx.js +20 -0
- package/dist/author/jsx.js.map +1 -0
- package/dist/author/jsx_shim.d.ts +117 -0
- package/dist/author/jsx_shim.d.ts.map +1 -0
- package/dist/author/jsx_shim.js +270 -0
- package/dist/author/jsx_shim.js.map +1 -0
- package/dist/author/prompt.d.ts +58 -0
- package/dist/author/prompt.d.ts.map +1 -0
- package/dist/author/prompt.js +148 -0
- package/dist/author/prompt.js.map +1 -0
- package/dist/author/schema_to_typescript.d.ts +37 -0
- package/dist/author/schema_to_typescript.d.ts.map +1 -0
- package/dist/author/schema_to_typescript.js +286 -0
- package/dist/author/schema_to_typescript.js.map +1 -0
- package/dist/cjs/author/authored_fields.js +233 -0
- package/dist/cjs/author/authored_fields.js.map +1 -0
- package/dist/cjs/author/authoring_input.js +64 -0
- package/dist/cjs/author/authoring_input.js.map +1 -0
- package/dist/cjs/author/authoring_model.js +104 -0
- package/dist/cjs/author/authoring_model.js.map +1 -0
- package/dist/cjs/author/declarations.js +281 -0
- package/dist/cjs/author/declarations.js.map +1 -0
- package/dist/cjs/author/index.js +25 -0
- package/dist/cjs/author/index.js.map +1 -0
- package/dist/cjs/author/jsx.js +24 -0
- package/dist/cjs/author/jsx.js.map +1 -0
- package/dist/cjs/author/jsx_shim.js +276 -0
- package/dist/cjs/author/jsx_shim.js.map +1 -0
- package/dist/cjs/author/prompt.js +153 -0
- package/dist/cjs/author/prompt.js.map +1 -0
- package/dist/cjs/author/schema_to_typescript.js +295 -0
- package/dist/cjs/author/schema_to_typescript.js.map +1 -0
- package/dist/cjs/composition/action_event.js +9 -0
- package/dist/cjs/composition/action_event.js.map +1 -0
- package/dist/cjs/composition/body_node_base.js +112 -0
- package/dist/cjs/composition/body_node_base.js.map +1 -0
- package/dist/cjs/composition/composition.js +9 -0
- package/dist/cjs/composition/composition.js.map +1 -0
- package/dist/cjs/composition/error.js +73 -0
- package/dist/cjs/composition/error.js.map +1 -0
- package/dist/cjs/composition/index.js +32 -0
- package/dist/cjs/composition/index.js.map +1 -0
- package/dist/cjs/composition/map_nodes.js +85 -0
- package/dist/cjs/composition/map_nodes.js.map +1 -0
- package/dist/cjs/composition/named_color.js +20 -0
- package/dist/cjs/composition/named_color.js.map +1 -0
- package/dist/cjs/composition/node.js +9 -0
- package/dist/cjs/composition/node.js.map +1 -0
- package/dist/cjs/composition/one_line.js +23 -0
- package/dist/cjs/composition/one_line.js.map +1 -0
- package/dist/cjs/composition/structured_value.js +21 -0
- package/dist/cjs/composition/structured_value.js.map +1 -0
- package/dist/cjs/composition/validation_error.js +40 -0
- package/dist/cjs/composition/validation_error.js.map +1 -0
- package/dist/cjs/define/frame.js +31 -0
- package/dist/cjs/define/frame.js.map +1 -0
- package/dist/cjs/define/index.js +31 -0
- package/dist/cjs/define/index.js.map +1 -0
- package/dist/cjs/define/markdown_content.js +12 -0
- package/dist/cjs/define/markdown_content.js.map +1 -0
- package/dist/cjs/define/primitive_example.js +26 -0
- package/dist/cjs/define/primitive_example.js.map +1 -0
- package/dist/cjs/define/primitive_icon.js +17 -0
- package/dist/cjs/define/primitive_icon.js.map +1 -0
- package/dist/cjs/define/primitive_module.js +118 -0
- package/dist/cjs/define/primitive_module.js.map +1 -0
- package/dist/cjs/define/slack_assets.js +9 -0
- package/dist/cjs/define/slack_assets.js.map +1 -0
- package/dist/cjs/define/slack_blocks.js +9 -0
- package/dist/cjs/define/slack_blocks.js.map +1 -0
- package/dist/cjs/define/zod_format.js +122 -0
- package/dist/cjs/define/zod_format.js.map +1 -0
- package/dist/cjs/define/zod_helpers.js +26 -0
- package/dist/cjs/define/zod_helpers.js.map +1 -0
- package/dist/cjs/entries/html.js +12 -0
- package/dist/cjs/entries/html.js.map +1 -0
- package/dist/cjs/entries/index.js +80 -0
- package/dist/cjs/entries/index.js.map +1 -0
- package/dist/cjs/entries/markdown.js +14 -0
- package/dist/cjs/entries/markdown.js.map +1 -0
- package/dist/cjs/entries/react.js +20 -0
- package/dist/cjs/entries/react.js.map +1 -0
- package/dist/cjs/entries/slack.js +25 -0
- package/dist/cjs/entries/slack.js.map +1 -0
- package/dist/cjs/entries/text.js +12 -0
- package/dist/cjs/entries/text.js.map +1 -0
- package/dist/cjs/pack/capabilities.js +40 -0
- package/dist/cjs/pack/capabilities.js.map +1 -0
- package/dist/cjs/pack/compose.js +59 -0
- package/dist/cjs/pack/compose.js.map +1 -0
- package/dist/cjs/pack/enhancements.js +65 -0
- package/dist/cjs/pack/enhancements.js.map +1 -0
- package/dist/cjs/pack/index.js +18 -0
- package/dist/cjs/pack/index.js.map +1 -0
- package/dist/cjs/pack/primitive_pack.js +97 -0
- package/dist/cjs/pack/primitive_pack.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/render/anchors.js +167 -0
- package/dist/cjs/render/anchors.js.map +1 -0
- package/dist/cjs/render/context_view.js +54 -0
- package/dist/cjs/render/context_view.js.map +1 -0
- package/dist/cjs/render/format_display_value.js +143 -0
- package/dist/cjs/render/format_display_value.js.map +1 -0
- package/dist/cjs/render/format_number.js +46 -0
- package/dist/cjs/render/format_number.js.map +1 -0
- package/dist/cjs/render/html/enhancements.js +30 -0
- package/dist/cjs/render/html/enhancements.js.map +1 -0
- package/dist/cjs/render/html/envelope.js +218 -0
- package/dist/cjs/render/html/envelope.js.map +1 -0
- package/dist/cjs/render/html/index.js +12 -0
- package/dist/cjs/render/html/index.js.map +1 -0
- package/dist/cjs/render/index.js +25 -0
- package/dist/cjs/render/index.js.map +1 -0
- package/dist/cjs/render/layout_check.js +133 -0
- package/dist/cjs/render/layout_check.js.map +1 -0
- package/dist/cjs/render/markdown/builder.js +195 -0
- package/dist/cjs/render/markdown/builder.js.map +1 -0
- package/dist/cjs/render/markdown/envelope.js +33 -0
- package/dist/cjs/render/markdown/envelope.js.map +1 -0
- package/dist/cjs/render/markdown/format.js +208 -0
- package/dist/cjs/render/markdown/format.js.map +1 -0
- package/dist/cjs/render/markdown/index.js +15 -0
- package/dist/cjs/render/markdown/index.js.map +1 -0
- package/dist/cjs/render/measure_dom.js +61 -0
- package/dist/cjs/render/measure_dom.js.map +1 -0
- package/dist/cjs/render/payload.js +13 -0
- package/dist/cjs/render/payload.js.map +1 -0
- package/dist/cjs/render/primitive_dispatch.js +173 -0
- package/dist/cjs/render/primitive_dispatch.js.map +1 -0
- package/dist/cjs/render/react/content.js +44 -0
- package/dist/cjs/render/react/content.js.map +1 -0
- package/dist/cjs/render/react/enhancements.js +32 -0
- package/dist/cjs/render/react/enhancements.js.map +1 -0
- package/dist/cjs/render/react/index.js +15 -0
- package/dist/cjs/render/react/index.js.map +1 -0
- package/dist/cjs/render/slack/assets.js +45 -0
- package/dist/cjs/render/slack/assets.js.map +1 -0
- package/dist/cjs/render/slack/blocks.js +80 -0
- package/dist/cjs/render/slack/blocks.js.map +1 -0
- package/dist/cjs/render/slack/envelope.js +551 -0
- package/dist/cjs/render/slack/envelope.js.map +1 -0
- package/dist/cjs/render/slack/format.js +225 -0
- package/dist/cjs/render/slack/format.js.map +1 -0
- package/dist/cjs/render/slack/index.js +30 -0
- package/dist/cjs/render/slack/index.js.map +1 -0
- package/dist/cjs/render/slack/markdown_content.js +409 -0
- package/dist/cjs/render/slack/markdown_content.js.map +1 -0
- package/dist/cjs/render/text/envelope.js +21 -0
- package/dist/cjs/render/text/envelope.js.map +1 -0
- package/dist/cjs/render/text/index.js +12 -0
- package/dist/cjs/render/text/index.js.map +1 -0
- package/dist/cjs/testing/conformance.js +312 -0
- package/dist/cjs/testing/conformance.js.map +1 -0
- package/dist/cjs/testing/icon.js +248 -0
- package/dist/cjs/testing/icon.js.map +1 -0
- package/dist/cjs/testing/index.js +18 -0
- package/dist/cjs/testing/index.js.map +1 -0
- package/dist/cjs/testing/registration.js +142 -0
- package/dist/cjs/testing/registration.js.map +1 -0
- package/dist/cjs/validate/authoring_schema.js +312 -0
- package/dist/cjs/validate/authoring_schema.js.map +1 -0
- package/dist/cjs/validate/composition_schema.js +135 -0
- package/dist/cjs/validate/composition_schema.js.map +1 -0
- package/dist/cjs/validate/index.js +53 -0
- package/dist/cjs/validate/index.js.map +1 -0
- package/dist/cjs/validate/input_budget.js +156 -0
- package/dist/cjs/validate/input_budget.js.map +1 -0
- package/dist/cjs/validate/json_schema.js +72 -0
- package/dist/cjs/validate/json_schema.js.map +1 -0
- package/dist/cjs/validate/node_issues.js +65 -0
- package/dist/cjs/validate/node_issues.js.map +1 -0
- package/dist/cjs/validate/url.js +116 -0
- package/dist/cjs/validate/url.js.map +1 -0
- package/dist/cjs/validate/validation.js +165 -0
- package/dist/cjs/validate/validation.js.map +1 -0
- package/dist/cjs/validate/value_schemas.js +53 -0
- package/dist/cjs/validate/value_schemas.js.map +1 -0
- package/dist/composition/action_event.d.ts +13 -0
- package/dist/composition/action_event.d.ts.map +1 -0
- package/dist/composition/action_event.js +8 -0
- package/dist/composition/action_event.js.map +1 -0
- package/dist/composition/body_node_base.d.ts +72 -0
- package/dist/composition/body_node_base.d.ts.map +1 -0
- package/dist/composition/body_node_base.js +104 -0
- package/dist/composition/body_node_base.js.map +1 -0
- package/dist/composition/composition.d.ts +71 -0
- package/dist/composition/composition.d.ts.map +1 -0
- package/dist/composition/composition.js +8 -0
- package/dist/composition/composition.js.map +1 -0
- package/dist/composition/error.d.ts +61 -0
- package/dist/composition/error.d.ts.map +1 -0
- package/dist/composition/error.js +69 -0
- package/dist/composition/error.js.map +1 -0
- package/dist/composition/index.d.ts +11 -0
- package/dist/composition/index.d.ts.map +1 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/index.js.map +1 -0
- package/dist/composition/map_nodes.d.ts +16 -0
- package/dist/composition/map_nodes.d.ts.map +1 -0
- package/dist/composition/map_nodes.js +81 -0
- package/dist/composition/map_nodes.js.map +1 -0
- package/dist/composition/named_color.d.ts +9 -0
- package/dist/composition/named_color.d.ts.map +1 -0
- package/dist/composition/named_color.js +17 -0
- package/dist/composition/named_color.js.map +1 -0
- package/dist/composition/node.d.ts +11 -0
- package/dist/composition/node.d.ts.map +1 -0
- package/dist/composition/node.js +8 -0
- package/dist/composition/node.js.map +1 -0
- package/dist/composition/one_line.d.ts +7 -0
- package/dist/composition/one_line.d.ts.map +1 -0
- package/dist/composition/one_line.js +17 -0
- package/dist/composition/one_line.js.map +1 -0
- package/dist/composition/structured_value.d.ts +27 -0
- package/dist/composition/structured_value.d.ts.map +1 -0
- package/dist/composition/structured_value.js +18 -0
- package/dist/composition/structured_value.js.map +1 -0
- package/dist/composition/validation_error.d.ts +33 -0
- package/dist/composition/validation_error.d.ts.map +1 -0
- package/dist/composition/validation_error.js +35 -0
- package/dist/composition/validation_error.js.map +1 -0
- package/dist/define/frame.d.ts +155 -0
- package/dist/define/frame.d.ts.map +1 -0
- package/dist/define/frame.js +27 -0
- package/dist/define/frame.js.map +1 -0
- package/dist/define/index.d.ts +10 -0
- package/dist/define/index.d.ts.map +1 -0
- package/dist/define/index.js +13 -0
- package/dist/define/index.js.map +1 -0
- package/dist/define/markdown_content.d.ts +15 -0
- package/dist/define/markdown_content.d.ts.map +1 -0
- package/dist/define/markdown_content.js +9 -0
- package/dist/define/markdown_content.js.map +1 -0
- package/dist/define/primitive_example.d.ts +30 -0
- package/dist/define/primitive_example.d.ts.map +1 -0
- package/dist/define/primitive_example.js +21 -0
- package/dist/define/primitive_example.js.map +1 -0
- package/dist/define/primitive_icon.d.ts +11 -0
- package/dist/define/primitive_icon.d.ts.map +1 -0
- package/dist/define/primitive_icon.js +14 -0
- package/dist/define/primitive_icon.js.map +1 -0
- package/dist/define/primitive_module.d.ts +435 -0
- package/dist/define/primitive_module.d.ts.map +1 -0
- package/dist/define/primitive_module.js +112 -0
- package/dist/define/primitive_module.js.map +1 -0
- package/dist/define/slack_assets.d.ts +28 -0
- package/dist/define/slack_assets.d.ts.map +1 -0
- package/dist/define/slack_assets.js +8 -0
- package/dist/define/slack_assets.js.map +1 -0
- package/dist/define/slack_blocks.d.ts +234 -0
- package/dist/define/slack_blocks.d.ts.map +1 -0
- package/dist/define/slack_blocks.js +8 -0
- package/dist/define/slack_blocks.js.map +1 -0
- package/dist/define/zod_format.d.ts +33 -0
- package/dist/define/zod_format.d.ts.map +1 -0
- package/dist/define/zod_format.js +114 -0
- package/dist/define/zod_format.js.map +1 -0
- package/dist/define/zod_helpers.d.ts +10 -0
- package/dist/define/zod_helpers.d.ts.map +1 -0
- package/dist/define/zod_helpers.js +22 -0
- package/dist/define/zod_helpers.js.map +1 -0
- package/dist/entries/html.d.ts +3 -0
- package/dist/entries/html.d.ts.map +1 -0
- package/dist/entries/html.js +8 -0
- package/dist/entries/html.js.map +1 -0
- package/dist/entries/index.d.ts +6 -0
- package/dist/entries/index.d.ts.map +1 -0
- package/dist/entries/index.js +12 -0
- package/dist/entries/index.js.map +1 -0
- package/dist/entries/markdown.d.ts +3 -0
- package/dist/entries/markdown.d.ts.map +1 -0
- package/dist/entries/markdown.js +8 -0
- package/dist/entries/markdown.js.map +1 -0
- package/dist/entries/react.d.ts +5 -0
- package/dist/entries/react.d.ts.map +1 -0
- package/dist/entries/react.js +11 -0
- package/dist/entries/react.js.map +1 -0
- package/dist/entries/slack.d.ts +2 -0
- package/dist/entries/slack.d.ts.map +1 -0
- package/dist/entries/slack.js +8 -0
- package/dist/entries/slack.js.map +1 -0
- package/dist/entries/text.d.ts +2 -0
- package/dist/entries/text.d.ts.map +1 -0
- package/dist/entries/text.js +8 -0
- package/dist/entries/text.js.map +1 -0
- package/dist/pack/capabilities.d.ts +41 -0
- package/dist/pack/capabilities.d.ts.map +1 -0
- package/dist/pack/capabilities.js +36 -0
- package/dist/pack/capabilities.js.map +1 -0
- package/dist/pack/compose.d.ts +24 -0
- package/dist/pack/compose.d.ts.map +1 -0
- package/dist/pack/compose.js +55 -0
- package/dist/pack/compose.js.map +1 -0
- package/dist/pack/enhancements.d.ts +65 -0
- package/dist/pack/enhancements.d.ts.map +1 -0
- package/dist/pack/enhancements.js +59 -0
- package/dist/pack/enhancements.js.map +1 -0
- package/dist/pack/index.d.ts +5 -0
- package/dist/pack/index.d.ts.map +1 -0
- package/dist/pack/index.js +11 -0
- package/dist/pack/index.js.map +1 -0
- package/dist/pack/primitive_pack.d.ts +164 -0
- package/dist/pack/primitive_pack.d.ts.map +1 -0
- package/dist/pack/primitive_pack.js +92 -0
- package/dist/pack/primitive_pack.js.map +1 -0
- package/dist/render/anchors.d.ts +82 -0
- package/dist/render/anchors.d.ts.map +1 -0
- package/dist/render/anchors.js +153 -0
- package/dist/render/anchors.js.map +1 -0
- package/dist/render/context_view.d.ts +10 -0
- package/dist/render/context_view.d.ts.map +1 -0
- package/dist/render/context_view.js +49 -0
- package/dist/render/context_view.js.map +1 -0
- package/dist/render/format_display_value.d.ts +20 -0
- package/dist/render/format_display_value.d.ts.map +1 -0
- package/dist/render/format_display_value.js +137 -0
- package/dist/render/format_display_value.js.map +1 -0
- package/dist/render/format_number.d.ts +9 -0
- package/dist/render/format_number.d.ts.map +1 -0
- package/dist/render/format_number.js +42 -0
- package/dist/render/format_number.js.map +1 -0
- package/dist/render/html/enhancements.d.ts +10 -0
- package/dist/render/html/enhancements.d.ts.map +1 -0
- package/dist/render/html/enhancements.js +25 -0
- package/dist/render/html/enhancements.js.map +1 -0
- package/dist/render/html/envelope.d.ts +182 -0
- package/dist/render/html/envelope.d.ts.map +1 -0
- package/dist/render/html/envelope.js +214 -0
- package/dist/render/html/envelope.js.map +1 -0
- package/dist/render/html/index.d.ts +3 -0
- package/dist/render/html/index.d.ts.map +1 -0
- package/dist/render/html/index.js +8 -0
- package/dist/render/html/index.js.map +1 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +11 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/layout_check.d.ts +43 -0
- package/dist/render/layout_check.d.ts.map +1 -0
- package/dist/render/layout_check.js +129 -0
- package/dist/render/layout_check.js.map +1 -0
- package/dist/render/markdown/builder.d.ts +46 -0
- package/dist/render/markdown/builder.d.ts.map +1 -0
- package/dist/render/markdown/builder.js +190 -0
- package/dist/render/markdown/builder.js.map +1 -0
- package/dist/render/markdown/envelope.d.ts +20 -0
- package/dist/render/markdown/envelope.d.ts.map +1 -0
- package/dist/render/markdown/envelope.js +29 -0
- package/dist/render/markdown/envelope.js.map +1 -0
- package/dist/render/markdown/format.d.ts +10 -0
- package/dist/render/markdown/format.d.ts.map +1 -0
- package/dist/render/markdown/format.js +202 -0
- package/dist/render/markdown/format.js.map +1 -0
- package/dist/render/markdown/index.d.ts +3 -0
- package/dist/render/markdown/index.d.ts.map +1 -0
- package/dist/render/markdown/index.js +9 -0
- package/dist/render/markdown/index.js.map +1 -0
- package/dist/render/measure_dom.d.ts +10 -0
- package/dist/render/measure_dom.d.ts.map +1 -0
- package/dist/render/measure_dom.js +57 -0
- package/dist/render/measure_dom.js.map +1 -0
- package/dist/render/payload.d.ts +16 -0
- package/dist/render/payload.d.ts.map +1 -0
- package/dist/render/payload.js +9 -0
- package/dist/render/payload.js.map +1 -0
- package/dist/render/primitive_dispatch.d.ts +72 -0
- package/dist/render/primitive_dispatch.d.ts.map +1 -0
- package/dist/render/primitive_dispatch.js +169 -0
- package/dist/render/primitive_dispatch.js.map +1 -0
- package/dist/render/react/content.d.ts +40 -0
- package/dist/render/react/content.d.ts.map +1 -0
- package/dist/render/react/content.js +39 -0
- package/dist/render/react/content.js.map +1 -0
- package/dist/render/react/enhancements.d.ts +15 -0
- package/dist/render/react/enhancements.d.ts.map +1 -0
- package/dist/render/react/enhancements.js +28 -0
- package/dist/render/react/enhancements.js.map +1 -0
- package/dist/render/react/index.d.ts +3 -0
- package/dist/render/react/index.d.ts.map +1 -0
- package/dist/render/react/index.js +9 -0
- package/dist/render/react/index.js.map +1 -0
- package/dist/render/slack/assets.d.ts +16 -0
- package/dist/render/slack/assets.d.ts.map +1 -0
- package/dist/render/slack/assets.js +40 -0
- package/dist/render/slack/assets.js.map +1 -0
- package/dist/render/slack/blocks.d.ts +72 -0
- package/dist/render/slack/blocks.d.ts.map +1 -0
- package/dist/render/slack/blocks.js +77 -0
- package/dist/render/slack/blocks.js.map +1 -0
- package/dist/render/slack/envelope.d.ts +52 -0
- package/dist/render/slack/envelope.d.ts.map +1 -0
- package/dist/render/slack/envelope.js +547 -0
- package/dist/render/slack/envelope.js.map +1 -0
- package/dist/render/slack/format.d.ts +70 -0
- package/dist/render/slack/format.d.ts.map +1 -0
- package/dist/render/slack/format.js +209 -0
- package/dist/render/slack/format.js.map +1 -0
- package/dist/render/slack/index.d.ts +6 -0
- package/dist/render/slack/index.d.ts.map +1 -0
- package/dist/render/slack/index.js +12 -0
- package/dist/render/slack/index.js.map +1 -0
- package/dist/render/slack/markdown_content.d.ts +17 -0
- package/dist/render/slack/markdown_content.d.ts.map +1 -0
- package/dist/render/slack/markdown_content.js +404 -0
- package/dist/render/slack/markdown_content.js.map +1 -0
- package/dist/render/text/envelope.d.ts +15 -0
- package/dist/render/text/envelope.d.ts.map +1 -0
- package/dist/render/text/envelope.js +17 -0
- package/dist/render/text/envelope.js.map +1 -0
- package/dist/render/text/index.d.ts +2 -0
- package/dist/render/text/index.d.ts.map +1 -0
- package/dist/render/text/index.js +8 -0
- package/dist/render/text/index.js.map +1 -0
- package/dist/testing/conformance.d.ts +145 -0
- package/dist/testing/conformance.d.ts.map +1 -0
- package/dist/testing/conformance.js +303 -0
- package/dist/testing/conformance.js.map +1 -0
- package/dist/testing/icon.d.ts +11 -0
- package/dist/testing/icon.d.ts.map +1 -0
- package/dist/testing/icon.js +244 -0
- package/dist/testing/icon.js.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +10 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/registration.d.ts +32 -0
- package/dist/testing/registration.d.ts.map +1 -0
- package/dist/testing/registration.js +105 -0
- package/dist/testing/registration.js.map +1 -0
- package/dist/validate/authoring_schema.d.ts +33 -0
- package/dist/validate/authoring_schema.d.ts.map +1 -0
- package/dist/validate/authoring_schema.js +306 -0
- package/dist/validate/authoring_schema.js.map +1 -0
- package/dist/validate/composition_schema.d.ts +80 -0
- package/dist/validate/composition_schema.d.ts.map +1 -0
- package/dist/validate/composition_schema.js +127 -0
- package/dist/validate/composition_schema.js.map +1 -0
- package/dist/validate/index.d.ts +9 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +15 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/input_budget.d.ts +35 -0
- package/dist/validate/input_budget.d.ts.map +1 -0
- package/dist/validate/input_budget.js +151 -0
- package/dist/validate/input_budget.js.map +1 -0
- package/dist/validate/json_schema.d.ts +32 -0
- package/dist/validate/json_schema.d.ts.map +1 -0
- package/dist/validate/json_schema.js +68 -0
- package/dist/validate/json_schema.js.map +1 -0
- package/dist/validate/node_issues.d.ts +12 -0
- package/dist/validate/node_issues.d.ts.map +1 -0
- package/dist/validate/node_issues.js +61 -0
- package/dist/validate/node_issues.js.map +1 -0
- package/dist/validate/url.d.ts +50 -0
- package/dist/validate/url.d.ts.map +1 -0
- package/dist/validate/url.js +107 -0
- package/dist/validate/url.js.map +1 -0
- package/dist/validate/validation.d.ts +95 -0
- package/dist/validate/validation.d.ts.map +1 -0
- package/dist/validate/validation.js +157 -0
- package/dist/validate/validation.js.map +1 -0
- package/dist/validate/value_schemas.d.ts +53 -0
- package/dist/validate/value_schemas.d.ts.map +1 -0
- package/dist/validate/value_schemas.js +50 -0
- package/dist/validate/value_schemas.js.map +1 -0
- package/package.json +119 -5
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
3
|
+
* or more contributor license agreements. Licensed under the Elastic License
|
|
4
|
+
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
5
|
+
* 2.0.
|
|
6
|
+
*/
|
|
7
|
+
import { renderTextEnvelope } from '../text/envelope.js';
|
|
8
|
+
import { createSlackAssetCollector, } from './assets.js';
|
|
9
|
+
import { SLACK_LIMITS, } from './blocks.js';
|
|
10
|
+
import { clampMrkdwn, clampSlackText, cutSlackValue, escapeMrkdwn, formatHeaderText, italic, } from './format.js';
|
|
11
|
+
/**
|
|
12
|
+
* The composition as a `chat.postMessage` payload: notification `text`, blocks,
|
|
13
|
+
* and the images the host must upload first.
|
|
14
|
+
*
|
|
15
|
+
* Degradation for a node with no `slack` renderer is the dispatcher's, which
|
|
16
|
+
* has to own it to reach a child nested inside a container. The result is
|
|
17
|
+
* fitted to Slack's limits — text is clamped, blocks past a count limit and
|
|
18
|
+
* `rich_text` elements past a section's limit split, tables past a table limit
|
|
19
|
+
* or the message's cell budget become rich text, spacers and then whole blocks
|
|
20
|
+
* are dropped — so the output is always postable. `assets` stays empty
|
|
21
|
+
* unless `collectAssets` is set.
|
|
22
|
+
*/
|
|
23
|
+
export const renderSlackEnvelope = (composition, dispatcher, options = {}) => {
|
|
24
|
+
const blocks = [];
|
|
25
|
+
// The collector is opt-in: without it, charts keep their markdown/text
|
|
26
|
+
// degradation and non-reachable images degrade to a link/text section, so
|
|
27
|
+
// default output is safe for callers that cannot upload files.
|
|
28
|
+
const collector = options.collectAssets
|
|
29
|
+
? createSlackAssetCollector(options.assetPrefix === undefined ? {} : { prefix: options.assetPrefix })
|
|
30
|
+
: undefined;
|
|
31
|
+
const { heading = true } = options;
|
|
32
|
+
if (heading && composition.title) {
|
|
33
|
+
blocks.push(headerBlock(composition.title, 1));
|
|
34
|
+
}
|
|
35
|
+
if (heading && composition.subtitle) {
|
|
36
|
+
blocks.push(contextBlock([escapeMrkdwn(composition.subtitle)]));
|
|
37
|
+
}
|
|
38
|
+
for (const node of composition.body) {
|
|
39
|
+
blocks.push(...dispatcher.renderSlack(node, collector).flatMap(fitBlock));
|
|
40
|
+
}
|
|
41
|
+
// Split after the rhythm, so the fragments of one block read as one.
|
|
42
|
+
const rhythm = applySectionRhythm(coalesceFieldSections(enforceTableLimits(blocks))).flatMap(splitBlockCounts);
|
|
43
|
+
const budgeted = enforceBlockBudget(rhythm);
|
|
44
|
+
// Only ask the host to upload assets whose placeholder block survived the
|
|
45
|
+
// budget; blocks elided by `enforceBlockBudget` are never posted, so
|
|
46
|
+
// uploading their files would be wasted (and orphaned) work.
|
|
47
|
+
const keptRefs = collectSlackFileRefs(budgeted);
|
|
48
|
+
return {
|
|
49
|
+
text: clampMrkdwn(options.text ??
|
|
50
|
+
escapeMrkdwn(renderTextEnvelope(composition, dispatcher, { heading })), SLACK_LIMITS.fallbackTextChars),
|
|
51
|
+
blocks: budgeted,
|
|
52
|
+
assets: collector
|
|
53
|
+
? collector.requests.filter((request) => keptRefs.has(request.ref))
|
|
54
|
+
: [],
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const clampText = (text, max) => text.text.length <= max
|
|
58
|
+
? text
|
|
59
|
+
: {
|
|
60
|
+
...text,
|
|
61
|
+
text: (text.type === 'mrkdwn' ? clampMrkdwn : clampSlackText)(text.text, max),
|
|
62
|
+
};
|
|
63
|
+
const fitsImageUrl = ({ image_url }) => image_url === undefined || image_url.length <= SLACK_LIMITS.imageUrlChars;
|
|
64
|
+
const clampAlt = (image) => image.alt_text.length <= SLACK_LIMITS.imageAltTextChars
|
|
65
|
+
? image
|
|
66
|
+
: {
|
|
67
|
+
...image,
|
|
68
|
+
alt_text: clampSlackText(image.alt_text, SLACK_LIMITS.imageAltTextChars),
|
|
69
|
+
};
|
|
70
|
+
// A cut URL would point somewhere else, so one past the limit is dropped.
|
|
71
|
+
const withoutLongUrl = (element) => {
|
|
72
|
+
if (element.url === undefined ||
|
|
73
|
+
element.url.length <= SLACK_LIMITS.urlChars) {
|
|
74
|
+
return element;
|
|
75
|
+
}
|
|
76
|
+
const { url: _dropped, ...rest } = element;
|
|
77
|
+
return rest;
|
|
78
|
+
};
|
|
79
|
+
const optionValue = (value) => cutSlackValue(value, SLACK_LIMITS.optionValueChars);
|
|
80
|
+
const clampOption = (option) => withoutLongUrl({
|
|
81
|
+
...option,
|
|
82
|
+
text: clampText(option.text, SLACK_LIMITS.optionTextChars),
|
|
83
|
+
value: optionValue(option.value),
|
|
84
|
+
...(option.description && {
|
|
85
|
+
description: clampText(option.description, SLACK_LIMITS.optionTextChars),
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
const clampControl = (element) => {
|
|
89
|
+
const actionId = element.action_id === undefined
|
|
90
|
+
? {}
|
|
91
|
+
: {
|
|
92
|
+
action_id: cutSlackValue(element.action_id, SLACK_LIMITS.actionIdChars),
|
|
93
|
+
};
|
|
94
|
+
if (element.type === 'button') {
|
|
95
|
+
return withoutLongUrl({
|
|
96
|
+
...element,
|
|
97
|
+
...actionId,
|
|
98
|
+
text: clampText(element.text, SLACK_LIMITS.buttonTextChars),
|
|
99
|
+
...(element.value !== undefined && {
|
|
100
|
+
value: cutSlackValue(element.value, SLACK_LIMITS.buttonValueChars),
|
|
101
|
+
}),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const menu = { ...element, ...actionId };
|
|
105
|
+
const maxOptions = menu.type === 'overflow'
|
|
106
|
+
? SLACK_LIMITS.optionsPerOverflow
|
|
107
|
+
: menu.type === 'radio_buttons' || menu.type === 'checkboxes'
|
|
108
|
+
? SLACK_LIMITS.optionsPerChoice
|
|
109
|
+
: SLACK_LIMITS.optionsPerSelect;
|
|
110
|
+
if (menu.options) {
|
|
111
|
+
menu.options = menu.options.slice(0, maxOptions).map(clampOption);
|
|
112
|
+
}
|
|
113
|
+
if ('placeholder' in menu && menu.placeholder) {
|
|
114
|
+
menu.placeholder = clampText(menu.placeholder, SLACK_LIMITS.placeholderChars);
|
|
115
|
+
}
|
|
116
|
+
if ('option_groups' in menu && menu.option_groups) {
|
|
117
|
+
menu.option_groups = menu.option_groups
|
|
118
|
+
.slice(0, SLACK_LIMITS.optionGroupsPerSelect)
|
|
119
|
+
.map((group) => ({
|
|
120
|
+
...group,
|
|
121
|
+
label: clampText(group.label, SLACK_LIMITS.optionGroupLabelChars),
|
|
122
|
+
options: group.options.slice(0, maxOptions).map(clampOption),
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
// Slack requires an initial option to equal one it emits, so each is
|
|
126
|
+
// replaced by the emitted option of the same value, or dropped.
|
|
127
|
+
const emitted = new Map([
|
|
128
|
+
...(menu.options ?? []),
|
|
129
|
+
...(('option_groups' in menu && menu.option_groups) || []).flatMap(({ options }) => options),
|
|
130
|
+
].map((option) => [option.value, option]));
|
|
131
|
+
if ('initial_option' in menu && menu.initial_option) {
|
|
132
|
+
const match = emitted.get(optionValue(menu.initial_option.value));
|
|
133
|
+
if (match) {
|
|
134
|
+
menu.initial_option = match;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
delete menu.initial_option;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if ('initial_options' in menu && menu.initial_options) {
|
|
141
|
+
const matches = menu.initial_options.flatMap(({ value }) => {
|
|
142
|
+
const match = emitted.get(optionValue(value));
|
|
143
|
+
return match ? [match] : [];
|
|
144
|
+
});
|
|
145
|
+
if (matches.length > 0) {
|
|
146
|
+
menu.initial_options = matches;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
delete menu.initial_options;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return menu;
|
|
153
|
+
};
|
|
154
|
+
const chunks = (items, size) => Array.from({ length: Math.ceil(items.length / size) }, (_, index) => items.slice(index * size, (index + 1) * size));
|
|
155
|
+
// Splits a block past a count limit into blocks of its type. Only the first
|
|
156
|
+
// keeps a `block_id`, which Slack requires to be unique.
|
|
157
|
+
const splitBlockCounts = (block) => {
|
|
158
|
+
switch (block.type) {
|
|
159
|
+
case 'context':
|
|
160
|
+
return chunks(block.elements, SLACK_LIMITS.contextElements).map((elements, index) => index === 0 ? { ...block, elements } : { type: 'context', elements });
|
|
161
|
+
case 'actions':
|
|
162
|
+
return chunks(block.elements, SLACK_LIMITS.buttonsPerActions).map((elements, index) => index === 0 ? { ...block, elements } : { type: 'actions', elements });
|
|
163
|
+
case 'section': {
|
|
164
|
+
if (!block.fields ||
|
|
165
|
+
block.fields.length <= SLACK_LIMITS.fieldsPerSection) {
|
|
166
|
+
return [block];
|
|
167
|
+
}
|
|
168
|
+
return chunks(block.fields, SLACK_LIMITS.fieldsPerSection).map((fields, index) => index === 0 ? { ...block, fields } : { type: 'section', fields });
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
return [block];
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
// An image whose URL Slack would reject leaves its alt text.
|
|
175
|
+
const fitImageUrls = (block) => {
|
|
176
|
+
switch (block.type) {
|
|
177
|
+
case 'image':
|
|
178
|
+
return fitsImageUrl(block)
|
|
179
|
+
? [block]
|
|
180
|
+
: block.alt_text
|
|
181
|
+
? [contextBlock([escapeMrkdwn(block.alt_text)])]
|
|
182
|
+
: [];
|
|
183
|
+
case 'context':
|
|
184
|
+
return [
|
|
185
|
+
{
|
|
186
|
+
...block,
|
|
187
|
+
elements: block.elements.flatMap((element) => element.type !== 'image' || fitsImageUrl(element)
|
|
188
|
+
? [element]
|
|
189
|
+
: element.alt_text
|
|
190
|
+
? [{ type: 'mrkdwn', text: escapeMrkdwn(element.alt_text) }]
|
|
191
|
+
: []),
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
case 'section': {
|
|
195
|
+
if (block.accessory?.type !== 'image' || fitsImageUrl(block.accessory)) {
|
|
196
|
+
return [block];
|
|
197
|
+
}
|
|
198
|
+
const { accessory, ...rest } = block;
|
|
199
|
+
return accessory.alt_text
|
|
200
|
+
? [rest, contextBlock([escapeMrkdwn(accessory.alt_text)])]
|
|
201
|
+
: [rest];
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
return [block];
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
const fitBlock = (block) => fitImageUrls(block).map(clampBlockText);
|
|
208
|
+
// Pack renderers build their own blocks, and one overlong text makes Slack
|
|
209
|
+
// reject the whole message.
|
|
210
|
+
const clampBlockText = (block) => {
|
|
211
|
+
switch (block.type) {
|
|
212
|
+
case 'header':
|
|
213
|
+
return {
|
|
214
|
+
...block,
|
|
215
|
+
text: clampText(block.text, SLACK_LIMITS.headerTextChars),
|
|
216
|
+
};
|
|
217
|
+
case 'section':
|
|
218
|
+
return {
|
|
219
|
+
...block,
|
|
220
|
+
...(block.text && {
|
|
221
|
+
text: clampText(block.text, SLACK_LIMITS.sectionTextChars),
|
|
222
|
+
}),
|
|
223
|
+
...(block.fields && {
|
|
224
|
+
fields: block.fields.map((field) => clampText(field, SLACK_LIMITS.sectionFieldChars)),
|
|
225
|
+
}),
|
|
226
|
+
...(block.accessory && {
|
|
227
|
+
accessory: block.accessory.type === 'image'
|
|
228
|
+
? clampAlt(block.accessory)
|
|
229
|
+
: clampControl(block.accessory),
|
|
230
|
+
}),
|
|
231
|
+
};
|
|
232
|
+
case 'rich_text':
|
|
233
|
+
return {
|
|
234
|
+
...block,
|
|
235
|
+
elements: block.elements.flatMap(splitRichTextElement),
|
|
236
|
+
};
|
|
237
|
+
case 'context':
|
|
238
|
+
return {
|
|
239
|
+
...block,
|
|
240
|
+
elements: block.elements.map((element) => element.type === 'image'
|
|
241
|
+
? clampAlt(element)
|
|
242
|
+
: clampText(element, SLACK_LIMITS.contextElementChars)),
|
|
243
|
+
};
|
|
244
|
+
case 'image':
|
|
245
|
+
return {
|
|
246
|
+
...clampAlt(block),
|
|
247
|
+
...(block.title && {
|
|
248
|
+
title: clampText(block.title, SLACK_LIMITS.imageTitleChars),
|
|
249
|
+
}),
|
|
250
|
+
};
|
|
251
|
+
case 'video':
|
|
252
|
+
return {
|
|
253
|
+
...block,
|
|
254
|
+
title: clampText(block.title, SLACK_LIMITS.videoTitleChars),
|
|
255
|
+
...(block.description && {
|
|
256
|
+
description: clampText(block.description, SLACK_LIMITS.videoDescriptionChars),
|
|
257
|
+
}),
|
|
258
|
+
...(block.author_name !== undefined && {
|
|
259
|
+
author_name: clampSlackText(block.author_name, SLACK_LIMITS.videoAuthorNameChars),
|
|
260
|
+
}),
|
|
261
|
+
};
|
|
262
|
+
case 'actions':
|
|
263
|
+
return { ...block, elements: block.elements.map(clampControl) };
|
|
264
|
+
default:
|
|
265
|
+
return block;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const collectSlackFileRefs = (blocks) => {
|
|
269
|
+
const refs = new Set();
|
|
270
|
+
for (const block of blocks) {
|
|
271
|
+
if (block.type === 'image' && block.slack_file?.ref !== undefined) {
|
|
272
|
+
refs.add(block.slack_file.ref);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return refs;
|
|
276
|
+
};
|
|
277
|
+
const headerBlock = (title, level) => ({
|
|
278
|
+
type: 'header',
|
|
279
|
+
text: { type: 'plain_text', text: formatHeaderText(title), emoji: true },
|
|
280
|
+
...(level !== undefined ? { level } : {}),
|
|
281
|
+
});
|
|
282
|
+
const contextBlock = (lines) => ({
|
|
283
|
+
type: 'context',
|
|
284
|
+
elements: lines
|
|
285
|
+
.filter((line) => line !== undefined && line.length > 0)
|
|
286
|
+
.map((text) => ({
|
|
287
|
+
type: 'mrkdwn',
|
|
288
|
+
text: clampMrkdwn(text, SLACK_LIMITS.contextElementChars),
|
|
289
|
+
})),
|
|
290
|
+
});
|
|
291
|
+
const SLACK_SPACER_TEXT = ' ';
|
|
292
|
+
const slackSpacerBlock = () => ({
|
|
293
|
+
type: 'section',
|
|
294
|
+
text: { type: 'mrkdwn', text: SLACK_SPACER_TEXT },
|
|
295
|
+
});
|
|
296
|
+
const isSpacer = (block) => block.type === 'section' &&
|
|
297
|
+
block.text?.type === 'mrkdwn' &&
|
|
298
|
+
block.text.text === SLACK_SPACER_TEXT &&
|
|
299
|
+
block.fields === undefined &&
|
|
300
|
+
block.accessory === undefined;
|
|
301
|
+
const isFieldsOnly = (block) => block.type === 'section' &&
|
|
302
|
+
(block.fields?.length ?? 0) > 0 &&
|
|
303
|
+
block.text === undefined &&
|
|
304
|
+
block.accessory === undefined;
|
|
305
|
+
const isContent = (block) => block.type !== 'header' &&
|
|
306
|
+
block.type !== 'divider' &&
|
|
307
|
+
block.type !== 'actions' &&
|
|
308
|
+
block.type !== 'context' &&
|
|
309
|
+
!isSpacer(block);
|
|
310
|
+
// Consecutive 1-field sections pack into Slack's two-column `fields` grid.
|
|
311
|
+
// A section that already has 2+ fields is a finished batch (e.g. a
|
|
312
|
+
// description list) and is left alone.
|
|
313
|
+
const coalesceFieldSections = (blocks) => {
|
|
314
|
+
const out = [];
|
|
315
|
+
let index = 0;
|
|
316
|
+
while (index < blocks.length) {
|
|
317
|
+
const block = blocks[index];
|
|
318
|
+
if (isFieldsOnly(block) && block.fields?.length === 1) {
|
|
319
|
+
const fields = [...block.fields];
|
|
320
|
+
index += 1;
|
|
321
|
+
while (index < blocks.length) {
|
|
322
|
+
const next = blocks[index];
|
|
323
|
+
if (!isFieldsOnly(next) ||
|
|
324
|
+
next.fields.length !== 1 ||
|
|
325
|
+
fields.length >= SLACK_LIMITS.fieldsPerSection) {
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
fields.push(...next.fields);
|
|
329
|
+
index += 1;
|
|
330
|
+
}
|
|
331
|
+
out.push({ type: 'section', fields });
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
out.push(block);
|
|
335
|
+
index += 1;
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
};
|
|
339
|
+
// Divider before every section heading (and trailing actions) after the
|
|
340
|
+
// composition title; spacer after each content run except a table already
|
|
341
|
+
// about to be followed by a divider. Consecutive field-only sections are
|
|
342
|
+
// not spaced — they read as one grid.
|
|
343
|
+
const applySectionRhythm = (blocks) => {
|
|
344
|
+
if (blocks.length === 0) {
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
const out = [];
|
|
348
|
+
for (let index = 0; index < blocks.length; index += 1) {
|
|
349
|
+
const block = blocks[index];
|
|
350
|
+
const prev = out[out.length - 1];
|
|
351
|
+
const needsDividerBefore = (block.type === 'header' && out.length > 0) || block.type === 'actions';
|
|
352
|
+
if (needsDividerBefore && prev && prev.type !== 'divider') {
|
|
353
|
+
if (isContent(prev) && prev.type !== 'table') {
|
|
354
|
+
out.push(slackSpacerBlock());
|
|
355
|
+
}
|
|
356
|
+
out.push({ type: 'divider' });
|
|
357
|
+
}
|
|
358
|
+
out.push(block);
|
|
359
|
+
if (isContent(block) && index + 1 < blocks.length) {
|
|
360
|
+
const next = blocks[index + 1];
|
|
361
|
+
if (isContent(next) && !(isFieldsOnly(block) && isFieldsOnly(next))) {
|
|
362
|
+
out.push(slackSpacerBlock());
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return out;
|
|
367
|
+
};
|
|
368
|
+
const truncateWithNotice = (blocks) => {
|
|
369
|
+
const kept = blocks.slice(0, SLACK_LIMITS.blocksPerMessage - 1);
|
|
370
|
+
const dropped = blocks.length - kept.length;
|
|
371
|
+
kept.push(contextBlock([
|
|
372
|
+
italic(`+${dropped} more blocks elided to fit Slack's limit.`),
|
|
373
|
+
]));
|
|
374
|
+
return kept;
|
|
375
|
+
};
|
|
376
|
+
const richTextInlineText = (inline) => inline.type === 'link' ? (inline.text ?? inline.url) : inline.text;
|
|
377
|
+
const richTextElementText = (element) => element.type === 'rich_text_list'
|
|
378
|
+
? element.elements.map(richTextElementText).join('')
|
|
379
|
+
: element.elements.map(richTextInlineText).join('');
|
|
380
|
+
const tableCellText = (cell) => cell.type === 'raw_text'
|
|
381
|
+
? cell.text
|
|
382
|
+
: cell.elements.map(richTextElementText).join('');
|
|
383
|
+
const tableCharCount = (block) => block.rows.reduce((total, row) => total + row.reduce((sum, cell) => sum + tableCellText(cell).length, 0), 0);
|
|
384
|
+
const textRun = (text) => ({ type: 'text', text });
|
|
385
|
+
const richSection = (elements) => ({ type: 'rich_text_section', elements });
|
|
386
|
+
const rowBreak = () => richSection([textRun('\n')]);
|
|
387
|
+
const cellElements = (cell) => {
|
|
388
|
+
if (cell?.type === 'rich_text') {
|
|
389
|
+
return cell.elements.filter(({ elements }) => elements.length > 0);
|
|
390
|
+
}
|
|
391
|
+
return cell?.text ? [richSection([textRun(cell.text)])] : [];
|
|
392
|
+
};
|
|
393
|
+
const boldInline = (inline) => ({
|
|
394
|
+
...inline,
|
|
395
|
+
style: { ...inline.style, bold: true },
|
|
396
|
+
});
|
|
397
|
+
const boldElement = (element) => element.type === 'rich_text_list'
|
|
398
|
+
? {
|
|
399
|
+
...element,
|
|
400
|
+
elements: element.elements.map((item) => ({
|
|
401
|
+
...item,
|
|
402
|
+
elements: item.elements.map(boldInline),
|
|
403
|
+
})),
|
|
404
|
+
}
|
|
405
|
+
: { ...element, elements: element.elements.map(boldInline) };
|
|
406
|
+
const isBlank = (cell) => cell === undefined || tableCellText(cell).trim() === '';
|
|
407
|
+
// A one-section heading leads its cell as `heading: `; any other heading keeps
|
|
408
|
+
// its blocks, bold, above the cell. A blank heading leaves the cell alone.
|
|
409
|
+
const columnElements = (heading, cell) => {
|
|
410
|
+
const body = cellElements(cell);
|
|
411
|
+
if (isBlank(heading)) {
|
|
412
|
+
return body;
|
|
413
|
+
}
|
|
414
|
+
const head = cellElements(heading);
|
|
415
|
+
const [only] = head;
|
|
416
|
+
if (head.length !== 1 || only?.type !== 'rich_text_section') {
|
|
417
|
+
return [...head.map(boldElement), ...body];
|
|
418
|
+
}
|
|
419
|
+
const lead = [...only.elements.map(boldInline), textRun(': ')];
|
|
420
|
+
const [first, ...rest] = body;
|
|
421
|
+
return first?.type === 'rich_text_section'
|
|
422
|
+
? [richSection([...lead, ...first.elements]), ...rest]
|
|
423
|
+
: [richSection(lead), ...body];
|
|
424
|
+
};
|
|
425
|
+
const endsLine = (element) => /[\n\r\u2028\u2029]$/u.test(richTextElementText(element));
|
|
426
|
+
// Slack runs adjacent sections together, so a section followed by another ends
|
|
427
|
+
// its line unless its rendered text already does.
|
|
428
|
+
const breakSections = (elements) => elements.map((element, index) => element.type === 'rich_text_section' &&
|
|
429
|
+
elements[index + 1]?.type === 'rich_text_section' &&
|
|
430
|
+
!endsLine(element)
|
|
431
|
+
? richSection([...element.elements, textRun('\n')])
|
|
432
|
+
: element);
|
|
433
|
+
// Graphemes, and the code points of any grapheme past `max`.
|
|
434
|
+
const textUnits = (text, max) => Array.from(new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text), ({ segment }) => (segment.length > max ? Array.from(segment) : [segment])).flat();
|
|
435
|
+
/**
|
|
436
|
+
* 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.
|
|
437
|
+
* 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.
|
|
438
|
+
*/
|
|
439
|
+
const splitRichTextElement = (element) => {
|
|
440
|
+
const max = SLACK_LIMITS.sectionTextChars;
|
|
441
|
+
if (element.type === 'rich_text_list' ||
|
|
442
|
+
richTextElementText(element).length <= max) {
|
|
443
|
+
return [element];
|
|
444
|
+
}
|
|
445
|
+
const chunks = [];
|
|
446
|
+
let chunk = [];
|
|
447
|
+
let room = max;
|
|
448
|
+
const flush = () => {
|
|
449
|
+
if (chunk.length > 0) {
|
|
450
|
+
chunks.push(chunk);
|
|
451
|
+
}
|
|
452
|
+
chunk = [];
|
|
453
|
+
room = max;
|
|
454
|
+
};
|
|
455
|
+
for (const inline of element.elements) {
|
|
456
|
+
const whole = richTextInlineText(inline);
|
|
457
|
+
if (inline.type !== 'text' && whole.length <= max) {
|
|
458
|
+
if (whole.length > room) {
|
|
459
|
+
flush();
|
|
460
|
+
}
|
|
461
|
+
chunk.push(inline);
|
|
462
|
+
room -= whole.length;
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
let text = '';
|
|
466
|
+
for (const unit of textUnits(whole, max)) {
|
|
467
|
+
if (text.length + unit.length > room) {
|
|
468
|
+
if (text) {
|
|
469
|
+
chunk.push({ ...inline, text });
|
|
470
|
+
}
|
|
471
|
+
flush();
|
|
472
|
+
text = '';
|
|
473
|
+
}
|
|
474
|
+
text += unit;
|
|
475
|
+
}
|
|
476
|
+
if (text) {
|
|
477
|
+
chunk.push({ ...inline, text });
|
|
478
|
+
room -= text.length;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
flush();
|
|
482
|
+
return chunks.map((elements) => ({ ...element, elements }));
|
|
483
|
+
};
|
|
484
|
+
// A table Slack would reject is replaced by one `rich_text` block. Each row's
|
|
485
|
+
// columns run `heading: cell` to the wider of the header and the row, and a
|
|
486
|
+
// blank section parts the rows. A cell keeps its inlines, styles, and blocks; a
|
|
487
|
+
// table whose rows past the header have no cells prints its headings, and one
|
|
488
|
+
// with nothing to print is dropped.
|
|
489
|
+
const degradeTable = ({ rows: [header = [], ...body], }) => {
|
|
490
|
+
const rows = body.filter((row) => row.length > 0);
|
|
491
|
+
const pieces = rows.length === 0
|
|
492
|
+
? [
|
|
493
|
+
header
|
|
494
|
+
.filter((heading) => !isBlank(heading))
|
|
495
|
+
.flatMap((heading) => cellElements(heading).map(boldElement)),
|
|
496
|
+
]
|
|
497
|
+
: rows.map((row) => Array.from({ length: Math.max(header.length, row.length) }, (_, column) => columnElements(header[column], row[column])).flat());
|
|
498
|
+
const elements = pieces
|
|
499
|
+
.filter((piece) => piece.length > 0)
|
|
500
|
+
.flatMap((piece, index) => (index > 0 ? [rowBreak(), ...piece] : piece));
|
|
501
|
+
return elements.length === 0
|
|
502
|
+
? []
|
|
503
|
+
: [
|
|
504
|
+
{
|
|
505
|
+
type: 'rich_text',
|
|
506
|
+
elements: breakSections(elements).flatMap(splitRichTextElement),
|
|
507
|
+
},
|
|
508
|
+
];
|
|
509
|
+
};
|
|
510
|
+
const fitsTableShape = ({ rows }) => rows.length > 0 &&
|
|
511
|
+
rows.length <= SLACK_LIMITS.tableRows &&
|
|
512
|
+
rows.every((row) => row.length > 0 && row.length <= SLACK_LIMITS.tableColumns);
|
|
513
|
+
// Slack counts table cell characters across the whole message, not per block,
|
|
514
|
+
// so a composition whose tables individually fit can still be rejected. In
|
|
515
|
+
// document order, a table is kept if its shape fits and its cells fit what the
|
|
516
|
+
// kept ones left.
|
|
517
|
+
const enforceTableLimits = (blocks) => {
|
|
518
|
+
let spent = 0;
|
|
519
|
+
return blocks.flatMap((block) => {
|
|
520
|
+
if (block.type !== 'table') {
|
|
521
|
+
return [block];
|
|
522
|
+
}
|
|
523
|
+
const cost = tableCharCount(block);
|
|
524
|
+
if (fitsTableShape(block) &&
|
|
525
|
+
spent + cost <= SLACK_LIMITS.tableCellCharsPerMessage) {
|
|
526
|
+
spent += cost;
|
|
527
|
+
return [block];
|
|
528
|
+
}
|
|
529
|
+
return degradeTable(block);
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
const enforceBlockBudget = (blocks) => {
|
|
533
|
+
if (blocks.length <= SLACK_LIMITS.blocksPerMessage) {
|
|
534
|
+
return blocks;
|
|
535
|
+
}
|
|
536
|
+
const trimmed = [...blocks];
|
|
537
|
+
for (let index = trimmed.length - 1; index >= 0 && trimmed.length > SLACK_LIMITS.blocksPerMessage; index -= 1) {
|
|
538
|
+
if (isSpacer(trimmed[index])) {
|
|
539
|
+
trimmed.splice(index, 1);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (trimmed.length <= SLACK_LIMITS.blocksPerMessage) {
|
|
543
|
+
return trimmed;
|
|
544
|
+
}
|
|
545
|
+
return truncateWithNotice(trimmed);
|
|
546
|
+
};
|
|
547
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +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"]}
|