@elastic/isomer-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +13 -2
  2. package/dist/author/authored_fields.d.ts +61 -11
  3. package/dist/author/authored_fields.d.ts.map +1 -1
  4. package/dist/author/authored_fields.js +73 -29
  5. package/dist/author/authored_fields.js.map +1 -1
  6. package/dist/author/authoring_input.d.ts +7 -0
  7. package/dist/author/authoring_input.d.ts.map +1 -0
  8. package/dist/author/authoring_input.js +60 -0
  9. package/dist/author/authoring_input.js.map +1 -0
  10. package/dist/author/authoring_model.d.ts +27 -0
  11. package/dist/author/authoring_model.d.ts.map +1 -0
  12. package/dist/author/authoring_model.js +98 -0
  13. package/dist/author/authoring_model.js.map +1 -0
  14. package/dist/author/declarations.d.ts +13 -0
  15. package/dist/author/declarations.d.ts.map +1 -0
  16. package/dist/author/declarations.js +277 -0
  17. package/dist/author/declarations.js.map +1 -0
  18. package/dist/author/index.d.ts +3 -1
  19. package/dist/author/index.d.ts.map +1 -1
  20. package/dist/author/index.js +3 -1
  21. package/dist/author/index.js.map +1 -1
  22. package/dist/author/jsx_shim.d.ts +6 -5
  23. package/dist/author/jsx_shim.d.ts.map +1 -1
  24. package/dist/author/jsx_shim.js +28 -111
  25. package/dist/author/jsx_shim.js.map +1 -1
  26. package/dist/author/schema_to_typescript.d.ts +37 -0
  27. package/dist/author/schema_to_typescript.d.ts.map +1 -0
  28. package/dist/author/schema_to_typescript.js +286 -0
  29. package/dist/author/schema_to_typescript.js.map +1 -0
  30. package/dist/cjs/author/authored_fields.js +77 -33
  31. package/dist/cjs/author/authored_fields.js.map +1 -1
  32. package/dist/cjs/author/authoring_input.js +64 -0
  33. package/dist/cjs/author/authoring_input.js.map +1 -0
  34. package/dist/cjs/author/authoring_model.js +104 -0
  35. package/dist/cjs/author/authoring_model.js.map +1 -0
  36. package/dist/cjs/author/declarations.js +281 -0
  37. package/dist/cjs/author/declarations.js.map +1 -0
  38. package/dist/cjs/author/index.js +6 -1
  39. package/dist/cjs/author/index.js.map +1 -1
  40. package/dist/cjs/author/jsx_shim.js +31 -114
  41. package/dist/cjs/author/jsx_shim.js.map +1 -1
  42. package/dist/cjs/author/schema_to_typescript.js +295 -0
  43. package/dist/cjs/author/schema_to_typescript.js.map +1 -0
  44. package/dist/cjs/composition/body_node_base.js +11 -4
  45. package/dist/cjs/composition/body_node_base.js.map +1 -1
  46. package/dist/cjs/composition/error.js +1 -0
  47. package/dist/cjs/composition/error.js.map +1 -1
  48. package/dist/cjs/composition/index.js +2 -1
  49. package/dist/cjs/composition/index.js.map +1 -1
  50. package/dist/cjs/define/frame.js +2 -3
  51. package/dist/cjs/define/frame.js.map +1 -1
  52. package/dist/cjs/define/index.js +7 -1
  53. package/dist/cjs/define/index.js.map +1 -1
  54. package/dist/cjs/define/primitive_example.js +26 -0
  55. package/dist/cjs/define/primitive_example.js.map +1 -0
  56. package/dist/cjs/define/primitive_icon.js +17 -0
  57. package/dist/cjs/define/primitive_icon.js.map +1 -0
  58. package/dist/cjs/define/primitive_module.js +14 -3
  59. package/dist/cjs/define/primitive_module.js.map +1 -1
  60. package/dist/cjs/define/slack_assets.js.map +1 -1
  61. package/dist/cjs/entries/index.js +7 -2
  62. package/dist/cjs/entries/index.js.map +1 -1
  63. package/dist/cjs/entries/slack.js +1 -2
  64. package/dist/cjs/entries/slack.js.map +1 -1
  65. package/dist/cjs/pack/capabilities.js +17 -11
  66. package/dist/cjs/pack/capabilities.js.map +1 -1
  67. package/dist/cjs/pack/compose.js +4 -1
  68. package/dist/cjs/pack/compose.js.map +1 -1
  69. package/dist/cjs/pack/index.js.map +1 -1
  70. package/dist/cjs/pack/primitive_pack.js +14 -2
  71. package/dist/cjs/pack/primitive_pack.js.map +1 -1
  72. package/dist/cjs/render/anchors.js +1 -1
  73. package/dist/cjs/render/anchors.js.map +1 -1
  74. package/dist/cjs/render/html/envelope.js.map +1 -1
  75. package/dist/cjs/render/layout_check.js.map +1 -1
  76. package/dist/cjs/render/markdown/builder.js +14 -8
  77. package/dist/cjs/render/markdown/builder.js.map +1 -1
  78. package/dist/cjs/render/markdown/format.js +30 -12
  79. package/dist/cjs/render/markdown/format.js.map +1 -1
  80. package/dist/cjs/render/primitive_dispatch.js +11 -25
  81. package/dist/cjs/render/primitive_dispatch.js.map +1 -1
  82. package/dist/cjs/render/slack/format.js +1 -601
  83. package/dist/cjs/render/slack/format.js.map +1 -1
  84. package/dist/cjs/render/slack/index.js +1 -2
  85. package/dist/cjs/render/slack/index.js.map +1 -1
  86. package/dist/cjs/render/slack/markdown_content.js +166 -115
  87. package/dist/cjs/render/slack/markdown_content.js.map +1 -1
  88. package/dist/cjs/testing/conformance.js +40 -24
  89. package/dist/cjs/testing/conformance.js.map +1 -1
  90. package/dist/cjs/testing/icon.js +248 -0
  91. package/dist/cjs/testing/icon.js.map +1 -0
  92. package/dist/cjs/testing/index.js +3 -1
  93. package/dist/cjs/testing/index.js.map +1 -1
  94. package/dist/cjs/testing/registration.js +5 -3
  95. package/dist/cjs/testing/registration.js.map +1 -1
  96. package/dist/cjs/validate/authoring_schema.js +17 -1
  97. package/dist/cjs/validate/authoring_schema.js.map +1 -1
  98. package/dist/cjs/validate/index.js +2 -1
  99. package/dist/cjs/validate/index.js.map +1 -1
  100. package/dist/cjs/validate/validation.js +2 -45
  101. package/dist/cjs/validate/validation.js.map +1 -1
  102. package/dist/composition/body_node_base.d.ts +7 -6
  103. package/dist/composition/body_node_base.d.ts.map +1 -1
  104. package/dist/composition/body_node_base.js +10 -3
  105. package/dist/composition/body_node_base.js.map +1 -1
  106. package/dist/composition/error.d.ts +1 -0
  107. package/dist/composition/error.d.ts.map +1 -1
  108. package/dist/composition/error.js +1 -0
  109. package/dist/composition/error.js.map +1 -1
  110. package/dist/composition/index.d.ts +1 -1
  111. package/dist/composition/index.d.ts.map +1 -1
  112. package/dist/composition/index.js +1 -1
  113. package/dist/composition/index.js.map +1 -1
  114. package/dist/define/frame.d.ts +9 -20
  115. package/dist/define/frame.d.ts.map +1 -1
  116. package/dist/define/frame.js +2 -3
  117. package/dist/define/frame.js.map +1 -1
  118. package/dist/define/index.d.ts +3 -1
  119. package/dist/define/index.d.ts.map +1 -1
  120. package/dist/define/index.js +3 -1
  121. package/dist/define/index.js.map +1 -1
  122. package/dist/define/primitive_example.d.ts +30 -0
  123. package/dist/define/primitive_example.d.ts.map +1 -0
  124. package/dist/define/primitive_example.js +21 -0
  125. package/dist/define/primitive_example.js.map +1 -0
  126. package/dist/define/primitive_icon.d.ts +11 -0
  127. package/dist/define/primitive_icon.d.ts.map +1 -0
  128. package/dist/define/primitive_icon.js +14 -0
  129. package/dist/define/primitive_icon.js.map +1 -0
  130. package/dist/define/primitive_module.d.ts +38 -24
  131. package/dist/define/primitive_module.d.ts.map +1 -1
  132. package/dist/define/primitive_module.js +14 -3
  133. package/dist/define/primitive_module.js.map +1 -1
  134. package/dist/define/slack_assets.d.ts +1 -1
  135. package/dist/define/slack_assets.d.ts.map +1 -1
  136. package/dist/define/slack_assets.js.map +1 -1
  137. package/dist/entries/index.d.ts +3 -3
  138. package/dist/entries/index.d.ts.map +1 -1
  139. package/dist/entries/index.js +2 -2
  140. package/dist/entries/index.js.map +1 -1
  141. package/dist/entries/slack.d.ts +1 -1
  142. package/dist/entries/slack.d.ts.map +1 -1
  143. package/dist/entries/slack.js +1 -1
  144. package/dist/entries/slack.js.map +1 -1
  145. package/dist/pack/capabilities.d.ts +24 -10
  146. package/dist/pack/capabilities.d.ts.map +1 -1
  147. package/dist/pack/capabilities.js +17 -11
  148. package/dist/pack/capabilities.js.map +1 -1
  149. package/dist/pack/compose.d.ts +4 -1
  150. package/dist/pack/compose.d.ts.map +1 -1
  151. package/dist/pack/compose.js +4 -1
  152. package/dist/pack/compose.js.map +1 -1
  153. package/dist/pack/index.d.ts +1 -1
  154. package/dist/pack/index.d.ts.map +1 -1
  155. package/dist/pack/index.js +1 -1
  156. package/dist/pack/index.js.map +1 -1
  157. package/dist/pack/primitive_pack.d.ts +11 -2
  158. package/dist/pack/primitive_pack.d.ts.map +1 -1
  159. package/dist/pack/primitive_pack.js +12 -1
  160. package/dist/pack/primitive_pack.js.map +1 -1
  161. package/dist/render/anchors.d.ts +2 -2
  162. package/dist/render/anchors.d.ts.map +1 -1
  163. package/dist/render/anchors.js +1 -1
  164. package/dist/render/anchors.js.map +1 -1
  165. package/dist/render/html/envelope.d.ts +3 -3
  166. package/dist/render/html/envelope.js.map +1 -1
  167. package/dist/render/layout_check.d.ts +1 -1
  168. package/dist/render/layout_check.d.ts.map +1 -1
  169. package/dist/render/layout_check.js.map +1 -1
  170. package/dist/render/markdown/builder.d.ts +2 -4
  171. package/dist/render/markdown/builder.d.ts.map +1 -1
  172. package/dist/render/markdown/builder.js +14 -7
  173. package/dist/render/markdown/builder.js.map +1 -1
  174. package/dist/render/markdown/format.d.ts +7 -0
  175. package/dist/render/markdown/format.d.ts.map +1 -1
  176. package/dist/render/markdown/format.js +27 -11
  177. package/dist/render/markdown/format.js.map +1 -1
  178. package/dist/render/primitive_dispatch.d.ts +6 -6
  179. package/dist/render/primitive_dispatch.d.ts.map +1 -1
  180. package/dist/render/primitive_dispatch.js +12 -26
  181. package/dist/render/primitive_dispatch.js.map +1 -1
  182. package/dist/render/slack/format.d.ts +0 -25
  183. package/dist/render/slack/format.d.ts.map +1 -1
  184. package/dist/render/slack/format.js +1 -599
  185. package/dist/render/slack/format.js.map +1 -1
  186. package/dist/render/slack/index.d.ts +1 -1
  187. package/dist/render/slack/index.d.ts.map +1 -1
  188. package/dist/render/slack/index.js +1 -1
  189. package/dist/render/slack/index.js.map +1 -1
  190. package/dist/render/slack/markdown_content.d.ts +10 -4
  191. package/dist/render/slack/markdown_content.d.ts.map +1 -1
  192. package/dist/render/slack/markdown_content.js +163 -113
  193. package/dist/render/slack/markdown_content.js.map +1 -1
  194. package/dist/testing/conformance.d.ts +19 -14
  195. package/dist/testing/conformance.d.ts.map +1 -1
  196. package/dist/testing/conformance.js +40 -24
  197. package/dist/testing/conformance.js.map +1 -1
  198. package/dist/testing/icon.d.ts +11 -0
  199. package/dist/testing/icon.d.ts.map +1 -0
  200. package/dist/testing/icon.js +244 -0
  201. package/dist/testing/icon.js.map +1 -0
  202. package/dist/testing/index.d.ts +2 -1
  203. package/dist/testing/index.d.ts.map +1 -1
  204. package/dist/testing/index.js +1 -0
  205. package/dist/testing/index.js.map +1 -1
  206. package/dist/testing/registration.d.ts +1 -1
  207. package/dist/testing/registration.d.ts.map +1 -1
  208. package/dist/testing/registration.js +6 -4
  209. package/dist/testing/registration.js.map +1 -1
  210. package/dist/validate/authoring_schema.d.ts +6 -0
  211. package/dist/validate/authoring_schema.d.ts.map +1 -1
  212. package/dist/validate/authoring_schema.js +15 -0
  213. package/dist/validate/authoring_schema.js.map +1 -1
  214. package/dist/validate/index.d.ts +1 -1
  215. package/dist/validate/index.d.ts.map +1 -1
  216. package/dist/validate/index.js +1 -1
  217. package/dist/validate/index.js.map +1 -1
  218. package/dist/validate/validation.d.ts +1 -11
  219. package/dist/validate/validation.d.ts.map +1 -1
  220. package/dist/validate/validation.js +3 -46
  221. package/dist/validate/validation.js.map +1 -1
  222. package/package.json +3 -2
@@ -15,7 +15,7 @@
15
15
  //
16
16
  // See https://api.slack.com/reference/surfaces/formatting
17
17
  import { sanitizeNavigationHref } from '../../validate/url.js';
18
- import { SLACK_LIMITS, } from './blocks.js';
18
+ import { SLACK_LIMITS } from './blocks.js';
19
19
  const MRKDWN_ESCAPES = {
20
20
  '&': '&',
21
21
  '<': '&lt;',
@@ -206,602 +206,4 @@ export const cutSlackValue = (value, max) => {
206
206
  * text is `plain_text`, so no markdown survives — do not pre-format it.
207
207
  */
208
208
  export const formatHeaderText = (value) => clampSlackText(value.replace(/\s+/g, ' ').trim(), SLACK_LIMITS.headerTextChars);
209
- const ASCII_PUNCTUATION_RE = /[!-/:-@[-`{-~]/;
210
- const NUMERIC_REFERENCE_RE = /&#(?:[xX]([0-9a-fA-F]{1,6})|(\d{1,7}));/y;
211
- // micromark's rule: controls other than tab and line breaks, surrogates,
212
- // noncharacters, and out-of-range values become U+FFFD.
213
- const decodeCodePoint = (codePoint) => codePoint < 9 ||
214
- codePoint === 11 ||
215
- (codePoint > 13 && codePoint < 32) ||
216
- (codePoint > 126 && codePoint < 160) ||
217
- (codePoint > 55_295 && codePoint < 57_344) ||
218
- (codePoint > 64_975 && codePoint < 65_008) ||
219
- codePoint % 65_536 >= 65_534 ||
220
- codePoint > 1_114_111
221
- ? '�'
222
- : String.fromCodePoint(codePoint);
223
- const backtickRunEnd = (text, start) => {
224
- let end = start;
225
- while (text[end] === '`') {
226
- end += 1;
227
- }
228
- return end;
229
- };
230
- // Every maximal backtick run's start, keyed by the run's length, in order.
231
- const backtickRuns = (text) => {
232
- const runs = new Map();
233
- let start = text.indexOf('`');
234
- while (start !== -1) {
235
- const end = backtickRunEnd(text, start);
236
- const starts = runs.get(end - start);
237
- if (starts) {
238
- starts.push(start);
239
- }
240
- else {
241
- runs.set(end - start, [start]);
242
- }
243
- start = text.indexOf('`', end);
244
- }
245
- return runs;
246
- };
247
- const firstAtOrAfter = (sorted, from) => {
248
- let low = 0;
249
- let high = sorted.length;
250
- while (low < high) {
251
- const middle = Math.floor((low + high) / 2);
252
- if (sorted[middle] < from) {
253
- low = middle + 1;
254
- }
255
- else {
256
- high = middle;
257
- }
258
- }
259
- return sorted[low];
260
- };
261
- // Indexes `text`'s backtick runs once, on the first query.
262
- const codeSpanCloser = (text) => {
263
- let runs;
264
- return (end, length) => {
265
- runs ??= backtickRuns(text);
266
- return firstAtOrAfter(runs.get(length) ?? [], end);
267
- };
268
- };
269
- // CommonMark strips one space from each side of a span that is not all spaces.
270
- const codeSpanText = (content) => /[^ ]/.test(content) && content.startsWith(' ') && content.endsWith(' ')
271
- ? content.slice(1, -1)
272
- : content;
273
- // Resolves the backslash escapes and numeric character references a GFM
274
- // serializer writes, which Slack would otherwise show literally, and leaves
275
- // code spans as written.
276
- const unescapeGfm = (text) => {
277
- const closer = codeSpanCloser(text);
278
- let out = '';
279
- let index = 0;
280
- while (index < text.length) {
281
- const char = text[index];
282
- const next = text[index + 1];
283
- if (char === '\\' &&
284
- next !== undefined &&
285
- ASCII_PUNCTUATION_RE.test(next)) {
286
- out += next;
287
- index += 2;
288
- continue;
289
- }
290
- if (char === '`') {
291
- const fenceEnd = backtickRunEnd(text, index);
292
- const close = closer(fenceEnd, fenceEnd - index);
293
- const end = close === undefined ? fenceEnd : close + fenceEnd - index;
294
- out += text.slice(index, end);
295
- index = end;
296
- continue;
297
- }
298
- if (char === '&') {
299
- NUMERIC_REFERENCE_RE.lastIndex = index;
300
- const reference = NUMERIC_REFERENCE_RE.exec(text);
301
- if (reference) {
302
- const [match, hex, decimal] = reference;
303
- out += decodeCodePoint(hex === undefined ? Number(decimal) : parseInt(hex, 16));
304
- index += match.length;
305
- continue;
306
- }
307
- }
308
- out += char;
309
- index += 1;
310
- }
311
- return out;
312
- };
313
- // A link destination may be wrapped in angle brackets (`[x](<dest>)`).
314
- const linkDestination = (dest) => unescapeGfm(dest.replace(/^<([^<>]*)>$/, '$1'));
315
- // The code span whose opener starts at `open`, or `undefined`.
316
- const codeSpanAt = (line, open, closer) => {
317
- const fenceEnd = backtickRunEnd(line, open);
318
- const close = closer(fenceEnd, fenceEnd - open);
319
- return close === undefined
320
- ? undefined
321
- : {
322
- index: open,
323
- end: close + fenceEnd - open,
324
- segment: {
325
- kind: 'code',
326
- text: codeSpanText(line.slice(fenceEnd, close)),
327
- },
328
- };
329
- };
330
- const regexFinder = (pattern, toSegment) => (line, from) => {
331
- pattern.lastIndex = from;
332
- const match = pattern.exec(line);
333
- return (match && {
334
- index: match.index,
335
- end: match.index + match[0].length,
336
- segment: toSegment(match),
337
- });
338
- };
339
- const findCodeSpan = (line, from, closer) => {
340
- let open = line.indexOf('`', from);
341
- while (open !== -1) {
342
- const span = codeSpanAt(line, open, closer);
343
- if (span) {
344
- return span;
345
- }
346
- open = line.indexOf('`', backtickRunEnd(line, open));
347
- }
348
- return null;
349
- };
350
- const WHITESPACE_RE = /\s/u;
351
- const PUNCTUATION_RE = /[\p{P}\p{S}]/u;
352
- // The line's edges count as whitespace.
353
- const isSpace = (char) => char === undefined || WHITESPACE_RE.test(char);
354
- const isPunctuation = (char) => char !== undefined && PUNCTUATION_RE.test(char);
355
- // An odd run of backslashes escapes the character at `index`.
356
- const isEscaped = (line, index) => {
357
- let run = 0;
358
- while (line[index - 1 - run] === '\\') {
359
- run += 1;
360
- }
361
- return run % 2 === 1;
362
- };
363
- // GFM's flanking rules for a lone delimiter; `_` also cannot open or close
364
- // inside a word.
365
- const flanking = (line, index, delimiter) => {
366
- // Whole code points, so an astral symbol such as an emoji is classified as one.
367
- const trailing = line.charCodeAt(index - 1);
368
- const before = index === 0
369
- ? undefined
370
- : trailing >= 0xdc00 && trailing <= 0xdfff && index >= 2
371
- ? String.fromCodePoint(line.codePointAt(index - 2) ?? trailing)
372
- : line[index - 1];
373
- const next = line.codePointAt(index + 1);
374
- const after = next === undefined ? undefined : String.fromCodePoint(next);
375
- if (before === delimiter || after === delimiter) {
376
- return { opens: false, closes: false };
377
- }
378
- const left = !isSpace(after) &&
379
- (!isPunctuation(after) || isSpace(before) || isPunctuation(before));
380
- const right = !isSpace(before) &&
381
- (!isPunctuation(before) || isSpace(after) || isPunctuation(after));
382
- return delimiter === '*'
383
- ? { opens: left, closes: right }
384
- : {
385
- opens: left && (!right || isPunctuation(before)),
386
- closes: right && (!left || isPunctuation(after)),
387
- };
388
- };
389
- // The index past what starts at `index` when it is an escape or a code span,
390
- // whose characters are never delimiters, or past one character otherwise.
391
- const stepOver = (line, index, closer) => {
392
- if (line[index] === '\\') {
393
- return index + 2;
394
- }
395
- if (line[index] === '`') {
396
- return codeSpanAt(line, index, closer)?.end ?? backtickRunEnd(line, index);
397
- }
398
- return index + 1;
399
- };
400
- const LINK_DESTINATION_RE = /\((<[^<>\n]*>|(?:\\.|[^\s()\\]|\([^()\s]*\))+)\)/y;
401
- // A link, or an image, which degrades to a link to its source labelled with
402
- // its alt text. The label may hold escapes and code spans but no bare bracket.
403
- const findLink = (line, from, closer) => {
404
- let open = line.indexOf('[', from);
405
- while (open !== -1) {
406
- let index = open + 1;
407
- while (index < line.length && line[index] !== '[' && line[index] !== ']') {
408
- index = stepOver(line, index, closer);
409
- }
410
- if (line[index] === ']') {
411
- LINK_DESTINATION_RE.lastIndex = index + 1;
412
- const destination = LINK_DESTINATION_RE.exec(line);
413
- if (destination) {
414
- const bang = line[open - 1] === '!' && !isEscaped(line, open - 1);
415
- return {
416
- index: bang ? open - 1 : open,
417
- end: LINK_DESTINATION_RE.lastIndex,
418
- segment: {
419
- kind: 'link',
420
- text: line.slice(open + 1, index),
421
- url: destination[1] ?? '',
422
- },
423
- };
424
- }
425
- }
426
- open = line.indexOf('[', index);
427
- }
428
- return null;
429
- };
430
- // Strong between `**` pairs whose body holds no `*` outside escapes and code.
431
- const findBold = (line, from, closer) => {
432
- let open = line.indexOf('**', from);
433
- while (open !== -1) {
434
- let index = open + 2;
435
- while (index < line.length && line[index] !== '*') {
436
- index = stepOver(line, index, closer);
437
- }
438
- if (index > open + 2 && line.startsWith('**', index)) {
439
- return {
440
- index: open,
441
- end: index + 2,
442
- segment: { kind: 'bold', text: line.slice(open + 2, index) },
443
- };
444
- }
445
- open = line.indexOf('**', index > open + 2 ? index : open + 1);
446
- }
447
- return null;
448
- };
449
- // Emphasis between two lone `delimiter`s, in one forward pass: the first
450
- // closer pairs with the nearest opener before it, and a delimiter that can
451
- // do neither is text.
452
- const emphasisFinder = (delimiter) => (line, from, closer) => {
453
- let open = -1;
454
- let index = from;
455
- while (index < line.length) {
456
- if (line[index] === '\\' || line[index] === '`') {
457
- index = stepOver(line, index, closer);
458
- continue;
459
- }
460
- if (line[index] === delimiter && !isEscaped(line, index)) {
461
- const { opens, closes } = flanking(line, index, delimiter);
462
- if (open !== -1 && closes) {
463
- return {
464
- index: open,
465
- end: index + 1,
466
- segment: { kind: 'italic', text: line.slice(open + 1, index) },
467
- };
468
- }
469
- if (opens) {
470
- open = index;
471
- }
472
- }
473
- index += 1;
474
- }
475
- return null;
476
- };
477
- // In tie order. Each label, destination, or body stops at the first character
478
- // that cannot continue it, so one search from a position is linear.
479
- const INLINE_FINDERS = [
480
- // A CommonMark backslash escape: any ASCII punctuation character.
481
- regexFinder(/\\([!-/:-@[-`{-~])/g, ([, text = '']) => ({
482
- kind: 'text',
483
- text,
484
- })),
485
- findCodeSpan,
486
- findLink,
487
- findBold,
488
- emphasisFinder('_'),
489
- emphasisFinder('*'),
490
- ];
491
- // Tokenizes a single line of GFM into ordered inline segments. The earliest
492
- // match wins; on a tie, the order of `INLINE_FINDERS` does. An escaped
493
- // character is text and never a delimiter. Each finder's next match is reused
494
- // until the cursor passes it, so a line is not rescanned per segment.
495
- const tokenizeInline = (line) => {
496
- const segments = [];
497
- const closer = codeSpanCloser(line);
498
- const found = new Map();
499
- const nextMatch = (finder, cursor) => {
500
- const cached = found.get(finder);
501
- if (cached === null || (cached !== undefined && cached.index >= cursor)) {
502
- return cached;
503
- }
504
- const match = finder(line, cursor, closer);
505
- found.set(finder, match);
506
- return match;
507
- };
508
- let cursor = 0;
509
- while (cursor < line.length) {
510
- let first;
511
- for (const finder of INLINE_FINDERS) {
512
- const match = nextMatch(finder, cursor);
513
- if (match && (first === undefined || match.index < first.index)) {
514
- first = match;
515
- }
516
- }
517
- if (first === undefined) {
518
- segments.push({ kind: 'text', text: line.slice(cursor) });
519
- break;
520
- }
521
- if (first.index > cursor) {
522
- segments.push({ kind: 'text', text: line.slice(cursor, first.index) });
523
- }
524
- segments.push(first.segment);
525
- cursor = first.end;
526
- // Backticks after an escaped one open a shorter run of their own.
527
- if (line[cursor - 1] === '`' && line[cursor] === '`') {
528
- const span = codeSpanAt(line, cursor, closer);
529
- const end = span?.end ?? backtickRunEnd(line, cursor);
530
- segments.push(span?.segment ?? { kind: 'text', text: line.slice(cursor, end) });
531
- cursor = end;
532
- }
533
- }
534
- return segments;
535
- };
536
- const renderInline = (line) => {
537
- const segments = tokenizeInline(line);
538
- return segments
539
- .map((segment) => {
540
- switch (segment.kind) {
541
- case 'text':
542
- return escapeMrkdwn(unescapeGfm(segment.text));
543
- case 'code':
544
- // Code spans pass through with mrkdwn's single-backtick syntax, but
545
- // we still need to neutralize any embedded backticks.
546
- return code(segment.text);
547
- // The inner text is translated too, so `**a _b_**` nests.
548
- case 'bold':
549
- return `*${renderInline(segment.text)}*`;
550
- case 'italic':
551
- return `_${renderInline(segment.text)}_`;
552
- case 'link':
553
- return link(linkDestination(segment.url ?? ''), plainInline(segment.text));
554
- default: {
555
- const unexpected = segment.kind;
556
- return unexpected;
557
- }
558
- }
559
- })
560
- .join('');
561
- };
562
- // Inline GFM as its text alone, for a link label or a table cell, where
563
- // mrkdwn formatting would show its markers.
564
- const plainInline = (line) => tokenizeInline(line)
565
- .map(({ kind, text }) => kind === 'text'
566
- ? unescapeGfm(text)
567
- : kind === 'code'
568
- ? text
569
- : plainInline(text))
570
- .join('');
571
- // GFM: up to three spaces of indent, and no backtick in the opener's info.
572
- const FENCE_RE = /^ {0,3}(`{3,})[^`]*$/;
573
- // Spaces and tabs only after it, plus the `\r` a CRLF line keeps.
574
- const CLOSING_FENCE_RE = /^ {0,3}(`{3,})[ \t]*\r?$/;
575
- // A closing fence is backticks alone, at least as long as the opening run.
576
- const closesFence = (line, opening) => (CLOSING_FENCE_RE.exec(line)?.[1]?.length ?? 0) >= opening.length;
577
- // At least one pipe, so a single-column table counts and a thematic break does not.
578
- const TABLE_SEPARATOR_RE = /^(?=[^|]*\|)\s*(?!\s)\|?\s*:?-+:?\s*(?!\s)(\|\s*:?-+:?\s*(?!\s))*\|?\s*$/;
579
- const TABLE_ROW_RE = /^\s*\|.*\|\s*$/;
580
- const BLOCKQUOTE_RE = /^(>\s?)(.*)$/;
581
- // An ATX heading's text without its closing `#` run, or `undefined`. An
582
- // escaped `\#` is text, not part of the closing run.
583
- const headingText = (line) => {
584
- const text = /^#{1,6}[ \t]+(.*)$/.exec(line)?.[1]?.trimEnd();
585
- if (text === undefined) {
586
- return undefined;
587
- }
588
- const closing = /(?:^|[ \t])#+$/.exec(text);
589
- const content = closing ? text.slice(0, closing.index).trimEnd() : text;
590
- return content.length > 0 ? content : undefined;
591
- };
592
- // Splits a `| a | b |` row on its unescaped pipes into cell text, dropping the
593
- // optional leading/trailing pipes. GFM unescapes `\|` before reading a cell,
594
- // code spans included.
595
- const splitPipeRow = (line) => {
596
- const row = line.trim();
597
- const cells = [];
598
- let cell = '';
599
- let endsWithPipe = false;
600
- for (let index = 0; index < row.length; index += 1) {
601
- const char = row[index];
602
- const next = row[index + 1];
603
- endsWithPipe = false;
604
- if (char === '\\' && next !== undefined) {
605
- cell += next === '|' ? '|' : `\\${next}`;
606
- index += 1;
607
- }
608
- else if (char === '|') {
609
- cells.push(cell);
610
- cell = '';
611
- endsWithPipe = true;
612
- }
613
- else {
614
- cell += char;
615
- }
616
- }
617
- if (!endsWithPipe) {
618
- cells.push(cell);
619
- }
620
- if (row.startsWith('|')) {
621
- cells.shift();
622
- }
623
- return cells.map((value) => plainInline(value.trim()));
624
- };
625
- /**
626
- * Translates GFM into one Slack `mrkdwn` string:
627
- *
628
- * - Bold `**X**` to `*X*`, links `[L](U)` to `<U|L>`.
629
- * - ATX headings to bold, since Slack renders no headings.
630
- * - Pipe tables into a fenced code block, mrkdwn having no table syntax — the
631
- * monospace alignment is all that survives. Prefer
632
- * {@link gfmToSlackBlocks} when a native `table` block is acceptable.
633
- *
634
- * Free text is HTML-escaped (`&` `<` `>`) per Slack's rules; code spans and
635
- * fenced blocks pass through untouched.
636
- */
637
- export const gfmToSlackMrkdwn = (gfm) => {
638
- const lines = gfm.split('\n');
639
- const out = [];
640
- let i = 0;
641
- while (i < lines.length) {
642
- const line = lines[i];
643
- const opening = FENCE_RE.exec(line)?.[1];
644
- if (opening !== undefined) {
645
- // Fenced code block: copy the body verbatim. Slack honours the
646
- // triple-backtick fence but ignores the language hint, so we strip it
647
- // for cleanliness.
648
- const body = [];
649
- i += 1;
650
- while (i < lines.length && !closesFence(lines[i], opening)) {
651
- body.push(lines[i]);
652
- i += 1;
653
- }
654
- out.push(codeBlock(body.join('\n')));
655
- i += 1;
656
- continue;
657
- }
658
- if (TABLE_ROW_RE.test(line) &&
659
- i + 1 < lines.length &&
660
- TABLE_SEPARATOR_RE.test(lines[i + 1])) {
661
- // GFM pipe table: Slack mrkdwn cannot render tables, so we wrap the
662
- // entire block in a code fence to preserve the column alignment that
663
- // the markdown renderer worked hard to produce.
664
- const tableLines = [];
665
- while (i < lines.length && TABLE_ROW_RE.test(lines[i])) {
666
- tableLines.push(lines[i]);
667
- i += 1;
668
- }
669
- out.push(codeBlock(tableLines
670
- .map((row) => TABLE_SEPARATOR_RE.test(row)
671
- ? row
672
- : `| ${splitPipeRow(row).join(' | ')} |`)
673
- .join('\n')));
674
- continue;
675
- }
676
- const heading = headingText(line);
677
- if (heading !== undefined) {
678
- // Headings have no first-class mrkdwn equivalent. Bolding the text keeps
679
- // the visual hierarchy without inventing markup Slack would render as
680
- // a literal `#`.
681
- out.push(bold(unescapeGfm(heading)));
682
- i += 1;
683
- continue;
684
- }
685
- const blockquoteMatch = line.match(BLOCKQUOTE_RE);
686
- if (blockquoteMatch) {
687
- // Slack mrkdwn supports `>` blockquotes. Preserve the prefix verbatim
688
- // and run only the body through inline transformation so that bold,
689
- // italic, links, and emoji glyphs inside the quote still translate.
690
- out.push(`${blockquoteMatch[1]}${renderInline(blockquoteMatch[2] ?? '')}`);
691
- i += 1;
692
- continue;
693
- }
694
- out.push(renderInline(line));
695
- i += 1;
696
- }
697
- return out.join('\n');
698
- };
699
- // ---------------------------------------------------------------------------
700
- // GFM -> Slack *block* translation.
701
- const slackPreformattedBlock = (code) => ({
702
- type: 'rich_text',
703
- elements: [
704
- {
705
- type: 'rich_text_preformatted',
706
- elements: [
707
- {
708
- type: 'text',
709
- text: clampSlackText(code, SLACK_LIMITS.sectionTextChars),
710
- },
711
- ],
712
- },
713
- ],
714
- });
715
- // Reads a GFM alignment marker (`:---`, `---:`, `:---:`) into a column align.
716
- const parseColumnAlign = (marker) => {
717
- const left = marker.startsWith(':');
718
- const right = marker.endsWith(':');
719
- if (left && right) {
720
- return 'center';
721
- }
722
- return right ? 'right' : 'left';
723
- };
724
- const pipeTableToTableBlock = (lines) => {
725
- const [headerLine, separatorLine, ...bodyLines] = lines;
726
- const aligns = splitPipeRow(separatorLine ?? '').map(parseColumnAlign);
727
- const rows = [splitPipeRow(headerLine ?? ''), ...bodyLines.map(splitPipeRow)]
728
- .slice(0, SLACK_LIMITS.tableRows)
729
- .map((cells) => cells
730
- .slice(0, SLACK_LIMITS.tableColumns)
731
- .map((value) => ({
732
- type: 'raw_text',
733
- text: value,
734
- })));
735
- return {
736
- type: 'table',
737
- rows,
738
- column_settings: aligns
739
- .slice(0, SLACK_LIMITS.tableColumns)
740
- .map((align) => ({ align, is_wrapped: true })),
741
- };
742
- };
743
- /**
744
- * Translates GFM into structural Block Kit: prose runs as `section`, fenced
745
- * code as `rich_text_preformatted`, pipe tables as a native `table` block.
746
- *
747
- * The markdown fallback for a primitive without a `slack` renderer whose
748
- * markdown is a string; builder content goes through
749
- * `markdownContentToSlackBlocks`. Preferred over {@link gfmToSlackMrkdwn},
750
- * which collapses code and tables into
751
- * a section-level fence that Slack and pixel-faithful previews render poorly.
752
- */
753
- export const gfmToSlackBlocks = (gfm) => {
754
- const lines = gfm.split('\n');
755
- const blocks = [];
756
- let prose = [];
757
- const flushProse = () => {
758
- while (prose.length > 0 && prose[0].trim() === '') {
759
- prose.shift();
760
- }
761
- while (prose.length > 0 && prose[prose.length - 1].trim() === '') {
762
- prose.pop();
763
- }
764
- if (prose.length === 0) {
765
- return;
766
- }
767
- const text = clampMrkdwn(gfmToSlackMrkdwn(prose.join('\n')), SLACK_LIMITS.sectionTextChars);
768
- prose = [];
769
- if (text.length > 0) {
770
- blocks.push({ type: 'section', text: { type: 'mrkdwn', text } });
771
- }
772
- };
773
- let i = 0;
774
- while (i < lines.length) {
775
- const line = lines[i];
776
- const opening = FENCE_RE.exec(line)?.[1];
777
- if (opening !== undefined) {
778
- flushProse();
779
- i += 1;
780
- const code = [];
781
- while (i < lines.length && !closesFence(lines[i], opening)) {
782
- code.push(lines[i]);
783
- i += 1;
784
- }
785
- i += 1; // Consume the closing fence.
786
- blocks.push(slackPreformattedBlock(code.join('\n')));
787
- continue;
788
- }
789
- if (TABLE_ROW_RE.test(line) &&
790
- i + 1 < lines.length &&
791
- TABLE_SEPARATOR_RE.test(lines[i + 1])) {
792
- flushProse();
793
- const tableLines = [];
794
- while (i < lines.length && TABLE_ROW_RE.test(lines[i])) {
795
- tableLines.push(lines[i]);
796
- i += 1;
797
- }
798
- blocks.push(pipeTableToTableBlock(tableLines));
799
- continue;
800
- }
801
- prose.push(line);
802
- i += 1;
803
- }
804
- flushProse();
805
- return blocks;
806
- };
807
209
  //# sourceMappingURL=format.js.map