@elastic/isomer-sdk 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.txt +0 -286
- package/THIRD_PARTY_LICENSES.md +1 -885
- package/dist/author/authored_fields.d.ts +37 -12
- package/dist/author/authored_fields.d.ts.map +1 -1
- package/dist/author/authored_fields.js +45 -69
- package/dist/author/authored_fields.js.map +1 -1
- package/dist/author/authoring_input.d.ts.map +1 -1
- package/dist/author/authoring_input.js +12 -6
- package/dist/author/authoring_input.js.map +1 -1
- package/dist/author/authoring_model.d.ts +8 -2
- package/dist/author/authoring_model.d.ts.map +1 -1
- package/dist/author/authoring_model.js +67 -23
- package/dist/author/authoring_model.js.map +1 -1
- package/dist/author/declarations.d.ts.map +1 -1
- package/dist/author/declarations.js +45 -34
- package/dist/author/declarations.js.map +1 -1
- package/dist/author/index.d.ts +2 -1
- package/dist/author/index.d.ts.map +1 -1
- package/dist/author/index.js +2 -1
- package/dist/author/index.js.map +1 -1
- package/dist/author/jsx_shim.d.ts +49 -30
- package/dist/author/jsx_shim.d.ts.map +1 -1
- package/dist/author/jsx_shim.js +131 -40
- package/dist/author/jsx_shim.js.map +1 -1
- package/dist/author/print_jsx.d.ts +19 -0
- package/dist/author/print_jsx.d.ts.map +1 -0
- package/dist/author/print_jsx.js +372 -0
- package/dist/author/print_jsx.js.map +1 -0
- package/dist/author/prompt.d.ts +2 -2
- package/dist/author/prompt.d.ts.map +1 -1
- package/dist/author/prompt.js +7 -2
- package/dist/author/prompt.js.map +1 -1
- package/dist/author/schema_to_typescript.d.ts.map +1 -1
- package/dist/author/schema_to_typescript.js +6 -3
- package/dist/author/schema_to_typescript.js.map +1 -1
- package/dist/cjs/author/authored_fields.js +47 -70
- package/dist/cjs/author/authored_fields.js.map +1 -1
- package/dist/cjs/author/authoring_input.js +12 -6
- package/dist/cjs/author/authoring_input.js.map +1 -1
- package/dist/cjs/author/authoring_model.js +69 -24
- package/dist/cjs/author/authoring_model.js.map +1 -1
- package/dist/cjs/author/declarations.js +44 -33
- package/dist/cjs/author/declarations.js.map +1 -1
- package/dist/cjs/author/index.js +5 -1
- package/dist/cjs/author/index.js.map +1 -1
- package/dist/cjs/author/jsx_shim.js +130 -39
- package/dist/cjs/author/jsx_shim.js.map +1 -1
- package/dist/cjs/author/print_jsx.js +378 -0
- package/dist/cjs/author/print_jsx.js.map +1 -0
- package/dist/cjs/author/prompt.js +7 -2
- package/dist/cjs/author/prompt.js.map +1 -1
- package/dist/cjs/author/schema_to_typescript.js +6 -3
- package/dist/cjs/author/schema_to_typescript.js.map +1 -1
- package/dist/cjs/composition/error.js +2 -0
- package/dist/cjs/composition/error.js.map +1 -1
- package/dist/cjs/composition/structured_value.js.map +1 -1
- package/dist/cjs/define/index.js.map +1 -1
- package/dist/cjs/define/primitive_module.js +10 -4
- package/dist/cjs/define/primitive_module.js.map +1 -1
- package/dist/cjs/define/slack_blocks.js.map +1 -1
- package/dist/cjs/entries/index.js +5 -2
- package/dist/cjs/entries/index.js.map +1 -1
- package/dist/cjs/entries/markdown.js +3 -1
- package/dist/cjs/entries/markdown.js.map +1 -1
- package/dist/cjs/entries/react.js +2 -1
- package/dist/cjs/entries/react.js.map +1 -1
- package/dist/cjs/entries/slack.js +5 -1
- package/dist/cjs/entries/slack.js.map +1 -1
- package/dist/cjs/pack/enhancements.js.map +1 -1
- package/dist/cjs/pack/index.js +2 -1
- package/dist/cjs/pack/index.js.map +1 -1
- package/dist/cjs/pack/primitive_pack.js +14 -4
- package/dist/cjs/pack/primitive_pack.js.map +1 -1
- package/dist/cjs/render/format_number.js +2 -1
- package/dist/cjs/render/format_number.js.map +1 -1
- package/dist/cjs/render/html/envelope.js +12 -6
- package/dist/cjs/render/html/envelope.js.map +1 -1
- package/dist/cjs/render/markdown/blocks.js +82 -0
- package/dist/cjs/render/markdown/blocks.js.map +1 -0
- package/dist/cjs/render/markdown/builder.js +6 -2
- package/dist/cjs/render/markdown/builder.js.map +1 -1
- package/dist/cjs/render/markdown/format.js +46 -24
- package/dist/cjs/render/markdown/format.js.map +1 -1
- package/dist/cjs/render/markdown/host_tags.js +67 -0
- package/dist/cjs/render/markdown/host_tags.js.map +1 -0
- package/dist/cjs/render/markdown/index.js +5 -1
- package/dist/cjs/render/markdown/index.js.map +1 -1
- package/dist/cjs/render/markdown/split.js +325 -0
- package/dist/cjs/render/markdown/split.js.map +1 -0
- package/dist/cjs/render/primitive_dispatch.js +36 -6
- package/dist/cjs/render/primitive_dispatch.js.map +1 -1
- package/dist/cjs/render/react/content.js +3 -1
- package/dist/cjs/render/react/content.js.map +1 -1
- package/dist/cjs/render/react/index.js +3 -1
- package/dist/cjs/render/react/index.js.map +1 -1
- package/dist/cjs/render/react/markdown_content.js +143 -0
- package/dist/cjs/render/react/markdown_content.js.map +1 -0
- package/dist/cjs/render/slack/blocks.js +7 -0
- package/dist/cjs/render/slack/blocks.js.map +1 -1
- package/dist/cjs/render/slack/container.js +62 -0
- package/dist/cjs/render/slack/container.js.map +1 -0
- package/dist/cjs/render/slack/envelope.js +70 -14
- package/dist/cjs/render/slack/envelope.js.map +1 -1
- package/dist/cjs/render/slack/format.js +56 -6
- package/dist/cjs/render/slack/format.js.map +1 -1
- package/dist/cjs/render/slack/index.js +7 -1
- package/dist/cjs/render/slack/index.js.map +1 -1
- package/dist/cjs/render/slack/markdown_content.js +36 -77
- package/dist/cjs/render/slack/markdown_content.js.map +1 -1
- package/dist/cjs/render/slack/unmodeled.js +38 -0
- package/dist/cjs/render/slack/unmodeled.js.map +1 -0
- package/dist/cjs/testing/conformance.js +15 -1
- package/dist/cjs/testing/conformance.js.map +1 -1
- package/dist/cjs/testing/index.js +2 -1
- package/dist/cjs/testing/index.js.map +1 -1
- package/dist/cjs/validate/json_schema.js +10 -3
- package/dist/cjs/validate/json_schema.js.map +1 -1
- package/dist/cjs/validate/url.js +2 -1
- package/dist/cjs/validate/url.js.map +1 -1
- package/dist/composition/error.d.ts +2 -0
- package/dist/composition/error.d.ts.map +1 -1
- package/dist/composition/error.js +2 -0
- package/dist/composition/error.js.map +1 -1
- package/dist/composition/structured_value.d.ts +3 -3
- package/dist/composition/structured_value.d.ts.map +1 -1
- package/dist/composition/structured_value.js.map +1 -1
- package/dist/define/index.d.ts +1 -1
- package/dist/define/index.d.ts.map +1 -1
- package/dist/define/index.js.map +1 -1
- package/dist/define/primitive_module.d.ts +14 -5
- package/dist/define/primitive_module.d.ts.map +1 -1
- package/dist/define/primitive_module.js +10 -4
- package/dist/define/primitive_module.js.map +1 -1
- package/dist/define/slack_blocks.d.ts +31 -1
- package/dist/define/slack_blocks.d.ts.map +1 -1
- package/dist/define/slack_blocks.js.map +1 -1
- package/dist/entries/index.d.ts +2 -2
- package/dist/entries/index.d.ts.map +1 -1
- package/dist/entries/index.js +2 -2
- package/dist/entries/index.js.map +1 -1
- package/dist/entries/markdown.d.ts +1 -1
- package/dist/entries/markdown.d.ts.map +1 -1
- package/dist/entries/markdown.js +1 -1
- package/dist/entries/markdown.js.map +1 -1
- package/dist/entries/react.d.ts +1 -1
- package/dist/entries/react.d.ts.map +1 -1
- package/dist/entries/react.js +1 -1
- package/dist/entries/react.js.map +1 -1
- package/dist/entries/slack.d.ts +1 -1
- package/dist/entries/slack.d.ts.map +1 -1
- package/dist/entries/slack.js +1 -1
- package/dist/entries/slack.js.map +1 -1
- package/dist/pack/enhancements.d.ts +4 -0
- package/dist/pack/enhancements.d.ts.map +1 -1
- package/dist/pack/enhancements.js.map +1 -1
- package/dist/pack/index.d.ts +1 -1
- package/dist/pack/index.d.ts.map +1 -1
- package/dist/pack/index.js +1 -1
- package/dist/pack/index.js.map +1 -1
- package/dist/pack/primitive_pack.d.ts +3 -1
- package/dist/pack/primitive_pack.d.ts.map +1 -1
- package/dist/pack/primitive_pack.js +13 -3
- package/dist/pack/primitive_pack.js.map +1 -1
- package/dist/render/format_number.d.ts.map +1 -1
- package/dist/render/format_number.js +2 -1
- package/dist/render/format_number.js.map +1 -1
- package/dist/render/html/envelope.js +12 -6
- package/dist/render/html/envelope.js.map +1 -1
- package/dist/render/markdown/blocks.d.ts +6 -0
- package/dist/render/markdown/blocks.d.ts.map +1 -0
- package/dist/render/markdown/blocks.js +77 -0
- package/dist/render/markdown/blocks.js.map +1 -0
- package/dist/render/markdown/builder.d.ts +3 -0
- package/dist/render/markdown/builder.d.ts.map +1 -1
- package/dist/render/markdown/builder.js +3 -1
- package/dist/render/markdown/builder.js.map +1 -1
- package/dist/render/markdown/format.d.ts +2 -0
- package/dist/render/markdown/format.d.ts.map +1 -1
- package/dist/render/markdown/format.js +42 -22
- package/dist/render/markdown/format.js.map +1 -1
- package/dist/render/markdown/host_tags.d.ts +14 -0
- package/dist/render/markdown/host_tags.d.ts.map +1 -0
- package/dist/render/markdown/host_tags.js +63 -0
- package/dist/render/markdown/host_tags.js.map +1 -0
- package/dist/render/markdown/index.d.ts +2 -0
- package/dist/render/markdown/index.d.ts.map +1 -1
- package/dist/render/markdown/index.js +2 -0
- package/dist/render/markdown/index.js.map +1 -1
- package/dist/render/markdown/split.d.ts +32 -0
- package/dist/render/markdown/split.d.ts.map +1 -0
- package/dist/render/markdown/split.js +321 -0
- package/dist/render/markdown/split.js.map +1 -0
- package/dist/render/primitive_dispatch.d.ts +4 -2
- package/dist/render/primitive_dispatch.d.ts.map +1 -1
- package/dist/render/primitive_dispatch.js +36 -6
- package/dist/render/primitive_dispatch.js.map +1 -1
- package/dist/render/react/content.d.ts +1 -1
- package/dist/render/react/content.d.ts.map +1 -1
- package/dist/render/react/content.js +3 -1
- package/dist/render/react/content.js.map +1 -1
- package/dist/render/react/index.d.ts +1 -0
- package/dist/render/react/index.d.ts.map +1 -1
- package/dist/render/react/index.js +1 -0
- package/dist/render/react/index.js.map +1 -1
- package/dist/render/react/markdown_content.d.ts +9 -0
- package/dist/render/react/markdown_content.d.ts.map +1 -0
- package/dist/render/react/markdown_content.js +139 -0
- package/dist/render/react/markdown_content.js.map +1 -0
- package/dist/render/slack/blocks.d.ts +8 -1
- package/dist/render/slack/blocks.d.ts.map +1 -1
- package/dist/render/slack/blocks.js +7 -0
- package/dist/render/slack/blocks.js.map +1 -1
- package/dist/render/slack/container.d.ts +25 -0
- package/dist/render/slack/container.d.ts.map +1 -0
- package/dist/render/slack/container.js +55 -0
- package/dist/render/slack/container.js.map +1 -0
- package/dist/render/slack/envelope.d.ts +6 -4
- package/dist/render/slack/envelope.d.ts.map +1 -1
- package/dist/render/slack/envelope.js +71 -15
- package/dist/render/slack/envelope.js.map +1 -1
- package/dist/render/slack/format.d.ts +15 -3
- package/dist/render/slack/format.d.ts.map +1 -1
- package/dist/render/slack/format.js +54 -5
- package/dist/render/slack/format.js.map +1 -1
- package/dist/render/slack/index.d.ts +4 -2
- package/dist/render/slack/index.d.ts.map +1 -1
- package/dist/render/slack/index.js +2 -0
- package/dist/render/slack/index.js.map +1 -1
- package/dist/render/slack/markdown_content.d.ts +3 -2
- package/dist/render/slack/markdown_content.d.ts.map +1 -1
- package/dist/render/slack/markdown_content.js +27 -68
- package/dist/render/slack/markdown_content.js.map +1 -1
- package/dist/render/slack/unmodeled.d.ts +16 -0
- package/dist/render/slack/unmodeled.d.ts.map +1 -0
- package/dist/render/slack/unmodeled.js +32 -0
- package/dist/render/slack/unmodeled.js.map +1 -0
- package/dist/testing/conformance.d.ts +3 -1
- package/dist/testing/conformance.d.ts.map +1 -1
- package/dist/testing/conformance.js +14 -0
- package/dist/testing/conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/validate/json_schema.d.ts.map +1 -1
- package/dist/validate/json_schema.js +10 -3
- package/dist/validate/json_schema.js.map +1 -1
- package/dist/validate/url.d.ts.map +1 -1
- package/dist/validate/url.js +2 -1
- package/dist/validate/url.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,321 @@
|
|
|
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 { md, printParsed, verbatim } from './builder.js';
|
|
8
|
+
import { exceedsParseBudget, inert, parseGfmBlocks } from './format.js';
|
|
9
|
+
import { findHostTags } from './host_tags.js';
|
|
10
|
+
// A sentinel keeps the tag's own `<` and `>` as its edges, so emphasis and
|
|
11
|
+
// other delimiters around it read exactly as they did around the tag, and
|
|
12
|
+
// holds private-use characters between them, which no Markdown construct
|
|
13
|
+
// reads, so it parses as text wherever the tag was written. Any already in
|
|
14
|
+
// the source, literal or as a character reference (the only other way text
|
|
15
|
+
// can decode to one), are replaced first, so the parsed text holds sentinels
|
|
16
|
+
// only where tags were.
|
|
17
|
+
const SENTINEL_RE = /<\uE000(\d+)\uE001>/g;
|
|
18
|
+
// In a link destination the parser strips the angle brackets.
|
|
19
|
+
const SENTINEL_ANYWHERE_RE = /<?\uE000(\d+)\uE001>?/g;
|
|
20
|
+
const RESERVED_RE = /[\uE000\uE001]|&#(?:[xX]0*[eE]00[01]|0*5734[45]);/g;
|
|
21
|
+
const sentinel = (index) => `<\uE000${index}\uE001>`;
|
|
22
|
+
const withoutReserved = (source) => source.replace(RESERVED_RE, (match) => match.length === 1 ? '\uFFFD' : '�');
|
|
23
|
+
// Tags written identically get the same sentinel, so a reference label that
|
|
24
|
+
// holds one still matches a definition that holds the same. Sharing by
|
|
25
|
+
// exact text keeps each tag's attributes and spelling its own.
|
|
26
|
+
const substitute = (source, tags) => {
|
|
27
|
+
const first = new Map();
|
|
28
|
+
let out = '';
|
|
29
|
+
let cursor = 0;
|
|
30
|
+
tags.forEach((tag, index) => {
|
|
31
|
+
if (!first.has(tag.raw)) {
|
|
32
|
+
first.set(tag.raw, index);
|
|
33
|
+
}
|
|
34
|
+
out += source.slice(cursor, tag.index) + sentinel(first.get(tag.raw));
|
|
35
|
+
cursor = tag.index + tag.raw.length;
|
|
36
|
+
});
|
|
37
|
+
return out + source.slice(cursor);
|
|
38
|
+
};
|
|
39
|
+
// The GFM serializer's cost grows steeply with nesting depth, while the
|
|
40
|
+
// parse budget bounds breadth, not depth. Nothing authored nests this deep.
|
|
41
|
+
const MAX_DEPTH = 64;
|
|
42
|
+
const exceedsDepth = (nodes, depth = 1) => depth > MAX_DEPTH ||
|
|
43
|
+
nodes.some((node) => 'children' in node && exceedsDepth(node.children, depth + 1));
|
|
44
|
+
// The tag's node in the tree, until it is cut out again.
|
|
45
|
+
const HOST = 'isomerHostElement';
|
|
46
|
+
const isHost = (node) => node.type === HOST;
|
|
47
|
+
const hostTag = (node) => node.tag;
|
|
48
|
+
const element = ({ name, attributes }) => ({
|
|
49
|
+
type: 'element',
|
|
50
|
+
name,
|
|
51
|
+
attributes,
|
|
52
|
+
});
|
|
53
|
+
const markdown = (source) => source.trim() === ''
|
|
54
|
+
? []
|
|
55
|
+
: [{ type: 'markdown', content: md.authored(source), source }];
|
|
56
|
+
// A sentinel in a text node becomes a host node between the text around it.
|
|
57
|
+
// In any other string (code, alt, url, title, HTML) the tag text goes back. A
|
|
58
|
+
// footnote prints at the end of its segment, away from where it is cited, so
|
|
59
|
+
// a tag inside one is literal too.
|
|
60
|
+
const resolve = (node, tags, literal) => {
|
|
61
|
+
if (node.type === 'text' && !literal) {
|
|
62
|
+
const parts = [];
|
|
63
|
+
let cursor = 0;
|
|
64
|
+
for (const match of node.value.matchAll(SENTINEL_RE)) {
|
|
65
|
+
if (match.index > cursor) {
|
|
66
|
+
parts.push({
|
|
67
|
+
type: 'text',
|
|
68
|
+
value: node.value.slice(cursor, match.index),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
parts.push({
|
|
72
|
+
type: HOST,
|
|
73
|
+
tag: tags[Number(match[1])],
|
|
74
|
+
});
|
|
75
|
+
cursor = match.index + match[0].length;
|
|
76
|
+
}
|
|
77
|
+
if (parts.length === 0) {
|
|
78
|
+
return [node];
|
|
79
|
+
}
|
|
80
|
+
if (cursor < node.value.length) {
|
|
81
|
+
parts.push({ type: 'text', value: node.value.slice(cursor) });
|
|
82
|
+
}
|
|
83
|
+
return parts;
|
|
84
|
+
}
|
|
85
|
+
const restored = { ...node };
|
|
86
|
+
for (const [key, value] of Object.entries(restored)) {
|
|
87
|
+
if (typeof value === 'string') {
|
|
88
|
+
restored[key] = value.replace(SENTINEL_ANYWHERE_RE, (_, index) => tags[Number(index)].raw);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if ('children' in node) {
|
|
92
|
+
restored.children = node.children.flatMap((child) => resolve(child, tags, literal || node.type === 'footnoteDefinition'));
|
|
93
|
+
}
|
|
94
|
+
return [restored];
|
|
95
|
+
};
|
|
96
|
+
// Depth-first, in document order.
|
|
97
|
+
const walk = (node, visit) => {
|
|
98
|
+
visit(node);
|
|
99
|
+
if ('children' in node) {
|
|
100
|
+
node.children.forEach((child) => walk(child, visit));
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const PHRASING_PARENTS = new Set([
|
|
104
|
+
'delete',
|
|
105
|
+
'emphasis',
|
|
106
|
+
'heading',
|
|
107
|
+
'link',
|
|
108
|
+
'linkReference',
|
|
109
|
+
'paragraph',
|
|
110
|
+
'strong',
|
|
111
|
+
'tableCell',
|
|
112
|
+
]);
|
|
113
|
+
// A wrapper the tag leaves empty would print its markers alone (`****` is a
|
|
114
|
+
// thematic break). Containers keep their place: an empty list item keeps the
|
|
115
|
+
// numbering of the items after it.
|
|
116
|
+
const DROPPED_WHEN_EMPTY = new Set([
|
|
117
|
+
'delete',
|
|
118
|
+
'emphasis',
|
|
119
|
+
'heading',
|
|
120
|
+
'link',
|
|
121
|
+
'linkReference',
|
|
122
|
+
'paragraph',
|
|
123
|
+
'strong',
|
|
124
|
+
]);
|
|
125
|
+
// Text either side of a removed tag joins, with one space if either side
|
|
126
|
+
// had one. The run's edges are trimmed, and a hard break left at an edge is
|
|
127
|
+
// dropped as `md.paragraph` drops it, since it would print as a bare `\\`.
|
|
128
|
+
const tidyPhrasing = (children) => {
|
|
129
|
+
const joined = [];
|
|
130
|
+
for (const child of children) {
|
|
131
|
+
const previous = joined[joined.length - 1];
|
|
132
|
+
if (previous?.type === 'text' && child.type === 'text') {
|
|
133
|
+
const left = previous.value.replace(/\s+$/, '');
|
|
134
|
+
const right = child.value.replace(/^\s+/, '');
|
|
135
|
+
const spaced = left !== previous.value || right !== child.value;
|
|
136
|
+
joined[joined.length - 1] = {
|
|
137
|
+
type: 'text',
|
|
138
|
+
value: left + (spaced ? ' ' : '') + right,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
joined.push(child);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const isEdge = (node) => node?.type === 'break' ||
|
|
146
|
+
(node?.type === 'text' && node.value.trim() === '');
|
|
147
|
+
while (isEdge(joined[0])) {
|
|
148
|
+
joined.shift();
|
|
149
|
+
}
|
|
150
|
+
while (isEdge(joined[joined.length - 1])) {
|
|
151
|
+
joined.pop();
|
|
152
|
+
}
|
|
153
|
+
const first = joined[0];
|
|
154
|
+
if (first?.type === 'text') {
|
|
155
|
+
joined[0] = { ...first, value: first.value.trimStart() };
|
|
156
|
+
}
|
|
157
|
+
const last = joined[joined.length - 1];
|
|
158
|
+
if (last?.type === 'text') {
|
|
159
|
+
joined[joined.length - 1] = { ...last, value: last.value.trimEnd() };
|
|
160
|
+
}
|
|
161
|
+
return joined;
|
|
162
|
+
};
|
|
163
|
+
// `node` without its host nodes, which are appended to `found` in document
|
|
164
|
+
// order; `[]` when nothing is left of it. Only a node a tag was removed
|
|
165
|
+
// from is tidied, so phrasing elsewhere in the block stays as written.
|
|
166
|
+
const strip = (node, found) => {
|
|
167
|
+
if (isHost(node)) {
|
|
168
|
+
found.push(hostTag(node));
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
if (!('children' in node)) {
|
|
172
|
+
return [node];
|
|
173
|
+
}
|
|
174
|
+
const before = found.length;
|
|
175
|
+
const stripped = node.children.flatMap((child) => strip(child, found));
|
|
176
|
+
if (found.length === before) {
|
|
177
|
+
return [node];
|
|
178
|
+
}
|
|
179
|
+
const children = PHRASING_PARENTS.has(node.type)
|
|
180
|
+
? tidyPhrasing(stripped)
|
|
181
|
+
: stripped;
|
|
182
|
+
return children.length === 0 && DROPPED_WHEN_EMPTY.has(node.type)
|
|
183
|
+
? []
|
|
184
|
+
: [{ ...node, children }];
|
|
185
|
+
};
|
|
186
|
+
// The first definition of each identifier, anywhere in the tree, as the
|
|
187
|
+
// parser resolved references.
|
|
188
|
+
const firstDefinitions = (blocks) => {
|
|
189
|
+
const definitions = new Map();
|
|
190
|
+
for (const block of blocks) {
|
|
191
|
+
walk(block, (node) => {
|
|
192
|
+
if (node.type === 'definition' && !definitions.has(node.identifier)) {
|
|
193
|
+
definitions.set(node.identifier, node);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return definitions;
|
|
198
|
+
};
|
|
199
|
+
// Each segment is a document of its own, so a definition another segment
|
|
200
|
+
// holds is copied ahead of the run that references it.
|
|
201
|
+
const printRun = (run, definitions) => {
|
|
202
|
+
const present = new Set();
|
|
203
|
+
const needed = new Map();
|
|
204
|
+
for (const block of run) {
|
|
205
|
+
walk(block, (node) => {
|
|
206
|
+
present.add(node);
|
|
207
|
+
if (node.type === 'linkReference' || node.type === 'imageReference') {
|
|
208
|
+
const definition = definitions.get(node.identifier);
|
|
209
|
+
if (definition) {
|
|
210
|
+
needed.set(node.identifier, definition);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const carried = [...needed.values()].filter((node) => !present.has(node));
|
|
216
|
+
return printParsed([...carried, ...run]);
|
|
217
|
+
};
|
|
218
|
+
const splitBlocks = (blocks, tags) => {
|
|
219
|
+
const resolved = blocks.flatMap((block) => resolve(block, tags, false));
|
|
220
|
+
const definitions = firstDefinitions(resolved);
|
|
221
|
+
const segments = [];
|
|
222
|
+
let run = [];
|
|
223
|
+
const flush = () => {
|
|
224
|
+
if (run.length > 0) {
|
|
225
|
+
segments.push(...markdown(printRun(run, definitions)));
|
|
226
|
+
}
|
|
227
|
+
run = [];
|
|
228
|
+
};
|
|
229
|
+
// `block` without its tags joins the run; each tag ends the run after it.
|
|
230
|
+
const push = (block) => {
|
|
231
|
+
const found = [];
|
|
232
|
+
run.push(...strip(block, found));
|
|
233
|
+
for (const tag of found) {
|
|
234
|
+
flush();
|
|
235
|
+
segments.push(element(tag));
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
for (const block of resolved) {
|
|
239
|
+
if (block.type === 'definition') {
|
|
240
|
+
// Prints nothing where it stands; it is copied where it is referenced.
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (block.type !== 'paragraph' || !block.children.some(isHost)) {
|
|
244
|
+
push(block);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// A tag directly in a top-level paragraph splits it in place.
|
|
248
|
+
let piece = [];
|
|
249
|
+
const pushPiece = () => {
|
|
250
|
+
const children = tidyPhrasing(piece);
|
|
251
|
+
if (children.length > 0) {
|
|
252
|
+
push({ ...block, children });
|
|
253
|
+
}
|
|
254
|
+
piece = [];
|
|
255
|
+
};
|
|
256
|
+
for (const child of block.children) {
|
|
257
|
+
if (isHost(child)) {
|
|
258
|
+
pushPiece();
|
|
259
|
+
flush();
|
|
260
|
+
segments.push(element(hostTag(child)));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
piece.push(child);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
pushPiece();
|
|
267
|
+
}
|
|
268
|
+
flush();
|
|
269
|
+
return segments;
|
|
270
|
+
};
|
|
271
|
+
// Past the parse budget there is no tree to consult, so the source is cut at
|
|
272
|
+
// each tag and every piece degrades to inert text, as `md.authored` degrades.
|
|
273
|
+
const cutLinearly = (source, tags) => {
|
|
274
|
+
const segments = [];
|
|
275
|
+
const push = (piece) => {
|
|
276
|
+
const text = piece.trim();
|
|
277
|
+
if (text !== '') {
|
|
278
|
+
segments.push({
|
|
279
|
+
type: 'markdown',
|
|
280
|
+
content: verbatim(inert(text), text),
|
|
281
|
+
source: text,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
let cursor = 0;
|
|
286
|
+
for (const tag of tags) {
|
|
287
|
+
push(source.slice(cursor, tag.index));
|
|
288
|
+
segments.push(element(tag));
|
|
289
|
+
cursor = tag.index + tag.raw.length;
|
|
290
|
+
}
|
|
291
|
+
push(source.slice(cursor));
|
|
292
|
+
return segments;
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Splits authored Markdown at the host's own elements, such as
|
|
296
|
+
* `<render_attachment id="…" />`, so the host can replace each with content
|
|
297
|
+
* of its own without cutting the raw string. The source is parsed once, so a
|
|
298
|
+
* tag in code, a link destination or title, an image's alt text, or raw HTML
|
|
299
|
+
* stays text, and a list, table, quote, or emphasis around a tag stays whole.
|
|
300
|
+
* Each `markdown` segment is sanitized as `md.authored` sanitizes; past the
|
|
301
|
+
* parse budget the source is cut at each tag into inert pieces.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* splitAuthoredMarkdown(message, { elements: ['render_attachment'] })
|
|
305
|
+
*/
|
|
306
|
+
export const splitAuthoredMarkdown = (source, { elements }) => {
|
|
307
|
+
const cleaned = withoutReserved(source);
|
|
308
|
+
const tags = findHostTags(cleaned, elements);
|
|
309
|
+
if (tags.length === 0) {
|
|
310
|
+
return markdown(source);
|
|
311
|
+
}
|
|
312
|
+
// The budget applies to the source as written: a long attribute value
|
|
313
|
+
// shrinks to a sentinel, but comes back in full wherever it is literal.
|
|
314
|
+
const blocks = exceedsParseBudget(cleaned)
|
|
315
|
+
? null
|
|
316
|
+
: parseGfmBlocks(substitute(cleaned, tags));
|
|
317
|
+
return blocks && !exceedsDepth(blocks)
|
|
318
|
+
? splitBlocks(blocks, tags)
|
|
319
|
+
: cutLinearly(cleaned, tags);
|
|
320
|
+
};
|
|
321
|
+
//# sourceMappingURL=split.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../../src/render/markdown/split.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// Splits authored Markdown at a host's own tags without a second grammar:\n// each tag becomes a sentinel, the stock GFM parser parses the whole source\n// once, and where the sentinel lands says what the tag is. In a `text`\n// node it is a tag; anywhere else (a code span or block, an image's alt, a\n// link destination or title, raw HTML) it is literal and the tag text goes\n// back. Blocks that held a tag are then printed from the tree.\n\nimport type { Definition, Nodes, RootContent } from 'mdast';\n\nimport type { MarkdownContent } from '../../define/markdown_content';\n\nimport { md, printParsed, verbatim } from './builder';\nimport { exceedsParseBudget, inert, parseGfmBlocks } from './format';\nimport { findHostTags, type HostTag } from './host_tags';\n\n/** A piece of authored Markdown, or one of the host's elements cut out of it. */\nexport type AuthoredMarkdownSegment =\n | {\n type: 'markdown';\n content: MarkdownContent;\n /** The text `content` was built from, for a host that stores a string and passes it to `md.authored` later. */\n source: string;\n }\n | {\n type: 'element';\n /** The name as listed in {@link SplitAuthoredMarkdownOptions.elements}. */\n name: string;\n /** Attribute values as written, keyed by lower-cased name; a bare attribute is `''`. */\n attributes: Readonly<Record<string, string>>;\n };\n\nexport interface SplitAuthoredMarkdownOptions {\n /** Tag names to cut out, matched case-insensitively and whole. */\n readonly elements: readonly string[];\n}\n\n// A sentinel keeps the tag's own `<` and `>` as its edges, so emphasis and\n// other delimiters around it read exactly as they did around the tag, and\n// holds private-use characters between them, which no Markdown construct\n// reads, so it parses as text wherever the tag was written. Any already in\n// the source, literal or as a character reference (the only other way text\n// can decode to one), are replaced first, so the parsed text holds sentinels\n// only where tags were.\nconst SENTINEL_RE = /<\\uE000(\\d+)\\uE001>/g;\n// In a link destination the parser strips the angle brackets.\nconst SENTINEL_ANYWHERE_RE = /<?\\uE000(\\d+)\\uE001>?/g;\nconst RESERVED_RE = /[\\uE000\\uE001]|&#(?:[xX]0*[eE]00[01]|0*5734[45]);/g;\nconst sentinel = (index: number): string => `<\\uE000${index}\\uE001>`;\nconst withoutReserved = (source: string): string =>\n source.replace(RESERVED_RE, (match) =>\n match.length === 1 ? '\\uFFFD' : '�'\n );\n\n// Tags written identically get the same sentinel, so a reference label that\n// holds one still matches a definition that holds the same. Sharing by\n// exact text keeps each tag's attributes and spelling its own.\nconst substitute = (source: string, tags: readonly HostTag[]): string => {\n const first = new Map<string, number>();\n let out = '';\n let cursor = 0;\n tags.forEach((tag, index) => {\n if (!first.has(tag.raw)) {\n first.set(tag.raw, index);\n }\n out += source.slice(cursor, tag.index) + sentinel(first.get(tag.raw)!);\n cursor = tag.index + tag.raw.length;\n });\n return out + source.slice(cursor);\n};\n\n// The GFM serializer's cost grows steeply with nesting depth, while the\n// parse budget bounds breadth, not depth. Nothing authored nests this deep.\nconst MAX_DEPTH = 64;\n\nconst exceedsDepth = (nodes: readonly Nodes[], depth = 1): boolean =>\n depth > MAX_DEPTH ||\n nodes.some(\n (node) => 'children' in node && exceedsDepth(node.children, depth + 1)\n );\n\n// The tag's node in the tree, until it is cut out again.\nconst HOST = 'isomerHostElement';\ninterface HostNode {\n type: typeof HOST;\n tag: HostTag;\n}\n\nconst isHost = (node: Nodes): boolean => (node.type as string) === HOST;\nconst hostTag = (node: Nodes): HostTag => (node as unknown as HostNode).tag;\n\nconst element = ({ name, attributes }: HostTag): AuthoredMarkdownSegment => ({\n type: 'element',\n name,\n attributes,\n});\n\nconst markdown = (source: string): AuthoredMarkdownSegment[] =>\n source.trim() === ''\n ? []\n : [{ type: 'markdown', content: md.authored(source), source }];\n\n// A sentinel in a text node becomes a host node between the text around it.\n// In any other string (code, alt, url, title, HTML) the tag text goes back. A\n// footnote prints at the end of its segment, away from where it is cited, so\n// a tag inside one is literal too.\nconst resolve = (\n node: Nodes,\n tags: readonly HostTag[],\n literal: boolean\n): Nodes[] => {\n if (node.type === 'text' && !literal) {\n const parts: Nodes[] = [];\n let cursor = 0;\n for (const match of node.value.matchAll(SENTINEL_RE)) {\n if (match.index > cursor) {\n parts.push({\n type: 'text',\n value: node.value.slice(cursor, match.index),\n });\n }\n parts.push({\n type: HOST,\n tag: tags[Number(match[1])]!,\n } as unknown as Nodes);\n cursor = match.index + match[0].length;\n }\n if (parts.length === 0) {\n return [node];\n }\n if (cursor < node.value.length) {\n parts.push({ type: 'text', value: node.value.slice(cursor) });\n }\n return parts;\n }\n const restored = { ...node } as Record<string, unknown>;\n for (const [key, value] of Object.entries(restored)) {\n if (typeof value === 'string') {\n restored[key] = value.replace(\n SENTINEL_ANYWHERE_RE,\n (_, index: string) => tags[Number(index)]!.raw\n );\n }\n }\n if ('children' in node) {\n restored.children = node.children.flatMap((child) =>\n resolve(child, tags, literal || node.type === 'footnoteDefinition')\n );\n }\n return [restored as unknown as Nodes];\n};\n\n// Depth-first, in document order.\nconst walk = (node: Nodes, visit: (node: Nodes) => void): void => {\n visit(node);\n if ('children' in node) {\n node.children.forEach((child) => walk(child, visit));\n }\n};\n\nconst PHRASING_PARENTS = new Set([\n 'delete',\n 'emphasis',\n 'heading',\n 'link',\n 'linkReference',\n 'paragraph',\n 'strong',\n 'tableCell',\n]);\n\n// A wrapper the tag leaves empty would print its markers alone (`****` is a\n// thematic break). Containers keep their place: an empty list item keeps the\n// numbering of the items after it.\nconst DROPPED_WHEN_EMPTY = new Set([\n 'delete',\n 'emphasis',\n 'heading',\n 'link',\n 'linkReference',\n 'paragraph',\n 'strong',\n]);\n\n// Text either side of a removed tag joins, with one space if either side\n// had one. The run's edges are trimmed, and a hard break left at an edge is\n// dropped as `md.paragraph` drops it, since it would print as a bare `\\\\`.\nconst tidyPhrasing = (children: Nodes[]): Nodes[] => {\n const joined: Nodes[] = [];\n for (const child of children) {\n const previous = joined[joined.length - 1];\n if (previous?.type === 'text' && child.type === 'text') {\n const left = previous.value.replace(/\\s+$/, '');\n const right = child.value.replace(/^\\s+/, '');\n const spaced = left !== previous.value || right !== child.value;\n joined[joined.length - 1] = {\n type: 'text',\n value: left + (spaced ? ' ' : '') + right,\n };\n } else {\n joined.push(child);\n }\n }\n const isEdge = (node: Nodes | undefined): boolean =>\n node?.type === 'break' ||\n (node?.type === 'text' && node.value.trim() === '');\n while (isEdge(joined[0])) {\n joined.shift();\n }\n while (isEdge(joined[joined.length - 1])) {\n joined.pop();\n }\n const first = joined[0];\n if (first?.type === 'text') {\n joined[0] = { ...first, value: first.value.trimStart() };\n }\n const last = joined[joined.length - 1];\n if (last?.type === 'text') {\n joined[joined.length - 1] = { ...last, value: last.value.trimEnd() };\n }\n return joined;\n};\n\n// `node` without its host nodes, which are appended to `found` in document\n// order; `[]` when nothing is left of it. Only a node a tag was removed\n// from is tidied, so phrasing elsewhere in the block stays as written.\nconst strip = (node: Nodes, found: HostTag[]): Nodes[] => {\n if (isHost(node)) {\n found.push(hostTag(node));\n return [];\n }\n if (!('children' in node)) {\n return [node];\n }\n const before = found.length;\n const stripped = node.children.flatMap((child) => strip(child, found));\n if (found.length === before) {\n return [node];\n }\n const children = PHRASING_PARENTS.has(node.type)\n ? tidyPhrasing(stripped)\n : stripped;\n return children.length === 0 && DROPPED_WHEN_EMPTY.has(node.type)\n ? []\n : [{ ...node, children } as Nodes];\n};\n\n// The first definition of each identifier, anywhere in the tree, as the\n// parser resolved references.\nconst firstDefinitions = (\n blocks: readonly Nodes[]\n): ReadonlyMap<string, Definition> => {\n const definitions = new Map<string, Definition>();\n for (const block of blocks) {\n walk(block, (node) => {\n if (node.type === 'definition' && !definitions.has(node.identifier)) {\n definitions.set(node.identifier, node);\n }\n });\n }\n return definitions;\n};\n\n// Each segment is a document of its own, so a definition another segment\n// holds is copied ahead of the run that references it.\nconst printRun = (\n run: readonly Nodes[],\n definitions: ReadonlyMap<string, Definition>\n): string => {\n const present = new Set<Nodes>();\n const needed = new Map<string, Definition>();\n for (const block of run) {\n walk(block, (node) => {\n present.add(node);\n if (node.type === 'linkReference' || node.type === 'imageReference') {\n const definition = definitions.get(node.identifier);\n if (definition) {\n needed.set(node.identifier, definition);\n }\n }\n });\n }\n const carried = [...needed.values()].filter((node) => !present.has(node));\n return printParsed([...carried, ...run]);\n};\n\nconst splitBlocks = (\n blocks: readonly Nodes[],\n tags: readonly HostTag[]\n): AuthoredMarkdownSegment[] => {\n const resolved = blocks.flatMap((block) => resolve(block, tags, false));\n const definitions = firstDefinitions(resolved);\n const segments: AuthoredMarkdownSegment[] = [];\n let run: Nodes[] = [];\n const flush = (): void => {\n if (run.length > 0) {\n segments.push(...markdown(printRun(run, definitions)));\n }\n run = [];\n };\n // `block` without its tags joins the run; each tag ends the run after it.\n const push = (block: Nodes): void => {\n const found: HostTag[] = [];\n run.push(...strip(block, found));\n for (const tag of found) {\n flush();\n segments.push(element(tag));\n }\n };\n for (const block of resolved) {\n if (block.type === 'definition') {\n // Prints nothing where it stands; it is copied where it is referenced.\n continue;\n }\n if (block.type !== 'paragraph' || !block.children.some(isHost)) {\n push(block);\n continue;\n }\n // A tag directly in a top-level paragraph splits it in place.\n let piece: Nodes[] = [];\n const pushPiece = (): void => {\n const children = tidyPhrasing(piece);\n if (children.length > 0) {\n push({ ...block, children } as Nodes);\n }\n piece = [];\n };\n for (const child of block.children) {\n if (isHost(child)) {\n pushPiece();\n flush();\n segments.push(element(hostTag(child)));\n } else {\n piece.push(child);\n }\n }\n pushPiece();\n }\n flush();\n return segments;\n};\n\n// Past the parse budget there is no tree to consult, so the source is cut at\n// each tag and every piece degrades to inert text, as `md.authored` degrades.\nconst cutLinearly = (\n source: string,\n tags: readonly HostTag[]\n): AuthoredMarkdownSegment[] => {\n const segments: AuthoredMarkdownSegment[] = [];\n const push = (piece: string): void => {\n const text = piece.trim();\n if (text !== '') {\n segments.push({\n type: 'markdown',\n content: verbatim(inert(text), text),\n source: text,\n });\n }\n };\n let cursor = 0;\n for (const tag of tags) {\n push(source.slice(cursor, tag.index));\n segments.push(element(tag));\n cursor = tag.index + tag.raw.length;\n }\n push(source.slice(cursor));\n return segments;\n};\n\n/**\n * Splits authored Markdown at the host's own elements, such as\n * `<render_attachment id=\"…\" />`, so the host can replace each with content\n * of its own without cutting the raw string. The source is parsed once, so a\n * tag in code, a link destination or title, an image's alt text, or raw HTML\n * stays text, and a list, table, quote, or emphasis around a tag stays whole.\n * Each `markdown` segment is sanitized as `md.authored` sanitizes; past the\n * parse budget the source is cut at each tag into inert pieces.\n *\n * @example\n * splitAuthoredMarkdown(message, { elements: ['render_attachment'] })\n */\nexport const splitAuthoredMarkdown = (\n source: string,\n { elements }: SplitAuthoredMarkdownOptions\n): AuthoredMarkdownSegment[] => {\n const cleaned = withoutReserved(source);\n const tags = findHostTags(cleaned, elements);\n if (tags.length === 0) {\n return markdown(source);\n }\n // The budget applies to the source as written: a long attribute value\n // shrinks to a sentinel, but comes back in full wherever it is literal.\n const blocks = exceedsParseBudget(cleaned)\n ? null\n : (parseGfmBlocks(substitute(cleaned, tags)) as\n readonly RootContent[] | null);\n return blocks && !exceedsDepth(blocks)\n ? splitBlocks(blocks, tags)\n : cutLinearly(cleaned, tags);\n};\n"]}
|
|
@@ -3,6 +3,7 @@ import { type SurfaceName } from '../composition/body_node_base.js';
|
|
|
3
3
|
import type { ValidationError } from '../composition/validation_error.js';
|
|
4
4
|
import type { MarkdownContent } from '../define/markdown_content.js';
|
|
5
5
|
import { type AnyPrimitiveDefinition, type DefaultPackTypes, type PackTypes, type PrimitiveNode, type PrimitiveStyleCollectionContext, type ReactContextArg, type SurfaceMap } from '../define/primitive_module.js';
|
|
6
|
+
import type { SlackLinkOptions } from './slack/format.js';
|
|
6
7
|
/**
|
|
7
8
|
* Renders a node on any surface by looking its `type` up in one flattened
|
|
8
9
|
* inventory.
|
|
@@ -39,9 +40,10 @@ export interface PrimitiveDispatcher<TNode extends PrimitiveNode, T extends Pack
|
|
|
39
40
|
* Empty when the node is hidden from `slack`, `sanitize` drops it, or its
|
|
40
41
|
* renderer returns nothing. A node with no `slack` renderer degrades through
|
|
41
42
|
* its markdown; one `isSlackAssetType` names becomes an `image` block when
|
|
42
|
-
* `collector` can allocate.
|
|
43
|
+
* `collector` can allocate. `options.baseUrl` reaches the renderer's env and
|
|
44
|
+
* every child it renders through `scope`.
|
|
43
45
|
*/
|
|
44
|
-
renderSlack(node: TNode, collector?: T['slackCollector']): readonly T['slackBlock'][];
|
|
46
|
+
renderSlack(node: TNode, collector?: T['slackCollector'], options?: SlackLinkOptions): readonly T['slackBlock'][];
|
|
45
47
|
/** `0` when the node is hidden from `snapshot` or its primitive declares no `metrics.snapshotHeight`. */
|
|
46
48
|
estimateSnapshotHeight(node: TNode): number;
|
|
47
49
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitive_dispatch.d.ts","sourceRoot":"","sources":["../../src/render/primitive_dispatch.ts"],"names":[],"mappings":"AAOA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,+BAA+B,EACpC,KAAK,eAAe,EAGpB,KAAK,UAAU,EAChB,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"primitive_dispatch.d.ts","sourceRoot":"","sources":["../../src/render/primitive_dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,7 +57,30 @@ export const createPrimitiveDispatcher = (definitions, options = {}) => {
|
|
|
57
57
|
// Assigned after helpers that close over this binding.
|
|
58
58
|
// eslint-disable-next-line prefer-const
|
|
59
59
|
let self;
|
|
60
|
-
const
|
|
60
|
+
const scopeFor = (surface, extras) => {
|
|
61
|
+
const parent = self;
|
|
62
|
+
if (surface === 'slack') {
|
|
63
|
+
const { baseUrl } = extras;
|
|
64
|
+
return baseUrl === undefined
|
|
65
|
+
? parent
|
|
66
|
+
: {
|
|
67
|
+
...parent,
|
|
68
|
+
renderOn: (target, node, targetExtras) => parent.renderOn(target, node, target === 'slack' ? { baseUrl, ...targetExtras } : targetExtras),
|
|
69
|
+
renderSlack: (node, collector) => self.renderSlack(node, collector, { baseUrl }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (surface !== 'snapshot') {
|
|
73
|
+
return parent;
|
|
74
|
+
}
|
|
75
|
+
const { theme } = extras;
|
|
76
|
+
return {
|
|
77
|
+
...parent,
|
|
78
|
+
renderReact: (node, ...context) => parent.renderOn('snapshot', node, {
|
|
79
|
+
context: context[0] ?? {},
|
|
80
|
+
theme,
|
|
81
|
+
}),
|
|
82
|
+
};
|
|
83
|
+
};
|
|
61
84
|
const renderOn = (surface, node, extras) => {
|
|
62
85
|
if (!isVisibleOnSurface(node, surface)) {
|
|
63
86
|
return undefined;
|
|
@@ -71,7 +94,10 @@ export const createPrimitiveDispatcher = (definitions, options = {}) => {
|
|
|
71
94
|
// `renderOn` for a node its sanitizer has already run on.
|
|
72
95
|
const renderSanitized = (surface, definition, safeNode, extras) => {
|
|
73
96
|
const renderer = definition.renderers[RENDERER_FOR_SURFACE[surface]];
|
|
74
|
-
return renderer?.(safeNode, {
|
|
97
|
+
return renderer?.(safeNode, {
|
|
98
|
+
...extras,
|
|
99
|
+
scope: scopeFor(surface, extras),
|
|
100
|
+
});
|
|
75
101
|
};
|
|
76
102
|
const renderMarkdownContent = (node) => renderOn('markdown', node, {}) ?? [];
|
|
77
103
|
const renderMarkdown = (node) => serializeMarkdown(renderMarkdownContent(node));
|
|
@@ -101,7 +127,7 @@ export const createPrimitiveDispatcher = (definitions, options = {}) => {
|
|
|
101
127
|
renderText: (node) => renderOn('text', node, {}) ?? '',
|
|
102
128
|
renderMarkdown,
|
|
103
129
|
renderMarkdownContent,
|
|
104
|
-
renderSlack: (node, collector) => {
|
|
130
|
+
renderSlack: (node, collector, options = {}) => {
|
|
105
131
|
if (!isVisibleOnSurface(node, 'slack')) {
|
|
106
132
|
return [];
|
|
107
133
|
}
|
|
@@ -129,15 +155,19 @@ export const createPrimitiveDispatcher = (definitions, options = {}) => {
|
|
|
129
155
|
// Degrading here rather than in the envelope is what reaches nested
|
|
130
156
|
// children: a container's `slack` renderer recurses through this
|
|
131
157
|
// method, and the envelope only ever sees the container's own output.
|
|
132
|
-
return asSlackPayload(markdownContentToSlackBlocks(renderMarkdownContent(node)));
|
|
158
|
+
return asSlackPayload(markdownContentToSlackBlocks(renderMarkdownContent(node), options));
|
|
133
159
|
}
|
|
134
160
|
const safeNode = sanitizeNode(definition, node);
|
|
135
161
|
if (safeNode === null) {
|
|
136
162
|
return [];
|
|
137
163
|
}
|
|
138
|
-
const
|
|
164
|
+
const extras = {
|
|
139
165
|
...(collector === undefined ? {} : { collector }),
|
|
140
|
-
|
|
166
|
+
...(options.baseUrl === undefined ? {} : { baseUrl: options.baseUrl }),
|
|
167
|
+
};
|
|
168
|
+
const rendered = slackRenderer(safeNode, {
|
|
169
|
+
...extras,
|
|
170
|
+
scope: scopeFor('slack', extras),
|
|
141
171
|
});
|
|
142
172
|
return isReadonlyArray(rendered) ? rendered : [rendered];
|
|
143
173
|
},
|
|
@@ -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"]}
|
|
@@ -27,7 +27,7 @@ export interface CompositionWrapperOptions {
|
|
|
27
27
|
framed?: boolean;
|
|
28
28
|
/** Adds the `fluid` class. */
|
|
29
29
|
fluid?: boolean;
|
|
30
|
-
/** Sets `data-theme
|
|
30
|
+
/** Sets `data-theme` and `color-scheme`, which `light-dark()` resolves against; defaults to the composition's `theme`, and `auto` sets nothing so the page's scheme applies. */
|
|
31
31
|
theme?: RenderTheme;
|
|
32
32
|
/** Used only when the composition has neither `meta.ariaLabel` nor a `title`. Defaults to `'View'`. */
|
|
33
33
|
defaultAriaLabel?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/render/react/content.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE1E,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB,CACrC,KAAK,SAAS,aAAa,EAC3B,QAAQ,GAAG,sBAAsB;IAEjC,4GAA4G;IAC5G,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACzD;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,KAAK,SAAS,aAAa,EAC3B,QAAQ,GAAG,sBAAsB,EAEjC,aAAa,WAAW,CAAC,KAAK,CAAC,EAC/B,YAAY,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,EACnD,SAAS,QAAQ,EACjB,cAAoB,mBAAwB,KAC3C,SAwBA,CAAC;AAkBJ,kDAAkD;AAClD,MAAM,WAAW,yBAAyB;IACxC,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/render/react/content.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE1E,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB,CACrC,KAAK,SAAS,aAAa,EAC3B,QAAQ,GAAG,sBAAsB;IAEjC,4GAA4G;IAC5G,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACzD;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,KAAK,SAAS,aAAa,EAC3B,QAAQ,GAAG,sBAAsB,EAEjC,aAAa,WAAW,CAAC,KAAK,CAAC,EAC/B,YAAY,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,EACnD,SAAS,QAAQ,EACjB,cAAoB,mBAAwB,KAC3C,SAwBA,CAAC;AAkBJ,kDAAkD;AAClD,MAAM,WAAW,yBAAyB;IACxC,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gLAAgL;IAChL,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,uGAAuG;IACvG,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,SAAS,aAAa,EAChE,SAAS,SAAS,EAClB,aAAa,WAAW,CAAC,KAAK,CAAC,EAC/B,8CAKG,yBAA8B,KAChC,YAeA,CAAC"}
|
|
@@ -34,6 +34,8 @@ export const wrapCompositionContent = (content, composition, { framed = true, fl
|
|
|
34
34
|
.join(' '),
|
|
35
35
|
role: 'group',
|
|
36
36
|
'aria-label': composition.meta?.ariaLabel ?? composition.title ?? defaultAriaLabel,
|
|
37
|
-
...(theme === 'auto'
|
|
37
|
+
...(theme === 'auto'
|
|
38
|
+
? {}
|
|
39
|
+
: { 'data-theme': theme, style: { colorScheme: theme } }),
|
|
38
40
|
}, content);
|
|
39
41
|
//# sourceMappingURL=content.js.map
|