@elastic/isomer-sdk 0.3.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/dist/cjs/composition/error.js +1 -0
- package/dist/cjs/composition/error.js.map +1 -1
- package/dist/cjs/define/index.js.map +1 -1
- 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 +3 -1
- package/dist/cjs/entries/index.js.map +1 -1
- package/dist/cjs/entries/markdown.js +2 -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/render/markdown/blocks.js +82 -0
- package/dist/cjs/render/markdown/blocks.js.map +1 -0
- package/dist/cjs/render/markdown/index.js +3 -1
- package/dist/cjs/render/markdown/index.js.map +1 -1
- package/dist/cjs/render/primitive_dispatch.js +36 -6
- package/dist/cjs/render/primitive_dispatch.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 +29 -76
- 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/composition/error.d.ts +1 -0
- package/dist/composition/error.d.ts.map +1 -1
- package/dist/composition/error.js +1 -0
- package/dist/composition/error.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 +7 -5
- package/dist/define/primitive_module.d.ts.map +1 -1
- 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 +1 -1
- package/dist/entries/index.d.ts.map +1 -1
- package/dist/entries/index.js +1 -1
- 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/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/index.d.ts +1 -0
- package/dist/render/markdown/index.d.ts.map +1 -1
- package/dist/render/markdown/index.js +1 -0
- package/dist/render/markdown/index.js.map +1 -1
- 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/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 +20 -67
- 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/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitive_dispatch.js","sourceRoot":"","sources":["../../src/render/primitive_dispatch.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 { cloneElement, isValidElement, type ReactNode } from 'react';\n\nimport {\n isVisibleOnSurface,\n type SurfaceName,\n} from '../composition/body_node_base';\nimport { IsomerError } from '../composition/error';\nimport type { ValidationError } from '../composition/validation_error';\nimport type { MarkdownContent } from '../define/markdown_content';\nimport {\n type AnyPrimitiveDefinition,\n type DefaultPackTypes,\n type PackTypes,\n type PrimitiveNode,\n type PrimitiveStyleCollectionContext,\n type ReactContextArg,\n type Renderer,\n type RenderScope,\n type SurfaceMap,\n} from '../define/primitive_module';\nimport { createNodeIssueFormatter } from '../validate/node_issues';\n\nimport { serializeMarkdown } from './markdown/builder';\nimport type { SlackAssetCollector } from './slack/assets';\nimport type { SlackBlock, SlackImageBlock } from './slack/blocks';\nimport { markdownContentToSlackBlocks } from './slack/markdown_content';\n\n/**\n * Renders a node on any surface by looking its `type` up in one flattened\n * inventory.\n *\n * The seam that makes packs composable: a container recurses through the\n * {@link RenderScope} it is passed rather than through its own pack, so a node\n * owned by another pack still renders.\n */\nexport interface PrimitiveDispatcher<\n TNode extends PrimitiveNode,\n T extends PackTypes = DefaultPackTypes,\n> {\n /** Every primitive this dispatcher can reach, across all composed packs. */\n readonly definitions: readonly AnyPrimitiveDefinition[];\n /** Throws for an unknown node type; a missing primitive is a bug, not a degradation. */\n getDefinition(node: TNode): AnyPrimitiveDefinition;\n /** `undefined` when the node is hidden from `surface`, `sanitize` drops it, or the primitive declares no renderer for `surface`. */\n renderOn<S extends SurfaceName>(\n surface: S,\n node: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined;\n /** The node's `react` renderer, or `undefined` when it is hidden or has none. `context` may be omitted only when `{}` is a complete context for the pack. */\n renderReact(\n node: TNode,\n ...context: ReactContextArg<T['context']>\n ): ReactNode;\n /** Mutates `styles` with this node's contribution. */\n collectStyles(\n node: TNode,\n styles: T['collector'],\n context: PrimitiveStyleCollectionContext\n ): void;\n /**\n * The node's `react` renderer, gated on `snapshot` visibility and keyed for a\n * frame's sibling list. `key` must be unique among those siblings.\n * `theme` is the frame's resolved palette for this render, or `undefined`\n * outside a frame.\n */\n renderSnapshot(\n node: TNode,\n context: T['context'],\n theme: T['theme'] | undefined,\n key: string\n ): ReactNode;\n /** `''` when the node is hidden from `text` or its primitive declares no `text` renderer. */\n renderText(node: TNode): string;\n /** The node's content serialized as GFM. */\n renderMarkdown(node: TNode): string;\n /** Empty when the node is hidden from `markdown`. */\n renderMarkdownContent(node: TNode): MarkdownContent;\n /**\n * Empty when the node is hidden from `slack`, `sanitize` drops it, or its\n * renderer returns nothing. A node with no `slack` renderer degrades through\n * its markdown; one `isSlackAssetType` names becomes an `image` block when\n * `collector` can allocate.\n */\n renderSlack(\n node: TNode,\n collector?: T['slackCollector']\n ): readonly T['slackBlock'][];\n /** `0` when the node is hidden from `snapshot` or its primitive declares no `metrics.snapshotHeight`. */\n estimateSnapshotHeight(node: TNode): number;\n /**\n * Appends schema failures under `path` to `errors`, each naming `node`'s\n * type, and an unknown key on `node` listing the fields it declares.\n */\n validate(node: TNode, path: string, errors: ValidationError[]): void;\n}\n\n/**\n * Which of a definition's renderers each surface dispatches to.\n *\n * `snapshot` maps to `react`: a rasterizer lays out the pack's DOM tree and\n * stylesheet, so the two surfaces differ only in visibility and in what\n * surrounds them.\n */\nconst RENDERER_FOR_SURFACE = {\n react: 'react',\n snapshot: 'react',\n text: 'text',\n markdown: 'markdown',\n slack: 'slack',\n} as const satisfies Record<\n SurfaceName,\n keyof AnyPrimitiveDefinition['renderers']\n>;\n\n/** Runtime facts {@link createPrimitiveDispatcher} cannot derive from the inventory. */\nexport interface PrimitiveDispatcherOptions {\n /** Names this dispatcher in error messages. */\n label?: string;\n /**\n * Which node types render as a picture rather than as text, so the Slack\n * surface uploads an image instead of degrading to markdown. Supplied by the\n * runtime from each pack's `slackAssetTypes`.\n */\n isSlackAssetType?: ((type: string) => boolean) | undefined;\n}\n\n/**\n * Flattens `definitions` into one type-keyed inventory.\n *\n * Throws on a duplicate `type`: two packs claiming one node type has no correct\n * resolution, so it fails at construction rather than resolving arbitrarily per\n * render.\n */\nexport const createPrimitiveDispatcher = <\n TNode extends PrimitiveNode,\n T extends PackTypes = DefaultPackTypes,\n>(\n definitions: readonly AnyPrimitiveDefinition[],\n options: PrimitiveDispatcherOptions = {}\n): PrimitiveDispatcher<TNode, T> => {\n const { isSlackAssetType } = options;\n const formatIssues = createNodeIssueFormatter(definitions);\n const byType = new Map<string, AnyPrimitiveDefinition>();\n for (const definition of definitions) {\n const existing = byType.get(definition.type);\n if (existing) {\n const label = options.label ? `${options.label}: ` : '';\n throw new IsomerError(\n 'DUPLICATE_PRIMITIVE_TYPE',\n `${label}duplicate primitive type \"${definition.type}\" registered`\n );\n }\n byType.set(definition.type, definition);\n }\n\n const getDefinition = (node: TNode): AnyPrimitiveDefinition => {\n const definition = byType.get(node.type);\n if (!definition) {\n throw new IsomerError(\n 'UNKNOWN_PRIMITIVE_TYPE',\n `Unknown primitive type \"${node.type}\"`\n );\n }\n return definition;\n };\n\n const sanitizeNode = (\n definition: AnyPrimitiveDefinition,\n node: TNode\n ): TNode | null => {\n const sanitize = definition.sanitize as\n ((node: TNode) => TNode | null) | undefined;\n return sanitize ? sanitize(node) : node;\n };\n\n // Assigned after helpers that close over this binding.\n // eslint-disable-next-line prefer-const\n let self: PrimitiveDispatcher<TNode, T>;\n\n const scope = (): RenderScope<T> => self;\n\n const renderOn = <S extends SurfaceName>(\n surface: S,\n node: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined => {\n if (!isVisibleOnSurface(node, surface)) {\n return undefined;\n }\n const definition = getDefinition(node);\n const safeNode = sanitizeNode(definition, node);\n return safeNode === null\n ? undefined\n : renderSanitized(surface, definition, safeNode, extras);\n };\n\n // `renderOn` for a node its sanitizer has already run on.\n const renderSanitized = <S extends SurfaceName>(\n surface: S,\n definition: AnyPrimitiveDefinition,\n safeNode: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined => {\n const renderer = definition.renderers[RENDERER_FOR_SURFACE[surface]] as\n Renderer<TNode, S, T> | undefined;\n return renderer?.(safeNode, { ...extras, scope: scope() });\n };\n\n const renderMarkdownContent = (node: TNode): MarkdownContent =>\n renderOn('markdown', node, {}) ?? [];\n\n const renderMarkdown = (node: TNode): string =>\n serializeMarkdown(renderMarkdownContent(node));\n\n self = {\n definitions,\n getDefinition,\n renderOn,\n // `{}` only ever runs when the argument was optional, which\n // `ReactContextArg` allows exactly when `{}` is a complete context.\n renderReact: (node, ...context) =>\n renderOn('react', node, {\n context: context[0] ?? {},\n }),\n collectStyles: (node, styles, context) => {\n const definition = getDefinition(node);\n const collectStyles = definition.collectStyles as\n | ((\n node: TNode,\n env: {\n styles: T['collector'];\n context: PrimitiveStyleCollectionContext;\n }\n ) => void)\n | undefined;\n collectStyles?.(node, { styles, context });\n },\n renderSnapshot: (node, context, theme, key) => {\n const rendered = renderOn('snapshot', node, { context, theme });\n // The frame hands these to React as an array; a `key` has to sit on the\n // element itself, since wrapping in a Fragment would hide the single\n // root an image backend lays out from.\n return isValidElement(rendered)\n ? cloneElement(rendered, { key })\n : rendered;\n },\n renderText: (node) => renderOn('text', node, {}) ?? '',\n renderMarkdown,\n renderMarkdownContent,\n renderSlack: (node, collector) => {\n if (!isVisibleOnSurface(node, 'slack')) {\n return [];\n }\n const assets = isSlackAssetCollector(collector) ? collector : undefined;\n if (assets && isSlackAssetType?.(node.type)) {\n const definition = getDefinition(node);\n const safeNode = sanitizeNode(definition, node);\n if (safeNode === null) {\n return [];\n }\n const altText =\n (isVisibleOnSurface(safeNode, 'text') &&\n renderSanitized('text', definition, safeNode, {})) ||\n node.type;\n const ref = assets.allocate(safeNode, altText);\n const block = {\n type: 'image',\n alt_text: altText,\n slack_file: { ref },\n } satisfies SlackImageBlock;\n return asSlackPayload<T['slackBlock']>([block]);\n }\n const definition = getDefinition(node);\n const slackRenderer = definition.renderers.slack as\n Renderer<TNode, 'slack', T> | undefined;\n if (!slackRenderer) {\n // Degrading here rather than in the envelope is what reaches nested\n // children: a container's `slack` renderer recurses through this\n // method, and the envelope only ever sees the container's own output.\n return asSlackPayload<T['slackBlock']>(\n markdownContentToSlackBlocks(renderMarkdownContent(node))\n );\n }\n const safeNode = sanitizeNode(definition, node);\n if (safeNode === null) {\n return [];\n }\n const rendered = slackRenderer(safeNode, {\n ...(collector === undefined ? {} : { collector }),\n scope: scope(),\n });\n return isReadonlyArray(rendered) ? rendered : [rendered];\n },\n estimateSnapshotHeight: (node) => {\n if (!isVisibleOnSurface(node, 'snapshot')) {\n return 0;\n }\n const snapshotHeight = getDefinition(node).metrics?.snapshotHeight as\n ((node: TNode) => number) | undefined;\n return snapshotHeight?.(node) ?? 0;\n },\n validate: (node, path, errors) => {\n const result = getDefinition(node).schema.safeParse(node, {\n reportInput: true,\n });\n if (!result.success) {\n errors.push(...formatIssues([[node, path]], result.error.issues, path));\n }\n },\n };\n return self;\n};\n\nconst isReadonlyArray = <T>(value: T | readonly T[]): value is readonly T[] =>\n Array.isArray(value);\n\n/** The picture swap needs a collector that can allocate; any other collector type skips it. */\nconst isSlackAssetCollector = (value: unknown): value is SlackAssetCollector =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { allocate?: unknown }).allocate === 'function';\n\n/** Rebinds checked Block Kit to the erased payload parameter. */\nconst asSlackPayload = <TSlackBlock>(\n blocks: readonly SlackBlock[]\n): readonly TSlackBlock[] => blocks as unknown as readonly TSlackBlock[];\n"]}
|
|
1
|
+
{"version":3,"file":"primitive_dispatch.js","sourceRoot":"","sources":["../../src/render/primitive_dispatch.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 { cloneElement, isValidElement, type ReactNode } from 'react';\n\nimport {\n isVisibleOnSurface,\n type SurfaceName,\n} from '../composition/body_node_base';\nimport { IsomerError } from '../composition/error';\nimport type { ValidationError } from '../composition/validation_error';\nimport type { MarkdownContent } from '../define/markdown_content';\nimport {\n type AnyPrimitiveDefinition,\n type DefaultPackTypes,\n type PackTypes,\n type PrimitiveNode,\n type PrimitiveStyleCollectionContext,\n type ReactContextArg,\n type Renderer,\n type RenderScope,\n type SurfaceMap,\n} from '../define/primitive_module';\nimport { createNodeIssueFormatter } from '../validate/node_issues';\n\nimport { serializeMarkdown } from './markdown/builder';\nimport type { SlackAssetCollector } from './slack/assets';\nimport type { SlackBlock, SlackImageBlock } from './slack/blocks';\nimport type { SlackLinkOptions } from './slack/format';\nimport { markdownContentToSlackBlocks } from './slack/markdown_content';\n\n/**\n * Renders a node on any surface by looking its `type` up in one flattened\n * inventory.\n *\n * The seam that makes packs composable: a container recurses through the\n * {@link RenderScope} it is passed rather than through its own pack, so a node\n * owned by another pack still renders.\n */\nexport interface PrimitiveDispatcher<\n TNode extends PrimitiveNode,\n T extends PackTypes = DefaultPackTypes,\n> {\n /** Every primitive this dispatcher can reach, across all composed packs. */\n readonly definitions: readonly AnyPrimitiveDefinition[];\n /** Throws for an unknown node type; a missing primitive is a bug, not a degradation. */\n getDefinition(node: TNode): AnyPrimitiveDefinition;\n /** `undefined` when the node is hidden from `surface`, `sanitize` drops it, or the primitive declares no renderer for `surface`. */\n renderOn<S extends SurfaceName>(\n surface: S,\n node: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined;\n /** The node's `react` renderer, or `undefined` when it is hidden or has none. `context` may be omitted only when `{}` is a complete context for the pack. */\n renderReact(\n node: TNode,\n ...context: ReactContextArg<T['context']>\n ): ReactNode;\n /** Mutates `styles` with this node's contribution. */\n collectStyles(\n node: TNode,\n styles: T['collector'],\n context: PrimitiveStyleCollectionContext\n ): void;\n /**\n * The node's `react` renderer, gated on `snapshot` visibility and keyed for a\n * frame's sibling list. `key` must be unique among those siblings.\n * `theme` is the frame's resolved palette for this render, or `undefined`\n * outside a frame.\n */\n renderSnapshot(\n node: TNode,\n context: T['context'],\n theme: T['theme'] | undefined,\n key: string\n ): ReactNode;\n /** `''` when the node is hidden from `text` or its primitive declares no `text` renderer. */\n renderText(node: TNode): string;\n /** The node's content serialized as GFM. */\n renderMarkdown(node: TNode): string;\n /** Empty when the node is hidden from `markdown`. */\n renderMarkdownContent(node: TNode): MarkdownContent;\n /**\n * Empty when the node is hidden from `slack`, `sanitize` drops it, or its\n * renderer returns nothing. A node with no `slack` renderer degrades through\n * its markdown; one `isSlackAssetType` names becomes an `image` block when\n * `collector` can allocate. `options.baseUrl` reaches the renderer's env and\n * every child it renders through `scope`.\n */\n renderSlack(\n node: TNode,\n collector?: T['slackCollector'],\n options?: SlackLinkOptions\n ): readonly T['slackBlock'][];\n /** `0` when the node is hidden from `snapshot` or its primitive declares no `metrics.snapshotHeight`. */\n estimateSnapshotHeight(node: TNode): number;\n /**\n * Appends schema failures under `path` to `errors`, each naming `node`'s\n * type, and an unknown key on `node` listing the fields it declares.\n */\n validate(node: TNode, path: string, errors: ValidationError[]): void;\n}\n\n/**\n * Which of a definition's renderers each surface dispatches to.\n *\n * `snapshot` maps to `react`: a rasterizer lays out the pack's DOM tree and\n * stylesheet, so the two surfaces differ only in visibility and in what\n * surrounds them.\n */\nconst RENDERER_FOR_SURFACE = {\n react: 'react',\n snapshot: 'react',\n text: 'text',\n markdown: 'markdown',\n slack: 'slack',\n} as const satisfies Record<\n SurfaceName,\n keyof AnyPrimitiveDefinition['renderers']\n>;\n\n/** Runtime facts {@link createPrimitiveDispatcher} cannot derive from the inventory. */\nexport interface PrimitiveDispatcherOptions {\n /** Names this dispatcher in error messages. */\n label?: string;\n /**\n * Which node types render as a picture rather than as text, so the Slack\n * surface uploads an image instead of degrading to markdown. Supplied by the\n * runtime from each pack's `slackAssetTypes`.\n */\n isSlackAssetType?: ((type: string) => boolean) | undefined;\n}\n\n/**\n * Flattens `definitions` into one type-keyed inventory.\n *\n * Throws on a duplicate `type`: two packs claiming one node type has no correct\n * resolution, so it fails at construction rather than resolving arbitrarily per\n * render.\n */\nexport const createPrimitiveDispatcher = <\n TNode extends PrimitiveNode,\n T extends PackTypes = DefaultPackTypes,\n>(\n definitions: readonly AnyPrimitiveDefinition[],\n options: PrimitiveDispatcherOptions = {}\n): PrimitiveDispatcher<TNode, T> => {\n const { isSlackAssetType } = options;\n const formatIssues = createNodeIssueFormatter(definitions);\n const byType = new Map<string, AnyPrimitiveDefinition>();\n for (const definition of definitions) {\n const existing = byType.get(definition.type);\n if (existing) {\n const label = options.label ? `${options.label}: ` : '';\n throw new IsomerError(\n 'DUPLICATE_PRIMITIVE_TYPE',\n `${label}duplicate primitive type \"${definition.type}\" registered`\n );\n }\n byType.set(definition.type, definition);\n }\n\n const getDefinition = (node: TNode): AnyPrimitiveDefinition => {\n const definition = byType.get(node.type);\n if (!definition) {\n throw new IsomerError(\n 'UNKNOWN_PRIMITIVE_TYPE',\n `Unknown primitive type \"${node.type}\"`\n );\n }\n return definition;\n };\n\n const sanitizeNode = (\n definition: AnyPrimitiveDefinition,\n node: TNode\n ): TNode | null => {\n const sanitize = definition.sanitize as\n ((node: TNode) => TNode | null) | undefined;\n return sanitize ? sanitize(node) : node;\n };\n\n // Assigned after helpers that close over this binding.\n // eslint-disable-next-line prefer-const\n let self: PrimitiveDispatcher<TNode, T>;\n\n const scopeFor = <S extends SurfaceName>(\n surface: S,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): RenderScope<T> => {\n const parent: RenderScope<T> = self;\n if (surface === 'slack') {\n const { baseUrl } = extras as Omit<\n SurfaceMap<T>['slack']['env'],\n 'scope'\n >;\n return baseUrl === undefined\n ? parent\n : {\n ...parent,\n renderOn: (target, node, targetExtras) =>\n parent.renderOn(\n target,\n node,\n target === 'slack' ? { baseUrl, ...targetExtras } : targetExtras\n ),\n renderSlack: (node, collector) =>\n self.renderSlack(node as TNode, collector, { baseUrl }),\n };\n }\n if (surface !== 'snapshot') {\n return parent;\n }\n const { theme } = extras as Omit<SurfaceMap<T>['snapshot']['env'], 'scope'>;\n return {\n ...parent,\n renderReact: (node, ...context) =>\n parent.renderOn('snapshot', node, {\n context: context[0] ?? {},\n theme,\n }),\n };\n };\n\n const renderOn = <S extends SurfaceName>(\n surface: S,\n node: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined => {\n if (!isVisibleOnSurface(node, surface)) {\n return undefined;\n }\n const definition = getDefinition(node);\n const safeNode = sanitizeNode(definition, node);\n return safeNode === null\n ? undefined\n : renderSanitized(surface, definition, safeNode, extras);\n };\n\n // `renderOn` for a node its sanitizer has already run on.\n const renderSanitized = <S extends SurfaceName>(\n surface: S,\n definition: AnyPrimitiveDefinition,\n safeNode: TNode,\n extras: Omit<SurfaceMap<T>[S]['env'], 'scope'>\n ): SurfaceMap<T>[S]['output'] | undefined => {\n const renderer = definition.renderers[RENDERER_FOR_SURFACE[surface]] as\n Renderer<TNode, S, T> | undefined;\n return renderer?.(safeNode, {\n ...extras,\n scope: scopeFor(surface, extras),\n });\n };\n\n const renderMarkdownContent = (node: TNode): MarkdownContent =>\n renderOn('markdown', node, {}) ?? [];\n\n const renderMarkdown = (node: TNode): string =>\n serializeMarkdown(renderMarkdownContent(node));\n\n self = {\n definitions,\n getDefinition,\n renderOn,\n // `{}` only ever runs when the argument was optional, which\n // `ReactContextArg` allows exactly when `{}` is a complete context.\n renderReact: (node, ...context) =>\n renderOn('react', node, {\n context: context[0] ?? {},\n }),\n collectStyles: (node, styles, context) => {\n const definition = getDefinition(node);\n const collectStyles = definition.collectStyles as\n | ((\n node: TNode,\n env: {\n styles: T['collector'];\n context: PrimitiveStyleCollectionContext;\n }\n ) => void)\n | undefined;\n collectStyles?.(node, { styles, context });\n },\n renderSnapshot: (node, context, theme, key) => {\n const rendered = renderOn('snapshot', node, { context, theme });\n // The frame hands these to React as an array; a `key` has to sit on the\n // element itself, since wrapping in a Fragment would hide the single\n // root an image backend lays out from.\n return isValidElement(rendered)\n ? cloneElement(rendered, { key })\n : rendered;\n },\n renderText: (node) => renderOn('text', node, {}) ?? '',\n renderMarkdown,\n renderMarkdownContent,\n renderSlack: (node, collector, options = {}) => {\n if (!isVisibleOnSurface(node, 'slack')) {\n return [];\n }\n const assets = isSlackAssetCollector(collector) ? collector : undefined;\n if (assets && isSlackAssetType?.(node.type)) {\n const definition = getDefinition(node);\n const safeNode = sanitizeNode(definition, node);\n if (safeNode === null) {\n return [];\n }\n const altText =\n (isVisibleOnSurface(safeNode, 'text') &&\n renderSanitized('text', definition, safeNode, {})) ||\n node.type;\n const ref = assets.allocate(safeNode, altText);\n const block = {\n type: 'image',\n alt_text: altText,\n slack_file: { ref },\n } satisfies SlackImageBlock;\n return asSlackPayload<T['slackBlock']>([block]);\n }\n const definition = getDefinition(node);\n const slackRenderer = definition.renderers.slack as\n Renderer<TNode, 'slack', T> | undefined;\n if (!slackRenderer) {\n // Degrading here rather than in the envelope is what reaches nested\n // children: a container's `slack` renderer recurses through this\n // method, and the envelope only ever sees the container's own output.\n return asSlackPayload<T['slackBlock']>(\n markdownContentToSlackBlocks(renderMarkdownContent(node), options)\n );\n }\n const safeNode = sanitizeNode(definition, node);\n if (safeNode === null) {\n return [];\n }\n const extras = {\n ...(collector === undefined ? {} : { collector }),\n ...(options.baseUrl === undefined ? {} : { baseUrl: options.baseUrl }),\n };\n const rendered = slackRenderer(safeNode, {\n ...extras,\n scope: scopeFor('slack', extras),\n });\n return isReadonlyArray(rendered) ? rendered : [rendered];\n },\n estimateSnapshotHeight: (node) => {\n if (!isVisibleOnSurface(node, 'snapshot')) {\n return 0;\n }\n const snapshotHeight = getDefinition(node).metrics?.snapshotHeight as\n ((node: TNode) => number) | undefined;\n return snapshotHeight?.(node) ?? 0;\n },\n validate: (node, path, errors) => {\n const result = getDefinition(node).schema.safeParse(node, {\n reportInput: true,\n });\n if (!result.success) {\n errors.push(...formatIssues([[node, path]], result.error.issues, path));\n }\n },\n };\n return self;\n};\n\nconst isReadonlyArray = <T>(value: T | readonly T[]): value is readonly T[] =>\n Array.isArray(value);\n\n/** The picture swap needs a collector that can allocate; any other collector type skips it. */\nconst isSlackAssetCollector = (value: unknown): value is SlackAssetCollector =>\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { allocate?: unknown }).allocate === 'function';\n\n/** Rebinds checked Block Kit to the erased payload parameter. */\nconst asSlackPayload = <TSlackBlock>(\n blocks: readonly SlackBlock[]\n): readonly TSlackBlock[] => blocks as unknown as readonly TSlackBlock[];\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { type CompositionWrapperOptions, type ReactContentDispatcher, type ReactContentOptions, renderCompositionContent, wrapCompositionContent, } from './content.js';
|
|
2
2
|
export { applyEnhancements } from './enhancements.js';
|
|
3
|
+
export { renderMarkdownContent } from './markdown_content.js';
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/react/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/render/react/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/render/react/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nexport {\n type CompositionWrapperOptions,\n type ReactContentDispatcher,\n type ReactContentOptions,\n renderCompositionContent,\n wrapCompositionContent,\n} from './content';\nexport { applyEnhancements } from './enhancements';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/render/react/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nexport {\n type CompositionWrapperOptions,\n type ReactContentDispatcher,\n type ReactContentOptions,\n renderCompositionContent,\n wrapCompositionContent,\n} from './content';\nexport { applyEnhancements } from './enhancements';\nexport { renderMarkdownContent } from './markdown_content';\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { MarkdownContent } from '../../define/markdown_content.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builder content as React elements: paragraphs, headings, lists, quotes, code, tables, and thematic breaks, with inline marks, links, and images. Source from `md.authored` is parsed as GFM, once, as the Markdown and Slack surfaces read it.
|
|
5
|
+
*
|
|
6
|
+
* Links and images follow `md`'s URL policy: a blocked link keeps its label on {@link BLOCKED_HREF}, and a blocked image degrades to its alt text.
|
|
7
|
+
*/
|
|
8
|
+
export declare const renderMarkdownContent: (content: MarkdownContent) => ReactNode;
|
|
9
|
+
//# sourceMappingURL=markdown_content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown_content.d.ts","sourceRoot":"","sources":["../../../src/render/react/markdown_content.ts"],"names":[],"mappings":"AAUA,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAWhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AA+MrE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,eAAe,KAAG,SAK9D,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
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
|
+
// Builder content as React elements, read from the blocks the Markdown and
|
|
8
|
+
// Slack surfaces read. Unstyled: a pack's stylesheet owns the look.
|
|
9
|
+
import { createElement, Fragment } from 'react';
|
|
10
|
+
import { BLOCKED_HREF, sanitizeParsedAssetUrl, sanitizeParsedNavigationHref, } from '../../validate/url.js';
|
|
11
|
+
import { resolvedMarkdownBlocks } from '../markdown/blocks.js';
|
|
12
|
+
const HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
|
13
|
+
const footnoteLabel = ({ identifier, label, }) => `[^${label ?? identifier}]`;
|
|
14
|
+
const plainText = (node) => {
|
|
15
|
+
if ('value' in node) {
|
|
16
|
+
return node.value;
|
|
17
|
+
}
|
|
18
|
+
if (node.type === 'image') {
|
|
19
|
+
return node.alt ?? '';
|
|
20
|
+
}
|
|
21
|
+
if (node.type === 'footnoteReference') {
|
|
22
|
+
return footnoteLabel(node);
|
|
23
|
+
}
|
|
24
|
+
return 'children' in node ? node.children.map(plainText).join('') : '';
|
|
25
|
+
};
|
|
26
|
+
const keyed = (nodes) => nodes.map((node, index) => createElement(Fragment, { key: index }, node));
|
|
27
|
+
const inlines = (nodes) => keyed(nodes.map(inline));
|
|
28
|
+
const inline = (node) => {
|
|
29
|
+
switch (node.type) {
|
|
30
|
+
case 'strong':
|
|
31
|
+
return createElement('strong', null, ...inlines(node.children));
|
|
32
|
+
case 'emphasis':
|
|
33
|
+
return createElement('em', null, ...inlines(node.children));
|
|
34
|
+
case 'delete':
|
|
35
|
+
return createElement('del', null, ...inlines(node.children));
|
|
36
|
+
case 'inlineCode':
|
|
37
|
+
return createElement('code', null, node.value);
|
|
38
|
+
case 'break':
|
|
39
|
+
return createElement('br');
|
|
40
|
+
case 'link':
|
|
41
|
+
return createElement('a', {
|
|
42
|
+
href: sanitizeParsedNavigationHref(node.url) ?? BLOCKED_HREF,
|
|
43
|
+
...(node.title ? { title: node.title } : {}),
|
|
44
|
+
}, ...inlines(node.children));
|
|
45
|
+
case 'image': {
|
|
46
|
+
const src = sanitizeParsedAssetUrl(node.url);
|
|
47
|
+
return src === null
|
|
48
|
+
? (node.alt ?? '')
|
|
49
|
+
: createElement('img', {
|
|
50
|
+
src,
|
|
51
|
+
alt: node.alt ?? '',
|
|
52
|
+
...(node.title ? { title: node.title } : {}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return plainText(node);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const paragraphCount = (item) => item.children.filter(({ type }) => type === 'paragraph').length;
|
|
60
|
+
// A spread list, a spread item, or an item with two paragraphs makes the whole list loose.
|
|
61
|
+
const items = (list) => {
|
|
62
|
+
const tight = list.spread !== true &&
|
|
63
|
+
!list.children.some((item) => item.spread === true || paragraphCount(item) > 1);
|
|
64
|
+
return list.children.map((item, index) => listItem(item, index, tight));
|
|
65
|
+
};
|
|
66
|
+
// A task item's checkbox leads its first paragraph, so a loose item keeps it on the task's line.
|
|
67
|
+
const listItem = (item, key, tight) => {
|
|
68
|
+
const checkbox = typeof item.checked === 'boolean'
|
|
69
|
+
? [
|
|
70
|
+
createElement('input', {
|
|
71
|
+
type: 'checkbox',
|
|
72
|
+
checked: item.checked,
|
|
73
|
+
disabled: true,
|
|
74
|
+
}),
|
|
75
|
+
' ',
|
|
76
|
+
]
|
|
77
|
+
: [];
|
|
78
|
+
const [first, ...rest] = item.children;
|
|
79
|
+
const leadsWithParagraph = first?.type === 'paragraph';
|
|
80
|
+
const lead = leadsWithParagraph
|
|
81
|
+
? [...checkbox, ...inlines(first.children)]
|
|
82
|
+
: checkbox;
|
|
83
|
+
const head = leadsWithParagraph && !tight ? [createElement('p', null, ...lead)] : lead;
|
|
84
|
+
const body = (leadsWithParagraph ? rest : item.children).flatMap((child) => child.type === 'paragraph' && tight
|
|
85
|
+
? inlines(child.children)
|
|
86
|
+
: [block(child)]);
|
|
87
|
+
return createElement('li', { key }, ...keyed([...head, ...body]));
|
|
88
|
+
};
|
|
89
|
+
const tableRows = (table) => {
|
|
90
|
+
const [header, ...body] = table.children;
|
|
91
|
+
const cells = (row, tag) => createElement('tr', null, ...row.children.map((cell, index) => {
|
|
92
|
+
const align = table.align?.[index];
|
|
93
|
+
return createElement(tag, {
|
|
94
|
+
key: index,
|
|
95
|
+
...(align ? { style: { textAlign: align } } : {}),
|
|
96
|
+
}, ...inlines(cell.children));
|
|
97
|
+
}));
|
|
98
|
+
return createElement(Fragment, null, header
|
|
99
|
+
? createElement('thead', { key: 'head' }, cells(header, 'th'))
|
|
100
|
+
: null, body.length > 0
|
|
101
|
+
? createElement('tbody', { key: 'body' }, ...body.map((row, index) => createElement(Fragment, { key: index }, cells(row, 'td'))))
|
|
102
|
+
: null);
|
|
103
|
+
};
|
|
104
|
+
const blocks = (nodes) => keyed(nodes.map(block));
|
|
105
|
+
const block = (node) => {
|
|
106
|
+
switch (node.type) {
|
|
107
|
+
case 'paragraph':
|
|
108
|
+
return createElement('p', null, ...inlines(node.children));
|
|
109
|
+
case 'heading':
|
|
110
|
+
return createElement(HEADINGS[node.depth - 1], null, ...inlines(node.children));
|
|
111
|
+
case 'blockquote':
|
|
112
|
+
return createElement('blockquote', null, ...blocks(node.children));
|
|
113
|
+
case 'list':
|
|
114
|
+
return createElement(node.ordered ? 'ol' : 'ul', node.ordered && node.start != null && node.start !== 1
|
|
115
|
+
? { start: node.start }
|
|
116
|
+
: null, ...items(node));
|
|
117
|
+
case 'code':
|
|
118
|
+
return createElement('pre', null, createElement('code', node.lang ? { className: `language-${node.lang}` } : null, node.value));
|
|
119
|
+
case 'table':
|
|
120
|
+
return createElement('table', null, tableRows(node));
|
|
121
|
+
case 'thematicBreak':
|
|
122
|
+
return createElement('hr');
|
|
123
|
+
case 'html':
|
|
124
|
+
return createElement('p', null, node.value);
|
|
125
|
+
case 'footnoteDefinition': {
|
|
126
|
+
const [first, ...rest] = node.children;
|
|
127
|
+
return createElement(Fragment, null, createElement('p', null, `${footnoteLabel(node)}: `, ...(first?.type === 'paragraph' ? inlines(first.children) : [])), ...blocks(first?.type === 'paragraph' ? rest : node.children));
|
|
128
|
+
}
|
|
129
|
+
default:
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Builder content as React elements: paragraphs, headings, lists, quotes, code, tables, and thematic breaks, with inline marks, links, and images. Source from `md.authored` is parsed as GFM, once, as the Markdown and Slack surfaces read it.
|
|
135
|
+
*
|
|
136
|
+
* Links and images follow `md`'s URL policy: a blocked link keeps its label on {@link BLOCKED_HREF}, and a blocked image degrades to its alt text.
|
|
137
|
+
*/
|
|
138
|
+
export const renderMarkdownContent = (content) => createElement(Fragment, null, ...blocks(resolvedMarkdownBlocks(content)));
|
|
139
|
+
//# sourceMappingURL=markdown_content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown_content.js","sourceRoot":"","sources":["../../../src/render/react/markdown_content.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\n// Builder content as React elements, read from the blocks the Markdown and\n// Slack surfaces read. Unstyled: a pack's stylesheet owns the look.\n\nimport { createElement, Fragment, type ReactNode } from 'react';\nimport type {\n FootnoteDefinition,\n List,\n ListItem,\n Nodes,\n PhrasingContent,\n RootContent,\n Table,\n} from 'mdast';\n\nimport type { MarkdownContent } from '../../define/markdown_content';\nimport {\n BLOCKED_HREF,\n sanitizeParsedAssetUrl,\n sanitizeParsedNavigationHref,\n} from '../../validate/url';\nimport { resolvedMarkdownBlocks } from '../markdown/blocks';\n\nconst HEADINGS = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;\n\nconst footnoteLabel = ({\n identifier,\n label,\n}: Pick<FootnoteDefinition, 'identifier' | 'label'>): string =>\n `[^${label ?? identifier}]`;\n\nconst plainText = (node: Nodes): string => {\n if ('value' in node) {\n return node.value;\n }\n if (node.type === 'image') {\n return node.alt ?? '';\n }\n if (node.type === 'footnoteReference') {\n return footnoteLabel(node);\n }\n return 'children' in node ? node.children.map(plainText).join('') : '';\n};\n\nconst keyed = (nodes: readonly ReactNode[]): ReactNode[] =>\n nodes.map((node, index) => createElement(Fragment, { key: index }, node));\n\nconst inlines = (nodes: readonly PhrasingContent[]): ReactNode[] =>\n keyed(nodes.map(inline));\n\nconst inline = (node: PhrasingContent): ReactNode => {\n switch (node.type) {\n case 'strong':\n return createElement('strong', null, ...inlines(node.children));\n case 'emphasis':\n return createElement('em', null, ...inlines(node.children));\n case 'delete':\n return createElement('del', null, ...inlines(node.children));\n case 'inlineCode':\n return createElement('code', null, node.value);\n case 'break':\n return createElement('br');\n case 'link':\n return createElement(\n 'a',\n {\n href: sanitizeParsedNavigationHref(node.url) ?? BLOCKED_HREF,\n ...(node.title ? { title: node.title } : {}),\n },\n ...inlines(node.children)\n );\n case 'image': {\n const src = sanitizeParsedAssetUrl(node.url);\n return src === null\n ? (node.alt ?? '')\n : createElement('img', {\n src,\n alt: node.alt ?? '',\n ...(node.title ? { title: node.title } : {}),\n });\n }\n default:\n return plainText(node);\n }\n};\n\nconst paragraphCount = (item: ListItem): number =>\n item.children.filter(({ type }) => type === 'paragraph').length;\n\n// A spread list, a spread item, or an item with two paragraphs makes the whole list loose.\nconst items = (list: List): ReactNode[] => {\n const tight =\n list.spread !== true &&\n !list.children.some(\n (item) => item.spread === true || paragraphCount(item) > 1\n );\n return list.children.map((item, index) => listItem(item, index, tight));\n};\n\n// A task item's checkbox leads its first paragraph, so a loose item keeps it on the task's line.\nconst listItem = (item: ListItem, key: number, tight: boolean): ReactNode => {\n const checkbox =\n typeof item.checked === 'boolean'\n ? [\n createElement('input', {\n type: 'checkbox',\n checked: item.checked,\n disabled: true,\n }),\n ' ',\n ]\n : [];\n const [first, ...rest] = item.children;\n const leadsWithParagraph = first?.type === 'paragraph';\n const lead = leadsWithParagraph\n ? [...checkbox, ...inlines(first.children)]\n : checkbox;\n const head =\n leadsWithParagraph && !tight ? [createElement('p', null, ...lead)] : lead;\n const body = (leadsWithParagraph ? rest : item.children).flatMap(\n (child): ReactNode[] =>\n child.type === 'paragraph' && tight\n ? inlines(child.children)\n : [block(child)]\n );\n return createElement('li', { key }, ...keyed([...head, ...body]));\n};\n\nconst tableRows = (table: Table): ReactNode => {\n const [header, ...body] = table.children;\n const cells = (row: Table['children'][number], tag: 'th' | 'td'): ReactNode =>\n createElement(\n 'tr',\n null,\n ...row.children.map((cell, index) => {\n const align = table.align?.[index];\n return createElement(\n tag,\n {\n key: index,\n ...(align ? { style: { textAlign: align } } : {}),\n },\n ...inlines(cell.children)\n );\n })\n );\n return createElement(\n Fragment,\n null,\n header\n ? createElement('thead', { key: 'head' }, cells(header, 'th'))\n : null,\n body.length > 0\n ? createElement(\n 'tbody',\n { key: 'body' },\n ...body.map((row, index) =>\n createElement(Fragment, { key: index }, cells(row, 'td'))\n )\n )\n : null\n );\n};\n\nconst blocks = (nodes: readonly RootContent[]): ReactNode[] =>\n keyed(nodes.map(block));\n\nconst block = (node: RootContent): ReactNode => {\n switch (node.type) {\n case 'paragraph':\n return createElement('p', null, ...inlines(node.children));\n case 'heading':\n return createElement(\n HEADINGS[node.depth - 1]!,\n null,\n ...inlines(node.children)\n );\n case 'blockquote':\n return createElement('blockquote', null, ...blocks(node.children));\n case 'list':\n return createElement(\n node.ordered ? 'ol' : 'ul',\n node.ordered && node.start != null && node.start !== 1\n ? { start: node.start }\n : null,\n ...items(node)\n );\n case 'code':\n return createElement(\n 'pre',\n null,\n createElement(\n 'code',\n node.lang ? { className: `language-${node.lang}` } : null,\n node.value\n )\n );\n case 'table':\n return createElement('table', null, tableRows(node));\n case 'thematicBreak':\n return createElement('hr');\n case 'html':\n return createElement('p', null, node.value);\n case 'footnoteDefinition': {\n const [first, ...rest] = node.children;\n return createElement(\n Fragment,\n null,\n createElement(\n 'p',\n null,\n `${footnoteLabel(node)}: `,\n ...(first?.type === 'paragraph' ? inlines(first.children) : [])\n ),\n ...blocks(first?.type === 'paragraph' ? rest : node.children)\n );\n }\n default:\n return null;\n }\n};\n\n/**\n * Builder content as React elements: paragraphs, headings, lists, quotes, code, tables, and thematic breaks, with inline marks, links, and images. Source from `md.authored` is parsed as GFM, once, as the Markdown and Slack surfaces read it.\n *\n * Links and images follow `md`'s URL policy: a blocked link keeps its label on {@link BLOCKED_HREF}, and a blocked image degrades to its alt text.\n */\nexport const renderMarkdownContent = (content: MarkdownContent): ReactNode =>\n createElement(\n Fragment,\n null,\n ...blocks(resolvedMarkdownBlocks(content) as RootContent[])\n );\n"]}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
export type { SlackActionElement, SlackActionsBlock, SlackBlock, SlackButtonElement, SlackCheckboxesElement, SlackContextBlock, SlackDividerBlock, SlackFileReference, SlackHeaderBlock, SlackHeaderLevel, SlackImageBlock, SlackImageElement, SlackMrkdwnTextObject, SlackMultiStaticSelectElement, SlackOptionGroup, SlackOptionObject, SlackOverflowElement, SlackPlainTextObject, SlackRadioButtonsElement, SlackRawTextElement, SlackRichTextBlock, SlackRichTextBlockElement, SlackRichTextInline, SlackRichTextLink, SlackRichTextList, SlackRichTextPreformatted, SlackRichTextQuote, SlackRichTextSection, SlackRichTextStyle, SlackRichTextTag, SlackRichTextText, SlackSectionAccessory, SlackSectionBlock, SlackStaticSelectElement, SlackTableBlock, SlackTableCell, SlackTableColumnSetting, SlackTagColor, SlackTextObject, SlackVideoBlock, } from '../../define/slack_blocks.js';
|
|
1
|
+
export type { SlackActionElement, SlackActionsBlock, SlackBlock, SlackButtonElement, SlackCheckboxesElement, SlackContainerBlock, SlackContainerChildBlock, SlackContextBlock, SlackDividerBlock, SlackFileReference, SlackHeaderBlock, SlackHeaderLevel, SlackImageBlock, SlackImageElement, SlackMrkdwnTextObject, SlackMultiStaticSelectElement, SlackOptionGroup, SlackOptionObject, SlackOverflowElement, SlackPlainTextObject, SlackRadioButtonsElement, SlackRawTextElement, SlackRichTextBlock, SlackRichTextBlockElement, SlackRichTextInline, SlackRichTextLink, SlackRichTextList, SlackRichTextPreformatted, SlackRichTextQuote, SlackRichTextSection, SlackRichTextStyle, SlackRichTextTag, SlackRichTextText, SlackSectionAccessory, SlackSectionBlock, SlackStaticSelectElement, SlackTableBlock, SlackTableCell, SlackTableColumnSetting, SlackTagColor, SlackTextObject, SlackVideoBlock, } from '../../define/slack_blocks.js';
|
|
2
2
|
/**
|
|
3
3
|
* Slack's published surface limits, enforced by the renderer so a composition
|
|
4
4
|
* cannot silently trip Slack's validation.
|
|
5
5
|
*/
|
|
6
6
|
export declare const SLACK_LIMITS: {
|
|
7
|
+
/** Top-level blocks; a `container`'s `child_blocks` do not count. */
|
|
7
8
|
readonly blocksPerMessage: 50;
|
|
9
|
+
/** `container.title`, which is `plain_text`. */
|
|
10
|
+
readonly containerTitleChars: 150;
|
|
11
|
+
/** `container.subtitle`. */
|
|
12
|
+
readonly containerSubtitleChars: 150;
|
|
13
|
+
/** `container.child_blocks`; Slack also requires at least one. */
|
|
14
|
+
readonly containerChildBlocks: 10;
|
|
8
15
|
/** `section.text`. */
|
|
9
16
|
readonly sectionTextChars: 3000;
|
|
10
17
|
/** One entry of `section.fields`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../../src/render/slack/blocks.ts"],"names":[],"mappings":"AAOA,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,aAAa,EACb,eAAe,EACf,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,YAAY;;
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../../src/render/slack/blocks.ts"],"names":[],"mappings":"AAOA,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,aAAa,EACb,eAAe,EACf,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB,qEAAqE;;IAErE,gDAAgD;;IAEhD,4BAA4B;;IAE5B,kEAAkE;;IAElE,sBAAsB;;IAEtB,qCAAqC;;IAErC,uCAAuC;;IAEvC,4CAA4C;;;IAG5C,oCAAoC;;;IAGpC,kFAAkF;;IAElF,yEAAyE;;IAEzE,sDAAsD;;IAEtD,4DAA4D;;IAE5D,4DAA4D;;IAE5D,+EAA+E;;IAE/E,yDAAyD;;IAEzD,0BAA0B;;IAE1B,6CAA6C;;IAE7C,4CAA4C;;IAE5C,6CAA6C;;IAE7C;;;;;OAKG;;IAEH,wDAAwD;;IAExD,iDAAiD;;IAEjD,oDAAoD;;IAEpD,mDAAmD;;IAEnD,6BAA6B;;IAE7B,4DAA4D;;IAE5D,kEAAkE;;IAElE,iEAAiE;;IAEjE,+BAA+B;;IAE/B,4BAA4B;;IAE5B,+BAA+B;;CAEvB,CAAC"}
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
* cannot silently trip Slack's validation.
|
|
10
10
|
*/
|
|
11
11
|
export const SLACK_LIMITS = {
|
|
12
|
+
/** Top-level blocks; a `container`'s `child_blocks` do not count. */
|
|
12
13
|
blocksPerMessage: 50,
|
|
14
|
+
/** `container.title`, which is `plain_text`. */
|
|
15
|
+
containerTitleChars: 150,
|
|
16
|
+
/** `container.subtitle`. */
|
|
17
|
+
containerSubtitleChars: 150,
|
|
18
|
+
/** `container.child_blocks`; Slack also requires at least one. */
|
|
19
|
+
containerChildBlocks: 10,
|
|
13
20
|
/** `section.text`. */
|
|
14
21
|
sectionTextChars: 3000,
|
|
15
22
|
/** One entry of `section.fields`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../src/render/slack/blocks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../src/render/slack/blocks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+CH;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,qEAAqE;IACrE,gBAAgB,EAAE,EAAE;IACpB,gDAAgD;IAChD,mBAAmB,EAAE,GAAG;IACxB,4BAA4B;IAC5B,sBAAsB,EAAE,GAAG;IAC3B,kEAAkE;IAClE,oBAAoB,EAAE,EAAE;IACxB,sBAAsB;IACtB,gBAAgB,EAAE,IAAI;IACtB,qCAAqC;IACrC,iBAAiB,EAAE,IAAI;IACvB,uCAAuC;IACvC,mBAAmB,EAAE,IAAI;IACzB,4CAA4C;IAC5C,eAAe,EAAE,GAAG;IACpB,gBAAgB,EAAE,EAAE;IACpB,oCAAoC;IACpC,eAAe,EAAE,EAAE;IACnB,iBAAiB,EAAE,EAAE;IACrB,kFAAkF;IAClF,iBAAiB,EAAE,IAAI;IACvB,yEAAyE;IACzE,eAAe,EAAE,EAAE;IACnB,sDAAsD;IACtD,gBAAgB,EAAE,GAAG;IACrB,4DAA4D;IAC5D,kBAAkB,EAAE,CAAC;IACrB,4DAA4D;IAC5D,gBAAgB,EAAE,EAAE;IACpB,+EAA+E;IAC/E,qBAAqB,EAAE,GAAG;IAC1B,yDAAyD;IACzD,gBAAgB,EAAE,GAAG;IACrB,0BAA0B;IAC1B,gBAAgB,EAAE,IAAI;IACtB,6CAA6C;IAC7C,QAAQ,EAAE,IAAI;IACd,4CAA4C;IAC5C,aAAa,EAAE,GAAG;IAClB,6CAA6C;IAC7C,qBAAqB,EAAE,CAAC;IACxB;;;;;OAKG;IACH,wBAAwB,EAAE,MAAM;IAChC,wDAAwD;IACxD,SAAS,EAAE,GAAG;IACd,iDAAiD;IACjD,YAAY,EAAE,EAAE;IAChB,oDAAoD;IACpD,aAAa,EAAE,IAAI;IACnB,mDAAmD;IACnD,iBAAiB,EAAE,IAAI;IACvB,6BAA6B;IAC7B,eAAe,EAAE,IAAI;IACrB,4DAA4D;IAC5D,eAAe,EAAE,GAAG;IACpB,kEAAkE;IAClE,qBAAqB,EAAE,GAAG;IAC1B,iEAAiE;IACjE,oBAAoB,EAAE,EAAE;IACxB,+BAA+B;IAC/B,eAAe,EAAE,EAAE;IACnB,4BAA4B;IAC5B,gBAAgB,EAAE,GAAG;IACrB,+BAA+B;IAC/B,qBAAqB,EAAE,EAAE;CACjB,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nexport type {\n SlackActionElement,\n SlackActionsBlock,\n SlackBlock,\n SlackButtonElement,\n SlackCheckboxesElement,\n SlackContainerBlock,\n SlackContainerChildBlock,\n SlackContextBlock,\n SlackDividerBlock,\n SlackFileReference,\n SlackHeaderBlock,\n SlackHeaderLevel,\n SlackImageBlock,\n SlackImageElement,\n SlackMrkdwnTextObject,\n SlackMultiStaticSelectElement,\n SlackOptionGroup,\n SlackOptionObject,\n SlackOverflowElement,\n SlackPlainTextObject,\n SlackRadioButtonsElement,\n SlackRawTextElement,\n SlackRichTextBlock,\n SlackRichTextBlockElement,\n SlackRichTextInline,\n SlackRichTextLink,\n SlackRichTextList,\n SlackRichTextPreformatted,\n SlackRichTextQuote,\n SlackRichTextSection,\n SlackRichTextStyle,\n SlackRichTextTag,\n SlackRichTextText,\n SlackSectionAccessory,\n SlackSectionBlock,\n SlackStaticSelectElement,\n SlackTableBlock,\n SlackTableCell,\n SlackTableColumnSetting,\n SlackTagColor,\n SlackTextObject,\n SlackVideoBlock,\n} from '../../define/slack_blocks';\n\n/**\n * Slack's published surface limits, enforced by the renderer so a composition\n * cannot silently trip Slack's validation.\n */\nexport const SLACK_LIMITS = {\n /** Top-level blocks; a `container`'s `child_blocks` do not count. */\n blocksPerMessage: 50,\n /** `container.title`, which is `plain_text`. */\n containerTitleChars: 150,\n /** `container.subtitle`. */\n containerSubtitleChars: 150,\n /** `container.child_blocks`; Slack also requires at least one. */\n containerChildBlocks: 10,\n /** `section.text`. */\n sectionTextChars: 3000,\n /** One entry of `section.fields`. */\n sectionFieldChars: 2000,\n /** One entry of `context.elements`. */\n contextElementChars: 2000,\n /** `header.text`, which is `plain_text`. */\n headerTextChars: 150,\n fieldsPerSection: 10,\n /** Elements per `context` block. */\n contextElements: 10,\n buttonsPerActions: 25,\n /** Slack truncates the top-level `text` fallback in notifications around here. */\n fallbackTextChars: 4000,\n /** `plain_text` option labels (selects, radio, checkboxes, overflow). */\n optionTextChars: 75,\n /** Options per select, or per option group of one. */\n optionsPerSelect: 100,\n /** Options per overflow menu (Slack caps overflow at 5). */\n optionsPerOverflow: 5,\n /** Options per radio button group or checkboxes element. */\n optionsPerChoice: 10,\n /** Option groups per select, each holding up to `optionsPerSelect` options. */\n optionGroupsPerSelect: 100,\n /** An option's `value`, which interactions send back. */\n optionValueChars: 150,\n /** A button's `value`. */\n buttonValueChars: 2000,\n /** A button's or overflow option's `url`. */\n urlChars: 3000,\n /** An interactive element's `action_id`. */\n actionIdChars: 255,\n /** Max indent level for `rich_text_list`. */\n richTextListMaxIndent: 8,\n /**\n * Characters across every table cell in one message. Slack publishes the\n * same 10,000 figure per table and per message, so the message-wide\n * aggregate is the binding one.\n * https://docs.slack.dev/reference/block-kit/blocks/table-block/\n */\n tableCellCharsPerMessage: 10_000,\n /** Rows per `table` block (includes the header row). */\n tableRows: 100,\n /** Cells per `table` row / columns per table. */\n tableColumns: 20,\n /** `image`/image-element `image_url` max length. */\n imageUrlChars: 3000,\n /** `image`/image-element `alt_text` max length. */\n imageAltTextChars: 2000,\n /** `image` block `title`. */\n imageTitleChars: 2000,\n /** `video` block `title`; Slack requires fewer than 200. */\n videoTitleChars: 199,\n /** `video` block `description`; Slack requires fewer than 200. */\n videoDescriptionChars: 199,\n /** `video` block `author_name`; Slack requires fewer than 50. */\n videoAuthorNameChars: 49,\n /** `button` element `text`. */\n buttonTextChars: 75,\n /** Select `placeholder`. */\n placeholderChars: 150,\n /** `option_groups[].label`. */\n optionGroupLabelChars: 75,\n} as const;\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type SlackBlock, type SlackContainerBlock, type SlackContainerChildBlock, type SlackHeaderLevel } from './blocks.js';
|
|
2
|
+
/** Options for {@link slackContainer}: the container's optional fields, and the level of the `header` it falls back to. */
|
|
3
|
+
export type SlackContainerOptions = Partial<Pick<SlackContainerBlock, 'block_id' | 'subtitle' | 'icon' | 'width' | 'is_collapsible' | 'default_collapsed' | 'has_header_divider'>> & {
|
|
4
|
+
fallbackLevel?: SlackHeaderLevel;
|
|
5
|
+
};
|
|
6
|
+
/** A container Isomer fits, as opposed to one passed through `unmodeledSlackBlock`. */
|
|
7
|
+
export declare const isContainer: (block: SlackBlock) => block is SlackContainerBlock;
|
|
8
|
+
/** A container as the blocks it holds, led by its title and subtitle. */
|
|
9
|
+
export declare const unwrapContainer: ({ title, rich_text_title, subtitle, child_blocks }: SlackContainerBlock, level?: SlackHeaderLevel) => SlackContainerChildBlock[];
|
|
10
|
+
/**
|
|
11
|
+
* `container` holding `children`, with any nested container unwrapped, since
|
|
12
|
+
* Slack rejects one. A container left with no children, or more than
|
|
13
|
+
* `containerChildBlocks`, is unwrapped itself.
|
|
14
|
+
*/
|
|
15
|
+
export declare const containerWithChildren: (container: SlackContainerBlock, children: readonly SlackBlock[], level?: SlackHeaderLevel) => SlackBlock[];
|
|
16
|
+
/**
|
|
17
|
+
* A titled section as one Block Kit `container`, from its title and the
|
|
18
|
+
* blocks its body rendered to, typically through `scope.renderSlack`.
|
|
19
|
+
*
|
|
20
|
+
* A nested container among `children` is unwrapped to its title and blocks.
|
|
21
|
+
* With no children, or more than `SLACK_LIMITS.containerChildBlocks`, the
|
|
22
|
+
* section falls back to a `header` at `fallbackLevel` followed by the blocks.
|
|
23
|
+
*/
|
|
24
|
+
export declare const slackContainer: (title: string, children: readonly SlackBlock[], { fallbackLevel, ...fields }?: SlackContainerOptions) => SlackBlock[];
|
|
25
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../src/render/slack/container.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACtB,MAAM,UAAU,CAAC;AAIlB,2HAA2H;AAC3H,MAAM,MAAM,qBAAqB,GAAG,OAAO,CACzC,IAAI,CACF,mBAAmB,EACjB,UAAU,GACV,UAAU,GACV,MAAM,GACN,OAAO,GACP,gBAAgB,GAChB,mBAAmB,GACnB,oBAAoB,CACvB,CACF,GAAG;IAAE,aAAa,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEzC,uFAAuF;AACvF,eAAO,MAAM,WAAW,GAAI,OAAO,UAAU,KAAG,KAAK,IAAI,mBACI,CAAC;AAE9D,yEAAyE;AACzE,eAAO,MAAM,eAAe,GAC1B,oDAAoD,mBAAmB,EACvE,QAAQ,gBAAgB,KACvB,wBAAwB,EAc1B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,WAAW,mBAAmB,EAC9B,UAAU,SAAS,UAAU,EAAE,EAC/B,QAAQ,gBAAgB,KACvB,UAAU,EASZ,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,UAAU,SAAS,UAAU,EAAE,EAC/B,+BAA8B,qBAA0B,KACvD,UAAU,EAUV,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { SLACK_LIMITS, } from './blocks.js';
|
|
8
|
+
import { formatHeaderText } from './format.js';
|
|
9
|
+
import { isUnmodeledSlackBlock } from './unmodeled.js';
|
|
10
|
+
/** A container Isomer fits, as opposed to one passed through `unmodeledSlackBlock`. */
|
|
11
|
+
export const isContainer = (block) => block.type === 'container' && !isUnmodeledSlackBlock(block);
|
|
12
|
+
/** A container as the blocks it holds, led by its title and subtitle. */
|
|
13
|
+
export const unwrapContainer = ({ title, rich_text_title, subtitle, child_blocks }, level) => [
|
|
14
|
+
...(rich_text_title
|
|
15
|
+
? [rich_text_title]
|
|
16
|
+
: title
|
|
17
|
+
? [
|
|
18
|
+
{
|
|
19
|
+
type: 'header',
|
|
20
|
+
text: title,
|
|
21
|
+
...(level === undefined ? {} : { level }),
|
|
22
|
+
},
|
|
23
|
+
]
|
|
24
|
+
: []),
|
|
25
|
+
...(subtitle ? [{ type: 'context', elements: [subtitle] }] : []),
|
|
26
|
+
...child_blocks,
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* `container` holding `children`, with any nested container unwrapped, since
|
|
30
|
+
* Slack rejects one. A container left with no children, or more than
|
|
31
|
+
* `containerChildBlocks`, is unwrapped itself.
|
|
32
|
+
*/
|
|
33
|
+
export const containerWithChildren = (container, children, level) => {
|
|
34
|
+
const child_blocks = children.flatMap((child) => isContainer(child) ? unwrapContainer(child) : [child]);
|
|
35
|
+
const refitted = { ...container, child_blocks };
|
|
36
|
+
return child_blocks.length === 0 ||
|
|
37
|
+
child_blocks.length > SLACK_LIMITS.containerChildBlocks
|
|
38
|
+
? unwrapContainer(refitted, level)
|
|
39
|
+
: [refitted];
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A titled section as one Block Kit `container`, from its title and the
|
|
43
|
+
* blocks its body rendered to, typically through `scope.renderSlack`.
|
|
44
|
+
*
|
|
45
|
+
* A nested container among `children` is unwrapped to its title and blocks.
|
|
46
|
+
* With no children, or more than `SLACK_LIMITS.containerChildBlocks`, the
|
|
47
|
+
* section falls back to a `header` at `fallbackLevel` followed by the blocks.
|
|
48
|
+
*/
|
|
49
|
+
export const slackContainer = (title, children, { fallbackLevel, ...fields } = {}) => containerWithChildren({
|
|
50
|
+
type: 'container',
|
|
51
|
+
title: { type: 'plain_text', text: formatHeaderText(title), emoji: true },
|
|
52
|
+
...fields,
|
|
53
|
+
child_blocks: [],
|
|
54
|
+
}, children, fallbackLevel);
|
|
55
|
+
//# sourceMappingURL=container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../../src/render/slack/container.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,YAAY,GAKb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAgBpD,uFAAuF;AACvF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAiB,EAAgC,EAAE,CAC7E,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;AAE9D,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,YAAY,EAAuB,EACvE,KAAwB,EACI,EAAE,CAAC;IAC/B,GAAG,CAAC,eAAe;QACjB,CAAC,CAAC,CAAC,eAAe,CAAC;QACnB,CAAC,CAAC,KAAK;YACL,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,QAAiB;oBACvB,IAAI,EAAE,KAAK;oBACX,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;iBAC1C;aACF;YACH,CAAC,CAAC,EAAE,CAAC;IACT,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAkB,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,GAAG,YAAY;CAChB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,SAA8B,EAC9B,QAA+B,EAC/B,KAAwB,EACV,EAAE;IAChB,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC9C,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CACtD,CAAC;IACF,MAAM,QAAQ,GAAG,EAAE,GAAG,SAAS,EAAE,YAAY,EAAE,CAAC;IAChD,OAAO,YAAY,CAAC,MAAM,KAAK,CAAC;QAC9B,YAAY,CAAC,MAAM,GAAG,YAAY,CAAC,oBAAoB;QACvD,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC;QAClC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AACjB,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,KAAa,EACb,QAA+B,EAC/B,EAAE,aAAa,EAAE,GAAG,MAAM,KAA4B,EAAE,EAC1C,EAAE,CAChB,qBAAqB,CACnB;IACE,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE;IACzE,GAAG,MAAM;IACT,YAAY,EAAE,EAAE;CACjB,EACD,QAAQ,EACR,aAAa,CACd,CAAC","sourcesContent":["/*\n * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one\n * or more contributor license agreements. Licensed under the Elastic License\n * 2.0; you may not use this file except in compliance with the Elastic License\n * 2.0.\n */\n\nimport {\n SLACK_LIMITS,\n type SlackBlock,\n type SlackContainerBlock,\n type SlackContainerChildBlock,\n type SlackHeaderLevel,\n} from './blocks';\nimport { formatHeaderText } from './format';\nimport { isUnmodeledSlackBlock } from './unmodeled';\n\n/** Options for {@link slackContainer}: the container's optional fields, and the level of the `header` it falls back to. */\nexport type SlackContainerOptions = Partial<\n Pick<\n SlackContainerBlock,\n | 'block_id'\n | 'subtitle'\n | 'icon'\n | 'width'\n | 'is_collapsible'\n | 'default_collapsed'\n | 'has_header_divider'\n >\n> & { fallbackLevel?: SlackHeaderLevel };\n\n/** A container Isomer fits, as opposed to one passed through `unmodeledSlackBlock`. */\nexport const isContainer = (block: SlackBlock): block is SlackContainerBlock =>\n block.type === 'container' && !isUnmodeledSlackBlock(block);\n\n/** A container as the blocks it holds, led by its title and subtitle. */\nexport const unwrapContainer = (\n { title, rich_text_title, subtitle, child_blocks }: SlackContainerBlock,\n level?: SlackHeaderLevel\n): SlackContainerChildBlock[] => [\n ...(rich_text_title\n ? [rich_text_title]\n : title\n ? [\n {\n type: 'header' as const,\n text: title,\n ...(level === undefined ? {} : { level }),\n },\n ]\n : []),\n ...(subtitle ? [{ type: 'context' as const, elements: [subtitle] }] : []),\n ...child_blocks,\n];\n\n/**\n * `container` holding `children`, with any nested container unwrapped, since\n * Slack rejects one. A container left with no children, or more than\n * `containerChildBlocks`, is unwrapped itself.\n */\nexport const containerWithChildren = (\n container: SlackContainerBlock,\n children: readonly SlackBlock[],\n level?: SlackHeaderLevel\n): SlackBlock[] => {\n const child_blocks = children.flatMap((child) =>\n isContainer(child) ? unwrapContainer(child) : [child]\n );\n const refitted = { ...container, child_blocks };\n return child_blocks.length === 0 ||\n child_blocks.length > SLACK_LIMITS.containerChildBlocks\n ? unwrapContainer(refitted, level)\n : [refitted];\n};\n\n/**\n * A titled section as one Block Kit `container`, from its title and the\n * blocks its body rendered to, typically through `scope.renderSlack`.\n *\n * A nested container among `children` is unwrapped to its title and blocks.\n * With no children, or more than `SLACK_LIMITS.containerChildBlocks`, the\n * section falls back to a `header` at `fallbackLevel` followed by the blocks.\n */\nexport const slackContainer = (\n title: string,\n children: readonly SlackBlock[],\n { fallbackLevel, ...fields }: SlackContainerOptions = {}\n): SlackBlock[] =>\n containerWithChildren(\n {\n type: 'container',\n title: { type: 'plain_text', text: formatHeaderText(title), emoji: true },\n ...fields,\n child_blocks: [],\n },\n children,\n fallbackLevel\n );\n"]}
|
|
@@ -3,6 +3,7 @@ import type { PrimitiveNode } from '../../define/primitive_module.js';
|
|
|
3
3
|
import type { MarkdownEnvelopeDispatcher } from '../markdown/envelope.js';
|
|
4
4
|
import { type SlackAssetCollector, type SlackAssetRequest } from './assets.js';
|
|
5
5
|
import { type SlackBlock } from './blocks.js';
|
|
6
|
+
import { type SlackLinkOptions } from './format.js';
|
|
6
7
|
/**
|
|
7
8
|
* Adds Block Kit to {@link MarkdownEnvelopeDispatcher}.
|
|
8
9
|
*
|
|
@@ -14,10 +15,10 @@ import { type SlackBlock } from './blocks.js';
|
|
|
14
15
|
*/
|
|
15
16
|
export interface SlackEnvelopeDispatcher<TNode extends PrimitiveNode> extends MarkdownEnvelopeDispatcher<TNode> {
|
|
16
17
|
/** `collector` is absent unless the caller opted into asset collection, so a renderer must still degrade an image it cannot upload. */
|
|
17
|
-
renderSlack(node: TNode, collector?: SlackAssetCollector): readonly SlackBlock[];
|
|
18
|
+
renderSlack(node: TNode, collector?: SlackAssetCollector, options?: SlackLinkOptions): readonly SlackBlock[];
|
|
18
19
|
}
|
|
19
20
|
/** Options for {@link renderSlackEnvelope}. */
|
|
20
|
-
export interface SlackEnvelopeOptions {
|
|
21
|
+
export interface SlackEnvelopeOptions extends SlackLinkOptions {
|
|
21
22
|
/** 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. */
|
|
22
23
|
heading?: boolean;
|
|
23
24
|
/** Fallback `text` summary shown in notifications and previews, as `mrkdwn`; defaults to the text render, escaped. */
|
|
@@ -45,8 +46,9 @@ export interface SlackEnvelopeResult {
|
|
|
45
46
|
* fitted to Slack's limits — text is clamped, blocks past a count limit and
|
|
46
47
|
* `rich_text` elements past a section's limit split, tables past a table limit
|
|
47
48
|
* or the message's cell budget become rich text, spacers and then whole blocks
|
|
48
|
-
* are dropped — so the output is always postable
|
|
49
|
-
*
|
|
49
|
+
* are dropped — so the output is always postable, except for a block from
|
|
50
|
+
* `unmodeledSlackBlock` or of a type Isomer does not model, which passes
|
|
51
|
+
* through unfitted. `assets` stays empty unless `collectAssets` is set.
|
|
50
52
|
*/
|
|
51
53
|
export declare const renderSlackEnvelope: <TNode extends PrimitiveNode>(composition: Composition<TNode>, dispatcher: SlackEnvelopeDispatcher<TNode>, options?: SlackEnvelopeOptions) => SlackEnvelopeResult;
|
|
52
54
|
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/render/slack/envelope.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,UAAU,CAAC;AAClB,OAAO,EAGL,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/render/slack/envelope.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACvB,MAAM,UAAU,CAAC;AAClB,OAAO,EAGL,KAAK,UAAU,EAchB,MAAM,UAAU,CAAC;AAElB,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,UAAU,CAAC;AAGlB;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB,CACtC,KAAK,SAAS,aAAa,CAC3B,SAAQ,0BAA0B,CAAC,KAAK,CAAC;IACzC,uIAAuI;IACvI,WAAW,CACT,IAAI,EAAE,KAAK,EACX,SAAS,CAAC,EAAE,mBAAmB,EAC/B,OAAO,CAAC,EAAE,gBAAgB,GACzB,SAAS,UAAU,EAAE,CAAC;CAC1B;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D,mMAAmM;IACnM,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sHAAsH;IACtH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8GAA8G;IAC9G,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,qEAAqE;IACrE,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,SAAS,aAAa,EAC7D,aAAa,WAAW,CAAC,KAAK,CAAC,EAC/B,YAAY,uBAAuB,CAAC,KAAK,CAAC,EAC1C,UAAS,oBAAyB,KACjC,mBA+CF,CAAC"}
|