@portabletext/markdown 1.0.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.
@@ -0,0 +1,3273 @@
1
+ import {
2
+ compileSchema,
3
+ defineSchema,
4
+ type BlockObjectDefinition,
5
+ } from '@portabletext/schema'
6
+ import {createTestKeyGenerator, getTersePt} from '@portabletext/test'
7
+ import {describe, expect, test} from 'vitest'
8
+ import {defaultSchema} from './default-schema'
9
+ import {markdownToPortableText} from './to-portable-text/markdown-to-portable-text'
10
+ import {buildObjectMatcher} from './to-portable-text/matchers'
11
+
12
+ describe(markdownToPortableText.name, () => {
13
+ test('empty string', () => {
14
+ const keyGenerator = createTestKeyGenerator()
15
+ expect(markdownToPortableText('', {keyGenerator})).toEqual([])
16
+ })
17
+
18
+ describe('style', () => {
19
+ describe('normal', () => {
20
+ test('default definition', () => {
21
+ const keyGenerator = createTestKeyGenerator()
22
+ expect(markdownToPortableText('foo', {keyGenerator})).toEqual([
23
+ {
24
+ _type: 'block',
25
+ _key: 'k0',
26
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
27
+ markDefs: [],
28
+ style: 'normal',
29
+ },
30
+ ])
31
+ })
32
+
33
+ test('custom definition', () => {
34
+ const keyGenerator = createTestKeyGenerator()
35
+ expect(
36
+ markdownToPortableText('foo', {
37
+ keyGenerator,
38
+ schema: compileSchema(
39
+ defineSchema({styles: [{name: 'paragraph'}]}),
40
+ ),
41
+ block: {
42
+ normal: ({context}) => {
43
+ return context.schema.styles.find(
44
+ (style) => style.name === 'paragraph',
45
+ )?.name
46
+ },
47
+ },
48
+ }),
49
+ ).toEqual([
50
+ {
51
+ _type: 'block',
52
+ _key: 'k0',
53
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
54
+ markDefs: [],
55
+ style: 'paragraph',
56
+ },
57
+ ])
58
+ })
59
+
60
+ test('no definition', () => {
61
+ const keyGenerator = createTestKeyGenerator()
62
+ expect(
63
+ markdownToPortableText('foo', {
64
+ keyGenerator,
65
+ schema: compileSchema(defineSchema({})),
66
+ }),
67
+ ).toEqual([
68
+ {
69
+ _type: 'block',
70
+ _key: 'k0',
71
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
72
+ markDefs: [],
73
+ style: 'normal',
74
+ },
75
+ ])
76
+ })
77
+ })
78
+
79
+ describe('blockquote', () => {
80
+ test('default definition', () => {
81
+ const keyGenerator = createTestKeyGenerator()
82
+ expect(markdownToPortableText('> foo', {keyGenerator})).toEqual([
83
+ {
84
+ _type: 'block',
85
+ _key: 'k0',
86
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
87
+ markDefs: [],
88
+ style: 'blockquote',
89
+ },
90
+ ])
91
+ })
92
+
93
+ test('custom definition', () => {
94
+ const keyGenerator = createTestKeyGenerator()
95
+ expect(
96
+ markdownToPortableText('> foo', {
97
+ keyGenerator,
98
+ schema: compileSchema(
99
+ defineSchema({
100
+ styles: [{name: 'normal'}, {name: 'quote'}],
101
+ }),
102
+ ),
103
+ block: {
104
+ blockquote: ({context}) =>
105
+ context.schema.styles.find((style) => style.name === 'quote')
106
+ ?.name,
107
+ },
108
+ }),
109
+ ).toEqual([
110
+ {
111
+ _type: 'block',
112
+ _key: 'k0',
113
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
114
+ markDefs: [],
115
+ style: 'quote',
116
+ },
117
+ ])
118
+ })
119
+
120
+ test('no definition', () => {
121
+ const keyGenerator = createTestKeyGenerator()
122
+ expect(
123
+ markdownToPortableText('> foo', {
124
+ keyGenerator,
125
+ schema: compileSchema(defineSchema({})),
126
+ }),
127
+ ).toEqual([
128
+ {
129
+ _type: 'block',
130
+ _key: 'k0',
131
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
132
+ markDefs: [],
133
+ style: 'normal',
134
+ },
135
+ ])
136
+ })
137
+
138
+ describe('multiple lines', () => {
139
+ const markdown = '> foo\n>\n> bar\n> baz'
140
+
141
+ test('default definition', () => {
142
+ const keyGenerator = createTestKeyGenerator()
143
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
144
+ {
145
+ _type: 'block',
146
+ _key: 'k0',
147
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
148
+ markDefs: [],
149
+ style: 'blockquote',
150
+ },
151
+ {
152
+ _type: 'block',
153
+ _key: 'k2',
154
+ children: [
155
+ {_type: 'span', _key: 'k3', text: 'bar\nbaz', marks: []},
156
+ ],
157
+ markDefs: [],
158
+ style: 'blockquote',
159
+ },
160
+ ])
161
+ })
162
+
163
+ test('custom definition', () => {
164
+ const keyGenerator = createTestKeyGenerator()
165
+ expect(
166
+ markdownToPortableText(markdown, {
167
+ keyGenerator,
168
+ schema: compileSchema(defineSchema({styles: [{name: 'quote'}]})),
169
+ block: {
170
+ blockquote: () => 'quote',
171
+ },
172
+ }),
173
+ ).toEqual([
174
+ {
175
+ _type: 'block',
176
+ _key: 'k0',
177
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
178
+ markDefs: [],
179
+ style: 'quote',
180
+ },
181
+ {
182
+ _type: 'block',
183
+ _key: 'k2',
184
+ children: [
185
+ {_type: 'span', _key: 'k3', text: 'bar\nbaz', marks: []},
186
+ ],
187
+ markDefs: [],
188
+ style: 'quote',
189
+ },
190
+ ])
191
+ })
192
+
193
+ test('no definition', () => {
194
+ const keyGenerator = createTestKeyGenerator()
195
+ expect(
196
+ markdownToPortableText(markdown, {
197
+ keyGenerator,
198
+ schema: compileSchema(defineSchema({})),
199
+ }),
200
+ ).toEqual([
201
+ {
202
+ _type: 'block',
203
+ _key: 'k0',
204
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
205
+ markDefs: [],
206
+ style: 'normal',
207
+ },
208
+ {
209
+ _type: 'block',
210
+ _key: 'k2',
211
+ children: [
212
+ {_type: 'span', _key: 'k3', text: 'bar\nbaz', marks: []},
213
+ ],
214
+ markDefs: [],
215
+ style: 'normal',
216
+ },
217
+ ])
218
+ })
219
+ })
220
+
221
+ test('nested blockquotes', () => {
222
+ const keyGenerator = createTestKeyGenerator()
223
+ const markdown = ['> outer', '> > inner'].join('\n')
224
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
225
+ {
226
+ _type: 'block',
227
+ _key: 'k0',
228
+ children: [{_type: 'span', _key: 'k1', text: 'outer', marks: []}],
229
+ markDefs: [],
230
+ style: 'blockquote',
231
+ },
232
+ {
233
+ _type: 'block',
234
+ _key: 'k2',
235
+ children: [{_type: 'span', _key: 'k3', text: 'inner', marks: []}],
236
+ markDefs: [],
237
+ style: 'blockquote',
238
+ },
239
+ ])
240
+ })
241
+
242
+ describe('with list items', () => {
243
+ const markdown = ['> - foo', '> - bar'].join('\n')
244
+
245
+ test('default definition', () => {
246
+ const keyGenerator = createTestKeyGenerator()
247
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
248
+ {
249
+ _type: 'block',
250
+ _key: 'k0',
251
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
252
+ markDefs: [],
253
+ style: 'blockquote',
254
+ listItem: 'bullet',
255
+ level: 1,
256
+ },
257
+ {
258
+ _type: 'block',
259
+ _key: 'k2',
260
+ children: [{_type: 'span', _key: 'k3', text: 'bar', marks: []}],
261
+ markDefs: [],
262
+ style: 'blockquote',
263
+ listItem: 'bullet',
264
+ level: 1,
265
+ },
266
+ ])
267
+ })
268
+
269
+ test('only list definition', () => {
270
+ const keyGenerator = createTestKeyGenerator()
271
+ expect(
272
+ markdownToPortableText(markdown, {
273
+ keyGenerator,
274
+ schema: compileSchema(defineSchema({lists: [{name: 'bullet'}]})),
275
+ }),
276
+ ).toEqual([
277
+ {
278
+ _type: 'block',
279
+ _key: 'k0',
280
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
281
+ markDefs: [],
282
+ style: 'normal',
283
+ listItem: 'bullet',
284
+ level: 1,
285
+ },
286
+ {
287
+ _type: 'block',
288
+ _key: 'k2',
289
+ children: [{_type: 'span', _key: 'k3', text: 'bar', marks: []}],
290
+ markDefs: [],
291
+ style: 'normal',
292
+ listItem: 'bullet',
293
+ level: 1,
294
+ },
295
+ ])
296
+ })
297
+ })
298
+ })
299
+
300
+ describe('h1', () => {
301
+ test('default definition', () => {
302
+ const keyGenerator = createTestKeyGenerator()
303
+ expect(markdownToPortableText('# foo', {keyGenerator})).toEqual([
304
+ {
305
+ _type: 'block',
306
+ _key: 'k0',
307
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
308
+ markDefs: [],
309
+ style: 'h1',
310
+ },
311
+ ])
312
+ })
313
+
314
+ test('custom definition', () => {
315
+ const keyGenerator = createTestKeyGenerator()
316
+ expect(
317
+ markdownToPortableText('# foo', {
318
+ keyGenerator,
319
+ schema: compileSchema(
320
+ defineSchema({styles: [{name: 'heading 1'}]}),
321
+ ),
322
+ block: {
323
+ h1: ({context}) => {
324
+ return context.schema.styles.find(
325
+ (style) => style.name === 'heading 1',
326
+ )?.name
327
+ },
328
+ },
329
+ }),
330
+ ).toEqual([
331
+ {
332
+ _type: 'block',
333
+ _key: 'k0',
334
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
335
+ markDefs: [],
336
+ style: 'heading 1',
337
+ },
338
+ ])
339
+ })
340
+
341
+ test('no definition', () => {
342
+ const keyGenerator = createTestKeyGenerator()
343
+ expect(
344
+ markdownToPortableText('# foo', {
345
+ keyGenerator,
346
+ schema: compileSchema(defineSchema({})),
347
+ }),
348
+ ).toEqual([
349
+ {
350
+ _type: 'block',
351
+ _key: 'k0',
352
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
353
+ markDefs: [],
354
+ style: 'normal',
355
+ },
356
+ ])
357
+ })
358
+ })
359
+ })
360
+
361
+ describe('hard breaks', () => {
362
+ test('backslash syntax', () => {
363
+ const keyGenerator = createTestKeyGenerator()
364
+ expect(markdownToPortableText('foo\\\nbar', {keyGenerator})).toEqual([
365
+ {
366
+ _type: 'block',
367
+ _key: 'k0',
368
+ children: [{_type: 'span', _key: 'k1', text: 'foo\nbar', marks: []}],
369
+ markDefs: [],
370
+ style: 'normal',
371
+ },
372
+ ])
373
+ })
374
+
375
+ test('two-space syntax', () => {
376
+ const keyGenerator = createTestKeyGenerator()
377
+ expect(markdownToPortableText('foo \nbar', {keyGenerator})).toEqual([
378
+ {
379
+ _type: 'block',
380
+ _key: 'k0',
381
+ children: [{_type: 'span', _key: 'k1', text: 'foo\nbar', marks: []}],
382
+ markDefs: [],
383
+ style: 'normal',
384
+ },
385
+ ])
386
+ })
387
+
388
+ test('multiple hard breaks in same paragraph', () => {
389
+ const keyGenerator = createTestKeyGenerator()
390
+ expect(
391
+ markdownToPortableText('foo \nbar \nbaz', {keyGenerator}),
392
+ ).toEqual([
393
+ {
394
+ _type: 'block',
395
+ _key: 'k0',
396
+ children: [
397
+ {_type: 'span', _key: 'k1', text: 'foo\nbar\nbaz', marks: []},
398
+ ],
399
+ markDefs: [],
400
+ style: 'normal',
401
+ },
402
+ ])
403
+ })
404
+
405
+ test('hard break in list item', () => {
406
+ const keyGenerator = createTestKeyGenerator()
407
+ expect(markdownToPortableText('- foo \n bar', {keyGenerator})).toEqual([
408
+ {
409
+ _type: 'block',
410
+ _key: 'k0',
411
+ children: [{_type: 'span', _key: 'k1', text: 'foo\nbar', marks: []}],
412
+ markDefs: [],
413
+ style: 'normal',
414
+ listItem: 'bullet',
415
+ level: 1,
416
+ },
417
+ ])
418
+ })
419
+ })
420
+
421
+ describe('decorators', () => {
422
+ describe('strong', () => {
423
+ test('default definition', () => {
424
+ const keyGenerator = createTestKeyGenerator()
425
+ expect(
426
+ markdownToPortableText('foo **bar** baz', {keyGenerator}),
427
+ ).toEqual([
428
+ {
429
+ _type: 'block',
430
+ _key: 'k0',
431
+ children: [
432
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
433
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['strong']},
434
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
435
+ ],
436
+ markDefs: [],
437
+ style: 'normal',
438
+ },
439
+ ])
440
+ })
441
+
442
+ test('custom definition', () => {
443
+ const keyGenerator = createTestKeyGenerator()
444
+ expect(
445
+ markdownToPortableText('foo **bar** baz', {
446
+ keyGenerator,
447
+ schema: compileSchema(defineSchema({decorators: [{name: 'bold'}]})),
448
+ marks: {
449
+ strong: () => 'bold',
450
+ },
451
+ }),
452
+ ).toEqual([
453
+ {
454
+ _type: 'block',
455
+ _key: 'k0',
456
+ children: [
457
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
458
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['bold']},
459
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
460
+ ],
461
+ markDefs: [],
462
+ style: 'normal',
463
+ },
464
+ ])
465
+ })
466
+
467
+ test('no definition', () => {
468
+ const keyGenerator = createTestKeyGenerator()
469
+ expect(
470
+ markdownToPortableText('foo **bar** baz', {
471
+ keyGenerator,
472
+ schema: compileSchema(defineSchema({})),
473
+ }),
474
+ ).toEqual([
475
+ {
476
+ _type: 'block',
477
+ _key: 'k0',
478
+ children: [
479
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
480
+ ],
481
+ markDefs: [],
482
+ style: 'normal',
483
+ },
484
+ ])
485
+ })
486
+ })
487
+
488
+ describe('emphasis', () => {
489
+ test('default definition', () => {
490
+ const keyGenerator = createTestKeyGenerator()
491
+ expect(markdownToPortableText('foo _bar_ baz', {keyGenerator})).toEqual(
492
+ [
493
+ {
494
+ _type: 'block',
495
+ _key: 'k0',
496
+ children: [
497
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
498
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['em']},
499
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
500
+ ],
501
+ markDefs: [],
502
+ style: 'normal',
503
+ },
504
+ ],
505
+ )
506
+ })
507
+
508
+ test('custom definition', () => {
509
+ const keyGenerator = createTestKeyGenerator()
510
+ expect(
511
+ markdownToPortableText('foo _bar_ baz', {
512
+ keyGenerator,
513
+ schema: compileSchema(
514
+ defineSchema({decorators: [{name: 'italic'}]}),
515
+ ),
516
+ marks: {
517
+ em: () => 'italic',
518
+ },
519
+ }),
520
+ ).toEqual([
521
+ {
522
+ _type: 'block',
523
+ _key: 'k0',
524
+ children: [
525
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
526
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['italic']},
527
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
528
+ ],
529
+ markDefs: [],
530
+ style: 'normal',
531
+ },
532
+ ])
533
+ })
534
+
535
+ test('no definition', () => {
536
+ const keyGenerator = createTestKeyGenerator()
537
+ expect(
538
+ markdownToPortableText('foo _bar_ baz', {
539
+ keyGenerator,
540
+ schema: compileSchema(defineSchema({})),
541
+ }),
542
+ ).toEqual([
543
+ {
544
+ _type: 'block',
545
+ _key: 'k0',
546
+ children: [
547
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
548
+ ],
549
+ markDefs: [],
550
+ style: 'normal',
551
+ },
552
+ ])
553
+ })
554
+ })
555
+
556
+ describe('code', () => {
557
+ test('default definition', () => {
558
+ const keyGenerator = createTestKeyGenerator()
559
+ expect(markdownToPortableText('foo `bar` baz', {keyGenerator})).toEqual(
560
+ [
561
+ {
562
+ _type: 'block',
563
+ _key: 'k0',
564
+ children: [
565
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
566
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['code']},
567
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
568
+ ],
569
+ markDefs: [],
570
+ style: 'normal',
571
+ },
572
+ ],
573
+ )
574
+ })
575
+
576
+ test('custom definition', () => {
577
+ const keyGenerator = createTestKeyGenerator()
578
+ expect(
579
+ markdownToPortableText('foo `bar` baz', {
580
+ keyGenerator,
581
+ schema: compileSchema(
582
+ defineSchema({decorators: [{name: 'monospace'}]}),
583
+ ),
584
+ marks: {
585
+ code: () => 'monospace',
586
+ },
587
+ }),
588
+ ).toEqual([
589
+ {
590
+ _type: 'block',
591
+ _key: 'k0',
592
+ children: [
593
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
594
+ {_type: 'span', _key: 'k2', text: 'bar', marks: ['monospace']},
595
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
596
+ ],
597
+ markDefs: [],
598
+ style: 'normal',
599
+ },
600
+ ])
601
+ })
602
+
603
+ test('no definition', () => {
604
+ const keyGenerator = createTestKeyGenerator()
605
+ expect(
606
+ markdownToPortableText('foo `bar` baz', {
607
+ keyGenerator,
608
+ schema: compileSchema(defineSchema({})),
609
+ }),
610
+ ).toEqual([
611
+ {
612
+ _type: 'block',
613
+ _key: 'k0',
614
+ children: [
615
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
616
+ ],
617
+ markDefs: [],
618
+ style: 'normal',
619
+ },
620
+ ])
621
+ })
622
+ })
623
+
624
+ describe('strike-through', () => {
625
+ test('default definition', () => {
626
+ const keyGenerator = createTestKeyGenerator()
627
+ expect(
628
+ markdownToPortableText('foo ~~bar~~ baz', {keyGenerator}),
629
+ ).toEqual([
630
+ {
631
+ _type: 'block',
632
+ _key: 'k0',
633
+ children: [
634
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
635
+ {
636
+ _type: 'span',
637
+ _key: 'k2',
638
+ text: 'bar',
639
+ marks: ['strike-through'],
640
+ },
641
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
642
+ ],
643
+ markDefs: [],
644
+ style: 'normal',
645
+ },
646
+ ])
647
+ })
648
+
649
+ test('custom definition', () => {
650
+ const keyGenerator = createTestKeyGenerator()
651
+ expect(
652
+ markdownToPortableText('foo ~~bar~~ baz', {
653
+ keyGenerator,
654
+ schema: compileSchema(
655
+ defineSchema({decorators: [{name: 'strikethrough'}]}),
656
+ ),
657
+ marks: {
658
+ strikeThrough: () => 'strikethrough',
659
+ },
660
+ }),
661
+ ).toEqual([
662
+ {
663
+ _type: 'block',
664
+ _key: 'k0',
665
+ children: [
666
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
667
+ {
668
+ _type: 'span',
669
+ _key: 'k2',
670
+ text: 'bar',
671
+ marks: ['strikethrough'],
672
+ },
673
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
674
+ ],
675
+ markDefs: [],
676
+ style: 'normal',
677
+ },
678
+ ])
679
+ })
680
+
681
+ test('no definition', () => {
682
+ const keyGenerator = createTestKeyGenerator()
683
+ expect(
684
+ markdownToPortableText('foo ~~bar~~ baz', {
685
+ keyGenerator,
686
+ schema: compileSchema(defineSchema({})),
687
+ }),
688
+ ).toEqual([
689
+ {
690
+ _type: 'block',
691
+ _key: 'k0',
692
+ children: [
693
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
694
+ ],
695
+ markDefs: [],
696
+ style: 'normal',
697
+ },
698
+ ])
699
+ })
700
+ })
701
+ })
702
+
703
+ describe('link', () => {
704
+ test('default definition', () => {
705
+ const keyGenerator = createTestKeyGenerator()
706
+ expect(
707
+ markdownToPortableText('foo [bar](https://example.com) baz', {
708
+ keyGenerator,
709
+ }),
710
+ ).toEqual([
711
+ {
712
+ _type: 'block',
713
+ _key: 'k0',
714
+ children: [
715
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
716
+ {_type: 'span', _key: 'k3', text: 'bar', marks: ['k2']},
717
+ {_type: 'span', _key: 'k4', text: ' baz', marks: []},
718
+ ],
719
+ markDefs: [
720
+ {
721
+ _key: 'k2',
722
+ _type: 'link',
723
+ href: 'https://example.com',
724
+ },
725
+ ],
726
+ style: 'normal',
727
+ },
728
+ ])
729
+ })
730
+
731
+ test('no href field', () => {
732
+ const keyGenerator = createTestKeyGenerator()
733
+ expect(
734
+ markdownToPortableText('foo [bar](https://example.com) baz', {
735
+ keyGenerator,
736
+ schema: compileSchema(
737
+ defineSchema({annotations: [{name: 'link', fields: []}]}),
738
+ ),
739
+ }),
740
+ ).toEqual([
741
+ {
742
+ _type: 'block',
743
+ _key: 'k0',
744
+ children: [
745
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
746
+ {_type: 'span', _key: 'k3', text: 'bar', marks: ['k2']},
747
+ {_type: 'span', _key: 'k4', text: ' baz', marks: []},
748
+ ],
749
+ markDefs: [
750
+ {
751
+ _key: 'k2',
752
+ _type: 'link',
753
+ },
754
+ ],
755
+ style: 'normal',
756
+ },
757
+ ])
758
+ })
759
+
760
+ test('custom definition', () => {
761
+ const keyGenerator = createTestKeyGenerator()
762
+ expect(
763
+ markdownToPortableText('foo [bar](https://example.com) baz', {
764
+ keyGenerator,
765
+ schema: compileSchema(
766
+ defineSchema({
767
+ annotations: [
768
+ {
769
+ name: 'internal link',
770
+ fields: [{name: 'url', type: 'string'}],
771
+ },
772
+ ],
773
+ }),
774
+ ),
775
+ marks: {
776
+ link: ({context, value}) => {
777
+ return {
778
+ _type: 'internal link',
779
+ _key: context.keyGenerator(),
780
+ url: value.href,
781
+ }
782
+ },
783
+ },
784
+ }),
785
+ ).toEqual([
786
+ {
787
+ _type: 'block',
788
+ _key: 'k0',
789
+ children: [
790
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
791
+ {_type: 'span', _key: 'k3', text: 'bar', marks: ['k2']},
792
+ {_type: 'span', _key: 'k4', text: ' baz', marks: []},
793
+ ],
794
+ markDefs: [
795
+ {
796
+ _key: 'k2',
797
+ _type: 'internal link',
798
+ url: 'https://example.com',
799
+ },
800
+ ],
801
+ style: 'normal',
802
+ },
803
+ ])
804
+ })
805
+
806
+ test('no definition', () => {
807
+ const keyGenerator = createTestKeyGenerator()
808
+ expect(
809
+ markdownToPortableText('foo [bar](https://example.com) baz', {
810
+ keyGenerator,
811
+ schema: compileSchema(defineSchema({})),
812
+ }),
813
+ ).toEqual([
814
+ {
815
+ _type: 'block',
816
+ _key: 'k0',
817
+ children: [
818
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
819
+ ],
820
+ markDefs: [],
821
+ style: 'normal',
822
+ },
823
+ ])
824
+ })
825
+
826
+ test('with title', () => {
827
+ const keyGenerator = createTestKeyGenerator()
828
+ expect(
829
+ markdownToPortableText(
830
+ 'foo [bar](https://example.com "Link Title") baz',
831
+ {
832
+ keyGenerator,
833
+ },
834
+ ),
835
+ ).toEqual([
836
+ {
837
+ _type: 'block',
838
+ _key: 'k0',
839
+ children: [
840
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
841
+ {_type: 'span', _key: 'k3', text: 'bar', marks: ['k2']},
842
+ {_type: 'span', _key: 'k4', text: ' baz', marks: []},
843
+ ],
844
+ markDefs: [
845
+ {
846
+ _key: 'k2',
847
+ _type: 'link',
848
+ href: 'https://example.com',
849
+ title: 'Link Title',
850
+ },
851
+ ],
852
+ style: 'normal',
853
+ },
854
+ ])
855
+ })
856
+
857
+ test('autolink', () => {
858
+ const keyGenerator = createTestKeyGenerator()
859
+ expect(
860
+ markdownToPortableText('Visit <https://example.com> for more', {
861
+ keyGenerator,
862
+ }),
863
+ ).toEqual([
864
+ {
865
+ _type: 'block',
866
+ _key: 'k0',
867
+ children: [
868
+ {_type: 'span', _key: 'k1', text: 'Visit ', marks: []},
869
+ {
870
+ _type: 'span',
871
+ _key: 'k3',
872
+ text: 'https://example.com',
873
+ marks: ['k2'],
874
+ },
875
+ {_type: 'span', _key: 'k4', text: ' for more', marks: []},
876
+ ],
877
+ markDefs: [
878
+ {
879
+ _key: 'k2',
880
+ _type: 'link',
881
+ href: 'https://example.com',
882
+ },
883
+ ],
884
+ style: 'normal',
885
+ },
886
+ ])
887
+ })
888
+
889
+ test('reference-style link', () => {
890
+ const keyGenerator = createTestKeyGenerator()
891
+ const markdown = [
892
+ 'See [my site][ref] for details',
893
+ '',
894
+ '[ref]: https://example.com "My Site"',
895
+ ].join('\n')
896
+ expect(
897
+ markdownToPortableText(markdown, {
898
+ keyGenerator,
899
+ }),
900
+ ).toEqual([
901
+ {
902
+ _type: 'block',
903
+ _key: 'k0',
904
+ children: [
905
+ {_type: 'span', _key: 'k1', text: 'See ', marks: []},
906
+ {_type: 'span', _key: 'k3', text: 'my site', marks: ['k2']},
907
+ {_type: 'span', _key: 'k4', text: ' for details', marks: []},
908
+ ],
909
+ markDefs: [
910
+ {
911
+ _key: 'k2',
912
+ _type: 'link',
913
+ href: 'https://example.com',
914
+ title: 'My Site',
915
+ },
916
+ ],
917
+ style: 'normal',
918
+ },
919
+ ])
920
+ })
921
+ })
922
+
923
+ describe('lists', () => {
924
+ describe('unordered', () => {
925
+ test('default unordered list', () => {
926
+ const keyGenerator = createTestKeyGenerator()
927
+ expect(markdownToPortableText('- foo', {keyGenerator})).toEqual([
928
+ {
929
+ _type: 'block',
930
+ _key: 'k0',
931
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
932
+ markDefs: [],
933
+ style: 'normal',
934
+ listItem: 'bullet',
935
+ level: 1,
936
+ },
937
+ ])
938
+ })
939
+
940
+ test('custom unordered list', () => {
941
+ const keyGenerator = createTestKeyGenerator()
942
+ expect(
943
+ markdownToPortableText('- foo', {
944
+ keyGenerator,
945
+ schema: compileSchema(defineSchema({lists: [{name: 'dot'}]})),
946
+ listItem: {
947
+ bullet: ({context}) => {
948
+ return context.schema.lists.find((list) => list.name === 'dot')
949
+ ?.name
950
+ },
951
+ },
952
+ }),
953
+ ).toEqual([
954
+ {
955
+ _type: 'block',
956
+ _key: 'k0',
957
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
958
+ markDefs: [],
959
+ style: 'normal',
960
+ listItem: 'dot',
961
+ level: 1,
962
+ },
963
+ ])
964
+ })
965
+
966
+ test('no unordered list', () => {
967
+ const keyGenerator = createTestKeyGenerator()
968
+ expect(
969
+ markdownToPortableText('- foo', {
970
+ keyGenerator,
971
+ schema: compileSchema(defineSchema({})),
972
+ }),
973
+ ).toEqual([
974
+ {
975
+ _type: 'block',
976
+ _key: 'k0',
977
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
978
+ markDefs: [],
979
+ style: 'normal',
980
+ },
981
+ ])
982
+ })
983
+ })
984
+
985
+ describe('ordered', () => {
986
+ test('default ordered list', () => {
987
+ const keyGenerator = createTestKeyGenerator()
988
+ expect(markdownToPortableText('1. foo', {keyGenerator})).toEqual([
989
+ {
990
+ _type: 'block',
991
+ _key: 'k0',
992
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
993
+ markDefs: [],
994
+ style: 'normal',
995
+ listItem: 'number',
996
+ level: 1,
997
+ },
998
+ ])
999
+ })
1000
+
1001
+ test('custom ordered list', () => {
1002
+ const keyGenerator = createTestKeyGenerator()
1003
+ expect(
1004
+ markdownToPortableText('1. foo', {
1005
+ keyGenerator,
1006
+ schema: compileSchema(defineSchema({lists: [{name: 'alpha'}]})),
1007
+ listItem: {
1008
+ number: ({context}) => {
1009
+ return context.schema.lists.find(
1010
+ (list) => list.name === 'alpha',
1011
+ )?.name
1012
+ },
1013
+ },
1014
+ }),
1015
+ ).toEqual([
1016
+ {
1017
+ _type: 'block',
1018
+ _key: 'k0',
1019
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
1020
+ markDefs: [],
1021
+ style: 'normal',
1022
+ listItem: 'alpha',
1023
+ level: 1,
1024
+ },
1025
+ ])
1026
+ })
1027
+
1028
+ test('no ordered list', () => {
1029
+ const keyGenerator = createTestKeyGenerator()
1030
+ expect(
1031
+ markdownToPortableText('1. foo', {
1032
+ keyGenerator,
1033
+ schema: compileSchema(defineSchema({})),
1034
+ }),
1035
+ ).toEqual([
1036
+ {
1037
+ _type: 'block',
1038
+ _key: 'k0',
1039
+ children: [{_type: 'span', _key: 'k1', text: 'foo', marks: []}],
1040
+ markDefs: [],
1041
+ style: 'normal',
1042
+ },
1043
+ ])
1044
+ })
1045
+ })
1046
+
1047
+ describe('nested', () => {
1048
+ test('unordered nested lists', () => {
1049
+ const keyGenerator = createTestKeyGenerator()
1050
+ const markdown = [
1051
+ '- Level 1 item 1',
1052
+ ' - Level 2 item 1',
1053
+ ' - Level 2 item 2',
1054
+ ' - Level 3 item 1',
1055
+ '- Level 1 item 2',
1056
+ ].join('\n')
1057
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1058
+ {
1059
+ _type: 'block',
1060
+ _key: 'k0',
1061
+ children: [
1062
+ {_type: 'span', _key: 'k1', text: 'Level 1 item 1', marks: []},
1063
+ ],
1064
+ markDefs: [],
1065
+ style: 'normal',
1066
+ listItem: 'bullet',
1067
+ level: 1,
1068
+ },
1069
+ {
1070
+ _type: 'block',
1071
+ _key: 'k2',
1072
+ children: [
1073
+ {_type: 'span', _key: 'k3', text: 'Level 2 item 1', marks: []},
1074
+ ],
1075
+ markDefs: [],
1076
+ style: 'normal',
1077
+ listItem: 'bullet',
1078
+ level: 2,
1079
+ },
1080
+ {
1081
+ _type: 'block',
1082
+ _key: 'k4',
1083
+ children: [
1084
+ {_type: 'span', _key: 'k5', text: 'Level 2 item 2', marks: []},
1085
+ ],
1086
+ markDefs: [],
1087
+ style: 'normal',
1088
+ listItem: 'bullet',
1089
+ level: 2,
1090
+ },
1091
+ {
1092
+ _type: 'block',
1093
+ _key: 'k6',
1094
+ children: [
1095
+ {_type: 'span', _key: 'k7', text: 'Level 3 item 1', marks: []},
1096
+ ],
1097
+ markDefs: [],
1098
+ style: 'normal',
1099
+ listItem: 'bullet',
1100
+ level: 3,
1101
+ },
1102
+ {
1103
+ _type: 'block',
1104
+ _key: 'k8',
1105
+ children: [
1106
+ {_type: 'span', _key: 'k9', text: 'Level 1 item 2', marks: []},
1107
+ ],
1108
+ markDefs: [],
1109
+ style: 'normal',
1110
+ listItem: 'bullet',
1111
+ level: 1,
1112
+ },
1113
+ ])
1114
+ })
1115
+
1116
+ test('ordered nested lists', () => {
1117
+ const keyGenerator = createTestKeyGenerator()
1118
+ const markdown = [
1119
+ '1. Level 1 item 1',
1120
+ ' 1. Level 2 item 1',
1121
+ ' 2. Level 2 item 2',
1122
+ '2. Level 1 item 2',
1123
+ ].join('\n')
1124
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1125
+ {
1126
+ _type: 'block',
1127
+ _key: 'k0',
1128
+ children: [
1129
+ {_type: 'span', _key: 'k1', text: 'Level 1 item 1', marks: []},
1130
+ ],
1131
+ markDefs: [],
1132
+ style: 'normal',
1133
+ listItem: 'number',
1134
+ level: 1,
1135
+ },
1136
+ {
1137
+ _type: 'block',
1138
+ _key: 'k2',
1139
+ children: [
1140
+ {_type: 'span', _key: 'k3', text: 'Level 2 item 1', marks: []},
1141
+ ],
1142
+ markDefs: [],
1143
+ style: 'normal',
1144
+ listItem: 'number',
1145
+ level: 2,
1146
+ },
1147
+ {
1148
+ _type: 'block',
1149
+ _key: 'k4',
1150
+ children: [
1151
+ {_type: 'span', _key: 'k5', text: 'Level 2 item 2', marks: []},
1152
+ ],
1153
+ markDefs: [],
1154
+ style: 'normal',
1155
+ listItem: 'number',
1156
+ level: 2,
1157
+ },
1158
+ {
1159
+ _type: 'block',
1160
+ _key: 'k6',
1161
+ children: [
1162
+ {_type: 'span', _key: 'k7', text: 'Level 1 item 2', marks: []},
1163
+ ],
1164
+ markDefs: [],
1165
+ style: 'normal',
1166
+ listItem: 'number',
1167
+ level: 1,
1168
+ },
1169
+ ])
1170
+ })
1171
+
1172
+ test('mixed nested lists', () => {
1173
+ const keyGenerator = createTestKeyGenerator()
1174
+ const markdown = [
1175
+ '1. Ordered item',
1176
+ ' - Unordered nested',
1177
+ ' - Another unordered',
1178
+ '2. Back to ordered',
1179
+ ].join('\n')
1180
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1181
+ {
1182
+ _type: 'block',
1183
+ _key: 'k0',
1184
+ children: [
1185
+ {_type: 'span', _key: 'k1', text: 'Ordered item', marks: []},
1186
+ ],
1187
+ markDefs: [],
1188
+ style: 'normal',
1189
+ listItem: 'number',
1190
+ level: 1,
1191
+ },
1192
+ {
1193
+ _type: 'block',
1194
+ _key: 'k2',
1195
+ children: [
1196
+ {_type: 'span', _key: 'k3', text: 'Unordered nested', marks: []},
1197
+ ],
1198
+ markDefs: [],
1199
+ style: 'normal',
1200
+ listItem: 'bullet',
1201
+ level: 2,
1202
+ },
1203
+ {
1204
+ _type: 'block',
1205
+ _key: 'k4',
1206
+ children: [
1207
+ {
1208
+ _type: 'span',
1209
+ _key: 'k5',
1210
+ text: 'Another unordered',
1211
+ marks: [],
1212
+ },
1213
+ ],
1214
+ markDefs: [],
1215
+ style: 'normal',
1216
+ listItem: 'bullet',
1217
+ level: 2,
1218
+ },
1219
+ {
1220
+ _type: 'block',
1221
+ _key: 'k6',
1222
+ children: [
1223
+ {_type: 'span', _key: 'k7', text: 'Back to ordered', marks: []},
1224
+ ],
1225
+ markDefs: [],
1226
+ style: 'normal',
1227
+ listItem: 'number',
1228
+ level: 1,
1229
+ },
1230
+ ])
1231
+ })
1232
+
1233
+ test('mixed, deeply nested lists', () => {
1234
+ const keyGenerator = createTestKeyGenerator()
1235
+ const markdown = [
1236
+ '1. Ordered parent',
1237
+ ' - Unordered child',
1238
+ ' - Another unordered',
1239
+ ' 1. Back to ordered',
1240
+ ' 2. Still ordered',
1241
+ '2. Continue ordered parent',
1242
+ ].join('\n')
1243
+ const portableText = markdownToPortableText(markdown, {keyGenerator})
1244
+
1245
+ expect(
1246
+ getTersePt({
1247
+ schema: defaultSchema,
1248
+ value: portableText,
1249
+ }),
1250
+ ).toEqual([
1251
+ '>#:Ordered parent',
1252
+ '>>-:Unordered child',
1253
+ '>>-:Another unordered',
1254
+ '>>>#:Back to ordered',
1255
+ '>>>#:Still ordered',
1256
+ '>#:Continue ordered parent',
1257
+ ])
1258
+ })
1259
+ })
1260
+ })
1261
+
1262
+ /*********************
1263
+ * Objects
1264
+ *********************/
1265
+
1266
+ describe('block image', () => {
1267
+ test('default definition', () => {
1268
+ const keyGenerator = createTestKeyGenerator()
1269
+ expect(
1270
+ markdownToPortableText('![alt text](https://example.com/image.png)', {
1271
+ keyGenerator,
1272
+ }),
1273
+ ).toEqual([
1274
+ {
1275
+ _type: 'image',
1276
+ _key: 'k1',
1277
+ src: 'https://example.com/image.png',
1278
+ alt: 'alt text',
1279
+ },
1280
+ ])
1281
+ })
1282
+
1283
+ test('custom definition and matcher', () => {
1284
+ const keyGenerator = createTestKeyGenerator()
1285
+ expect(
1286
+ markdownToPortableText('![alt](https://example.com/pic.jpg)', {
1287
+ keyGenerator,
1288
+ schema: compileSchema(
1289
+ defineSchema({
1290
+ blockObjects: [
1291
+ {
1292
+ name: 'photo',
1293
+ fields: [
1294
+ {name: 'url', type: 'string'},
1295
+ {name: 'description', type: 'string'},
1296
+ ],
1297
+ },
1298
+ ],
1299
+ }),
1300
+ ),
1301
+ types: {
1302
+ image: ({context, value}) => ({
1303
+ _key: context.keyGenerator(),
1304
+ _type: 'photo',
1305
+ url: value.src,
1306
+ description: value.alt,
1307
+ }),
1308
+ },
1309
+ }),
1310
+ ).toEqual([
1311
+ {
1312
+ _type: 'photo',
1313
+ _key: 'k1',
1314
+ url: 'https://example.com/pic.jpg',
1315
+ description: 'alt',
1316
+ },
1317
+ ])
1318
+ })
1319
+
1320
+ test('no definition', () => {
1321
+ const keyGenerator = createTestKeyGenerator()
1322
+ expect(
1323
+ markdownToPortableText('![alt](https://example.com/image.png)', {
1324
+ keyGenerator,
1325
+ schema: compileSchema(defineSchema({})),
1326
+ }),
1327
+ ).toEqual([
1328
+ {
1329
+ _type: 'block',
1330
+ _key: 'k0',
1331
+ children: [
1332
+ {
1333
+ _type: 'span',
1334
+ _key: 'k1',
1335
+ text: '![alt](https://example.com/image.png)',
1336
+ marks: [],
1337
+ },
1338
+ ],
1339
+ markDefs: [],
1340
+ style: 'normal',
1341
+ },
1342
+ ])
1343
+ })
1344
+
1345
+ test('no `src` field', () => {
1346
+ const keyGenerator = createTestKeyGenerator()
1347
+ expect(
1348
+ markdownToPortableText('![alt](https://example.com/image.png)', {
1349
+ keyGenerator,
1350
+ schema: compileSchema(
1351
+ defineSchema({
1352
+ blockObjects: [
1353
+ {
1354
+ name: 'image',
1355
+ fields: [
1356
+ {name: 'asset', type: 'object'},
1357
+ {name: 'alt', type: 'string'},
1358
+ ],
1359
+ },
1360
+ ],
1361
+ }),
1362
+ ),
1363
+ }),
1364
+ ).toEqual([
1365
+ {
1366
+ _type: 'block',
1367
+ _key: 'k0',
1368
+ children: [
1369
+ {
1370
+ _type: 'span',
1371
+ _key: 'k2',
1372
+ text: '![alt](https://example.com/image.png)',
1373
+ marks: [],
1374
+ },
1375
+ ],
1376
+ markDefs: [],
1377
+ style: 'normal',
1378
+ },
1379
+ ])
1380
+ })
1381
+
1382
+ test('no matching fields', () => {
1383
+ const keyGenerator = createTestKeyGenerator()
1384
+ expect(
1385
+ markdownToPortableText('![alt](https://example.com/image.png)', {
1386
+ keyGenerator,
1387
+ schema: compileSchema(
1388
+ defineSchema({
1389
+ blockObjects: [
1390
+ {name: 'image', fields: [{name: 'asset', type: 'object'}]},
1391
+ ],
1392
+ }),
1393
+ ),
1394
+ }),
1395
+ ).toEqual([
1396
+ {
1397
+ _type: 'block',
1398
+ _key: 'k0',
1399
+ children: [
1400
+ {
1401
+ _type: 'span',
1402
+ _key: 'k2',
1403
+ text: '![alt](https://example.com/image.png)',
1404
+ marks: [],
1405
+ },
1406
+ ],
1407
+ markDefs: [],
1408
+ style: 'normal',
1409
+ },
1410
+ ])
1411
+ })
1412
+
1413
+ test('both block and inline images', () => {
1414
+ const keyGenerator = createTestKeyGenerator()
1415
+ const markdown = [
1416
+ '![block image](https://example.com/block.png)',
1417
+ '',
1418
+ 'Text with ![inline image](https://example.com/inline.png) in it',
1419
+ ].join('\n')
1420
+
1421
+ expect(
1422
+ markdownToPortableText(markdown, {
1423
+ keyGenerator,
1424
+ }),
1425
+ ).toEqual([
1426
+ {
1427
+ _type: 'image',
1428
+ _key: 'k1',
1429
+ src: 'https://example.com/block.png',
1430
+ alt: 'block image',
1431
+ },
1432
+ {
1433
+ _type: 'block',
1434
+ _key: 'k2',
1435
+ children: [
1436
+ {_type: 'span', _key: 'k3', text: 'Text with ', marks: []},
1437
+ {
1438
+ _type: 'image',
1439
+ _key: 'k4',
1440
+ src: 'https://example.com/inline.png',
1441
+ alt: 'inline image',
1442
+ },
1443
+ {_type: 'span', _key: 'k5', text: ' in it', marks: []},
1444
+ ],
1445
+ markDefs: [],
1446
+ style: 'normal',
1447
+ },
1448
+ ])
1449
+ })
1450
+ })
1451
+
1452
+ describe('block image with title', () => {
1453
+ test('default definition', () => {
1454
+ const keyGenerator = createTestKeyGenerator()
1455
+ expect(
1456
+ markdownToPortableText(
1457
+ '![alt text](https://example.com/image.png "Image Title")',
1458
+ {keyGenerator},
1459
+ ),
1460
+ ).toEqual([
1461
+ {
1462
+ _type: 'image',
1463
+ _key: 'k1',
1464
+ src: 'https://example.com/image.png',
1465
+ alt: 'alt text',
1466
+ title: 'Image Title',
1467
+ },
1468
+ ])
1469
+ })
1470
+ })
1471
+
1472
+ describe('inline image', () => {
1473
+ test('default definition', () => {
1474
+ const keyGenerator = createTestKeyGenerator()
1475
+ expect(
1476
+ markdownToPortableText(
1477
+ 'foo ![alt text](https://example.com/image.png) baz',
1478
+ {keyGenerator},
1479
+ ),
1480
+ ).toEqual([
1481
+ {
1482
+ _type: 'block',
1483
+ _key: 'k0',
1484
+ children: [
1485
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
1486
+ {
1487
+ _type: 'image',
1488
+ _key: 'k2',
1489
+ src: 'https://example.com/image.png',
1490
+ alt: 'alt text',
1491
+ },
1492
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
1493
+ ],
1494
+ markDefs: [],
1495
+ style: 'normal',
1496
+ },
1497
+ ])
1498
+ })
1499
+
1500
+ test('custom definition and matcher', () => {
1501
+ const keyGenerator = createTestKeyGenerator()
1502
+ expect(
1503
+ markdownToPortableText('foo ![alt](https://example.com/pic.jpg) baz', {
1504
+ keyGenerator,
1505
+ schema: compileSchema(
1506
+ defineSchema({
1507
+ inlineObjects: [
1508
+ {
1509
+ name: 'photo',
1510
+ fields: [
1511
+ {name: 'url', type: 'string'},
1512
+ {name: 'description', type: 'string'},
1513
+ ],
1514
+ },
1515
+ ],
1516
+ }),
1517
+ ),
1518
+ types: {
1519
+ image: ({context, value}) => ({
1520
+ _key: context.keyGenerator(),
1521
+ _type: 'photo',
1522
+ url: value.src,
1523
+ description: value.alt,
1524
+ }),
1525
+ },
1526
+ }),
1527
+ ).toEqual([
1528
+ {
1529
+ _type: 'block',
1530
+ _key: 'k0',
1531
+ children: [
1532
+ {_type: 'span', _key: 'k1', text: 'foo ', marks: []},
1533
+ {
1534
+ _type: 'photo',
1535
+ _key: 'k2',
1536
+ url: 'https://example.com/pic.jpg',
1537
+ description: 'alt',
1538
+ },
1539
+ {_type: 'span', _key: 'k3', text: ' baz', marks: []},
1540
+ ],
1541
+ markDefs: [],
1542
+ style: 'normal',
1543
+ },
1544
+ ])
1545
+ })
1546
+
1547
+ test('no definition', () => {
1548
+ const keyGenerator = createTestKeyGenerator()
1549
+ expect(
1550
+ markdownToPortableText(
1551
+ 'foo ![alt](https://example.com/image.png) baz',
1552
+ {
1553
+ keyGenerator,
1554
+ schema: compileSchema(defineSchema({})),
1555
+ },
1556
+ ),
1557
+ ).toEqual([
1558
+ {
1559
+ _type: 'block',
1560
+ _key: 'k0',
1561
+ children: [
1562
+ {
1563
+ _type: 'span',
1564
+ _key: 'k1',
1565
+ text: 'foo ![alt](https://example.com/image.png) baz',
1566
+ marks: [],
1567
+ },
1568
+ ],
1569
+ markDefs: [],
1570
+ style: 'normal',
1571
+ },
1572
+ ])
1573
+ })
1574
+
1575
+ test('only image block object definition', () => {
1576
+ const keyGenerator = createTestKeyGenerator()
1577
+ expect(
1578
+ markdownToPortableText(
1579
+ 'foo ![alt](https://example.com/image.png) baz',
1580
+ {
1581
+ keyGenerator,
1582
+ schema: compileSchema(
1583
+ defineSchema({
1584
+ blockObjects: [
1585
+ {
1586
+ name: 'image',
1587
+ fields: [
1588
+ {name: 'src', type: 'string'},
1589
+ {name: 'alt', type: 'string'},
1590
+ ],
1591
+ },
1592
+ ],
1593
+ }),
1594
+ ),
1595
+ },
1596
+ ),
1597
+ ).toEqual([
1598
+ {
1599
+ _type: 'block',
1600
+ _key: 'k0',
1601
+ children: [{_type: 'span', _key: 'k1', text: 'foo ', marks: []}],
1602
+ markDefs: [],
1603
+ style: 'normal',
1604
+ },
1605
+ {
1606
+ _type: 'image',
1607
+ _key: 'k2',
1608
+ src: 'https://example.com/image.png',
1609
+ alt: 'alt',
1610
+ },
1611
+ {
1612
+ _type: 'block',
1613
+ _key: 'k3',
1614
+ children: [{_type: 'span', _key: 'k4', text: ' baz', marks: []}],
1615
+ markDefs: [],
1616
+ style: 'normal',
1617
+ },
1618
+ ])
1619
+ })
1620
+ })
1621
+
1622
+ describe('horizontal rule', () => {
1623
+ test('default definition', () => {
1624
+ const keyGenerator = createTestKeyGenerator()
1625
+ expect(markdownToPortableText('---', {keyGenerator})).toEqual([
1626
+ {
1627
+ _type: 'horizontal-rule',
1628
+ _key: 'k0',
1629
+ },
1630
+ ])
1631
+ })
1632
+
1633
+ test('custom definition', () => {
1634
+ const keyGenerator = createTestKeyGenerator()
1635
+ expect(
1636
+ markdownToPortableText('---', {
1637
+ keyGenerator,
1638
+ schema: compileSchema(
1639
+ defineSchema({
1640
+ blockObjects: [
1641
+ {
1642
+ name: 'divider',
1643
+ fields: [{name: 'orientation', type: 'string'}],
1644
+ },
1645
+ ],
1646
+ }),
1647
+ ),
1648
+ types: {
1649
+ horizontalRule: ({context}) => ({
1650
+ _key: context.keyGenerator(),
1651
+ _type: 'divider',
1652
+ orientation: 'horizontal',
1653
+ }),
1654
+ },
1655
+ }),
1656
+ ).toEqual([
1657
+ {
1658
+ _type: 'divider',
1659
+ _key: 'k0',
1660
+ orientation: 'horizontal',
1661
+ },
1662
+ ])
1663
+ })
1664
+
1665
+ test('no definition', () => {
1666
+ const keyGenerator = createTestKeyGenerator()
1667
+ expect(
1668
+ markdownToPortableText('---', {
1669
+ keyGenerator,
1670
+ schema: compileSchema(defineSchema({})),
1671
+ }),
1672
+ ).toEqual([
1673
+ {
1674
+ _key: 'k0',
1675
+ _type: 'block',
1676
+ children: [
1677
+ {
1678
+ _key: 'k1',
1679
+ _type: 'span',
1680
+ text: '---',
1681
+ marks: [],
1682
+ },
1683
+ ],
1684
+ markDefs: [],
1685
+ style: 'normal',
1686
+ },
1687
+ ])
1688
+ })
1689
+ })
1690
+
1691
+ describe('code block', () => {
1692
+ describe('default definition', () => {
1693
+ test('one line', () => {
1694
+ const keyGenerator = createTestKeyGenerator()
1695
+ const markdown = ['```js', `const foo = 'bar'`, '```'].join('\n')
1696
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1697
+ {
1698
+ _type: 'code',
1699
+ _key: 'k0',
1700
+ code: `const foo = 'bar'`,
1701
+ language: 'js',
1702
+ },
1703
+ ])
1704
+ })
1705
+
1706
+ test('multiple lines', () => {
1707
+ const keyGenerator = createTestKeyGenerator()
1708
+ const markdown = [
1709
+ '```js',
1710
+ `const foo = 'bar'`,
1711
+ `const bar = 'baz'`,
1712
+ '```',
1713
+ ].join('\n')
1714
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1715
+ {
1716
+ _type: 'code',
1717
+ _key: 'k0',
1718
+ code: `const foo = 'bar'\nconst bar = 'baz'`,
1719
+ language: 'js',
1720
+ },
1721
+ ])
1722
+ })
1723
+ })
1724
+
1725
+ test('custom definition', () => {
1726
+ const keyGenerator = createTestKeyGenerator()
1727
+ const markdown = ['```js', `const foo = 'bar'`, '```'].join('\n')
1728
+ expect(
1729
+ markdownToPortableText(markdown, {
1730
+ keyGenerator,
1731
+ schema: compileSchema(
1732
+ defineSchema({
1733
+ blockObjects: [
1734
+ {
1735
+ name: 'kode',
1736
+ fields: [
1737
+ {
1738
+ name: 'sprog',
1739
+ type: 'string',
1740
+ },
1741
+ {
1742
+ name: 'indhold',
1743
+ type: 'string',
1744
+ },
1745
+ ],
1746
+ },
1747
+ ],
1748
+ }),
1749
+ ),
1750
+ types: {
1751
+ code: ({context, value}) => {
1752
+ const schemaDefinition = context.schema.blockObjects.find(
1753
+ (object) => object.name === 'kode',
1754
+ )
1755
+
1756
+ if (!schemaDefinition) {
1757
+ return undefined
1758
+ }
1759
+
1760
+ return {
1761
+ _type: schemaDefinition.name,
1762
+ _key: context.keyGenerator(),
1763
+ indhold: value.code,
1764
+ ...(value.language ? {sprog: value.language} : {}),
1765
+ }
1766
+ },
1767
+ },
1768
+ }),
1769
+ ).toEqual([
1770
+ {
1771
+ _type: 'kode',
1772
+ _key: 'k0',
1773
+ sprog: 'js',
1774
+ indhold: "const foo = 'bar'",
1775
+ },
1776
+ ])
1777
+ })
1778
+
1779
+ describe('no definition', () => {
1780
+ test('one line', () => {
1781
+ const keyGenerator = createTestKeyGenerator()
1782
+ const markdown = ['```js', `const foo = 'bar'`, '```'].join('\n')
1783
+ expect(
1784
+ markdownToPortableText(markdown, {
1785
+ keyGenerator,
1786
+ schema: compileSchema(defineSchema({})),
1787
+ }),
1788
+ ).toEqual([
1789
+ {
1790
+ _type: 'block',
1791
+ _key: 'k0',
1792
+ children: [
1793
+ {
1794
+ _type: 'span',
1795
+ _key: 'k1',
1796
+ text: "const foo = 'bar'",
1797
+ marks: [],
1798
+ },
1799
+ ],
1800
+ markDefs: [],
1801
+ style: 'normal',
1802
+ },
1803
+ ])
1804
+ })
1805
+
1806
+ test('multiple lines', () => {
1807
+ const keyGenerator = createTestKeyGenerator()
1808
+ const markdown = [
1809
+ '```js',
1810
+ `const foo = 'bar'`,
1811
+ `const bar = 'baz'`,
1812
+ '```',
1813
+ ].join('\n')
1814
+ expect(
1815
+ markdownToPortableText(markdown, {
1816
+ keyGenerator,
1817
+ schema: compileSchema(defineSchema({})),
1818
+ }),
1819
+ ).toEqual([
1820
+ {
1821
+ _type: 'code',
1822
+ _key: 'k0',
1823
+ code: `const foo = 'bar'\nconst bar = 'baz'`,
1824
+ },
1825
+ ])
1826
+ })
1827
+ })
1828
+
1829
+ test('some matching fields', () => {
1830
+ const keyGenerator = createTestKeyGenerator()
1831
+ const markdown = ['```js', `const foo = 'bar'`, '```'].join('\n')
1832
+ expect(
1833
+ markdownToPortableText(markdown, {
1834
+ keyGenerator,
1835
+ schema: compileSchema(
1836
+ defineSchema({
1837
+ blockObjects: [
1838
+ {name: 'code', fields: [{name: 'code', type: 'string'}]},
1839
+ ],
1840
+ }),
1841
+ ),
1842
+ }),
1843
+ ).toEqual([
1844
+ {
1845
+ _type: 'code',
1846
+ _key: 'k0',
1847
+ code: `const foo = 'bar'`,
1848
+ },
1849
+ ])
1850
+ })
1851
+
1852
+ test('no matching fields', () => {
1853
+ const markdown = ['```js', `const foo = 'bar'`, '```'].join('\n')
1854
+ const keyGenerator = createTestKeyGenerator()
1855
+ expect(
1856
+ markdownToPortableText(markdown, {
1857
+ keyGenerator,
1858
+ schema: compileSchema(
1859
+ defineSchema({
1860
+ blockObjects: [{name: 'code'}],
1861
+ }),
1862
+ ),
1863
+ }),
1864
+ ).toEqual([
1865
+ {
1866
+ _type: 'block',
1867
+ _key: 'k1',
1868
+ children: [
1869
+ {
1870
+ _type: 'span',
1871
+ _key: 'k2',
1872
+ text: "const foo = 'bar'",
1873
+ marks: [],
1874
+ },
1875
+ ],
1876
+ markDefs: [],
1877
+ style: 'normal',
1878
+ },
1879
+ ])
1880
+ })
1881
+
1882
+ test('indented code block', () => {
1883
+ const keyGenerator = createTestKeyGenerator()
1884
+ const markdown = ' const foo = "bar"'
1885
+ expect(markdownToPortableText(markdown, {keyGenerator})).toEqual([
1886
+ {
1887
+ _type: 'code',
1888
+ _key: 'k0',
1889
+ code: 'const foo = "bar"',
1890
+ },
1891
+ ])
1892
+ })
1893
+ })
1894
+
1895
+ describe('HTML', () => {
1896
+ describe('block HTML', () => {
1897
+ test('default definition', () => {
1898
+ const keyGenerator = createTestKeyGenerator()
1899
+ expect(
1900
+ markdownToPortableText('<div class="custom">Content</div>', {
1901
+ keyGenerator,
1902
+ }),
1903
+ ).toEqual([
1904
+ {
1905
+ _type: 'html',
1906
+ _key: 'k0',
1907
+ html: '<div class="custom">Content</div>',
1908
+ },
1909
+ ])
1910
+ })
1911
+
1912
+ test('custom definition', () => {
1913
+ const keyGenerator = createTestKeyGenerator()
1914
+ expect(
1915
+ markdownToPortableText('<div>Content</div>', {
1916
+ keyGenerator,
1917
+ schema: compileSchema(
1918
+ defineSchema({
1919
+ blockObjects: [
1920
+ {name: 'rawHtml', fields: [{name: 'code', type: 'string'}]},
1921
+ ],
1922
+ }),
1923
+ ),
1924
+ types: {
1925
+ html: ({context, value}) => ({
1926
+ _key: context.keyGenerator(),
1927
+ _type: 'rawHtml',
1928
+ code: value.html,
1929
+ }),
1930
+ },
1931
+ }),
1932
+ ).toEqual([
1933
+ {
1934
+ _type: 'rawHtml',
1935
+ _key: 'k0',
1936
+ code: '<div>Content</div>',
1937
+ },
1938
+ ])
1939
+ })
1940
+
1941
+ test('no definition', () => {
1942
+ const keyGenerator = createTestKeyGenerator()
1943
+ expect(
1944
+ markdownToPortableText('<div>Content</div>', {
1945
+ keyGenerator,
1946
+ schema: compileSchema(defineSchema({})),
1947
+ }),
1948
+ ).toEqual([
1949
+ {
1950
+ _key: 'k0',
1951
+ _type: 'block',
1952
+ children: [
1953
+ {
1954
+ _key: 'k1',
1955
+ _type: 'span',
1956
+ text: '<div>Content</div>',
1957
+ marks: [],
1958
+ },
1959
+ ],
1960
+ markDefs: [],
1961
+ style: 'normal',
1962
+ },
1963
+ ])
1964
+ })
1965
+ })
1966
+
1967
+ describe('inline HTML', () => {
1968
+ test('skip by default', () => {
1969
+ const keyGenerator = createTestKeyGenerator()
1970
+ expect(
1971
+ markdownToPortableText('foo <span>bar</span> baz', {keyGenerator}),
1972
+ ).toEqual([
1973
+ {
1974
+ _type: 'block',
1975
+ _key: 'k0',
1976
+ children: [
1977
+ {_type: 'span', _key: 'k1', text: 'foo bar baz', marks: []},
1978
+ ],
1979
+ markDefs: [],
1980
+ style: 'normal',
1981
+ },
1982
+ ])
1983
+ })
1984
+
1985
+ test('convert to text when configured', () => {
1986
+ const keyGenerator = createTestKeyGenerator()
1987
+ expect(
1988
+ markdownToPortableText('foo <span>bar</span> baz', {
1989
+ keyGenerator,
1990
+ html: {inline: 'text'},
1991
+ }),
1992
+ ).toEqual([
1993
+ {
1994
+ _type: 'block',
1995
+ _key: 'k0',
1996
+ children: [
1997
+ {
1998
+ _type: 'span',
1999
+ _key: 'k1',
2000
+ text: 'foo <span>bar</span> baz',
2001
+ marks: [],
2002
+ },
2003
+ ],
2004
+ markDefs: [],
2005
+ style: 'normal',
2006
+ },
2007
+ ])
2008
+ })
2009
+ })
2010
+ })
2011
+
2012
+ describe('tables', () => {
2013
+ const tableObjectDefinition = {
2014
+ name: 'table',
2015
+ fields: [
2016
+ {name: 'headerRows', type: 'number'},
2017
+ {name: 'rows', type: 'array'},
2018
+ ],
2019
+ } as const satisfies BlockObjectDefinition
2020
+
2021
+ const schemaWithTable = compileSchema(
2022
+ defineSchema({
2023
+ ...defaultSchema,
2024
+ blockObjects: [...defaultSchema.blockObjects, tableObjectDefinition],
2025
+ }),
2026
+ )
2027
+
2028
+ // Helper to get table options for tests
2029
+ const getTableTestOptions = (keyGenerator: () => string) => ({
2030
+ keyGenerator,
2031
+ schema: schemaWithTable,
2032
+ types: {
2033
+ table: buildObjectMatcher(tableObjectDefinition),
2034
+ },
2035
+ })
2036
+
2037
+ test('simple table', () => {
2038
+ const keyGenerator = createTestKeyGenerator()
2039
+ const markdown = [
2040
+ '| Header 1 | Header 2 |',
2041
+ '|----------|----------|',
2042
+ '| Cell 1 | Cell 2 |',
2043
+ '| Cell 3 | Cell 4 |',
2044
+ ].join('\n')
2045
+ expect(
2046
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2047
+ ).toEqual([
2048
+ {
2049
+ _type: 'table',
2050
+ _key: 'k21',
2051
+ headerRows: 1,
2052
+ rows: [
2053
+ {
2054
+ _key: 'k6',
2055
+ _type: 'row',
2056
+ cells: [
2057
+ {
2058
+ _type: 'cell',
2059
+ _key: 'k2',
2060
+ value: [
2061
+ {
2062
+ _type: 'block',
2063
+ _key: 'k0',
2064
+ style: 'normal',
2065
+ children: [
2066
+ {
2067
+ _type: 'span',
2068
+ _key: 'k1',
2069
+ text: 'Header 1',
2070
+ marks: [],
2071
+ },
2072
+ ],
2073
+ markDefs: [],
2074
+ },
2075
+ ],
2076
+ },
2077
+ {
2078
+ _type: 'cell',
2079
+ _key: 'k5',
2080
+ value: [
2081
+ {
2082
+ _type: 'block',
2083
+ _key: 'k3',
2084
+ style: 'normal',
2085
+ children: [
2086
+ {
2087
+ _type: 'span',
2088
+ _key: 'k4',
2089
+ text: 'Header 2',
2090
+ marks: [],
2091
+ },
2092
+ ],
2093
+ markDefs: [],
2094
+ },
2095
+ ],
2096
+ },
2097
+ ],
2098
+ },
2099
+ {
2100
+ _key: 'k13',
2101
+ _type: 'row',
2102
+ cells: [
2103
+ {
2104
+ _type: 'cell',
2105
+ _key: 'k9',
2106
+ value: [
2107
+ {
2108
+ _type: 'block',
2109
+ _key: 'k7',
2110
+ style: 'normal',
2111
+ children: [
2112
+ {
2113
+ _type: 'span',
2114
+ _key: 'k8',
2115
+ text: 'Cell 1',
2116
+ marks: [],
2117
+ },
2118
+ ],
2119
+ markDefs: [],
2120
+ },
2121
+ ],
2122
+ },
2123
+ {
2124
+ _type: 'cell',
2125
+ _key: 'k12',
2126
+ value: [
2127
+ {
2128
+ _type: 'block',
2129
+ _key: 'k10',
2130
+ style: 'normal',
2131
+ children: [
2132
+ {
2133
+ _type: 'span',
2134
+ _key: 'k11',
2135
+ text: 'Cell 2',
2136
+ marks: [],
2137
+ },
2138
+ ],
2139
+ markDefs: [],
2140
+ },
2141
+ ],
2142
+ },
2143
+ ],
2144
+ },
2145
+ {
2146
+ _key: 'k20',
2147
+ _type: 'row',
2148
+ cells: [
2149
+ {
2150
+ _type: 'cell',
2151
+ _key: 'k16',
2152
+ value: [
2153
+ {
2154
+ _type: 'block',
2155
+ _key: 'k14',
2156
+ style: 'normal',
2157
+ children: [
2158
+ {
2159
+ _type: 'span',
2160
+ _key: 'k15',
2161
+ text: 'Cell 3',
2162
+ marks: [],
2163
+ },
2164
+ ],
2165
+ markDefs: [],
2166
+ },
2167
+ ],
2168
+ },
2169
+ {
2170
+ _type: 'cell',
2171
+ _key: 'k19',
2172
+ value: [
2173
+ {
2174
+ _type: 'block',
2175
+ _key: 'k17',
2176
+ style: 'normal',
2177
+ children: [
2178
+ {
2179
+ _type: 'span',
2180
+ _key: 'k18',
2181
+ text: 'Cell 4',
2182
+ marks: [],
2183
+ },
2184
+ ],
2185
+ markDefs: [],
2186
+ },
2187
+ ],
2188
+ },
2189
+ ],
2190
+ },
2191
+ ],
2192
+ },
2193
+ ])
2194
+ })
2195
+
2196
+ test('table with formatting', () => {
2197
+ const keyGenerator = createTestKeyGenerator()
2198
+ const markdown = [
2199
+ '| **Header 1** | **Header 2** |',
2200
+ '|--------------|--------------|',
2201
+ '| *Cell 1* | *Cell 2* |',
2202
+ '| *Cell 3* | *Cell 4* |',
2203
+ ].join('\n')
2204
+ expect(
2205
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2206
+ ).toEqual([
2207
+ {
2208
+ _type: 'table',
2209
+ _key: 'k21',
2210
+ headerRows: 1,
2211
+ rows: [
2212
+ {
2213
+ _key: 'k6',
2214
+ _type: 'row',
2215
+ cells: [
2216
+ {
2217
+ _type: 'cell',
2218
+ _key: 'k2',
2219
+ value: [
2220
+ {
2221
+ _type: 'block',
2222
+ _key: 'k0',
2223
+ style: 'normal',
2224
+ children: [
2225
+ {
2226
+ _type: 'span',
2227
+ _key: 'k1',
2228
+ text: 'Header 1',
2229
+ marks: ['strong'],
2230
+ },
2231
+ ],
2232
+ markDefs: [],
2233
+ },
2234
+ ],
2235
+ },
2236
+ {
2237
+ _type: 'cell',
2238
+ _key: 'k5',
2239
+ value: [
2240
+ {
2241
+ _type: 'block',
2242
+ _key: 'k3',
2243
+ style: 'normal',
2244
+ children: [
2245
+ {
2246
+ _type: 'span',
2247
+ _key: 'k4',
2248
+ text: 'Header 2',
2249
+ marks: ['strong'],
2250
+ },
2251
+ ],
2252
+ markDefs: [],
2253
+ },
2254
+ ],
2255
+ },
2256
+ ],
2257
+ },
2258
+ {
2259
+ _key: 'k13',
2260
+ _type: 'row',
2261
+ cells: [
2262
+ {
2263
+ _type: 'cell',
2264
+ _key: 'k9',
2265
+ value: [
2266
+ {
2267
+ _type: 'block',
2268
+ _key: 'k7',
2269
+ style: 'normal',
2270
+ children: [
2271
+ {
2272
+ _type: 'span',
2273
+ _key: 'k8',
2274
+ text: 'Cell 1',
2275
+ marks: ['em'],
2276
+ },
2277
+ ],
2278
+ markDefs: [],
2279
+ },
2280
+ ],
2281
+ },
2282
+ {
2283
+ _type: 'cell',
2284
+ _key: 'k12',
2285
+ value: [
2286
+ {
2287
+ _type: 'block',
2288
+ _key: 'k10',
2289
+ style: 'normal',
2290
+ children: [
2291
+ {
2292
+ _type: 'span',
2293
+ _key: 'k11',
2294
+ text: 'Cell 2',
2295
+ marks: ['em'],
2296
+ },
2297
+ ],
2298
+ markDefs: [],
2299
+ },
2300
+ ],
2301
+ },
2302
+ ],
2303
+ },
2304
+ {
2305
+ _key: 'k20',
2306
+ _type: 'row',
2307
+ cells: [
2308
+ {
2309
+ _type: 'cell',
2310
+ _key: 'k16',
2311
+ value: [
2312
+ {
2313
+ _type: 'block',
2314
+ _key: 'k14',
2315
+ style: 'normal',
2316
+ children: [
2317
+ {
2318
+ _type: 'span',
2319
+ _key: 'k15',
2320
+ text: 'Cell 3',
2321
+ marks: ['em'],
2322
+ },
2323
+ ],
2324
+ markDefs: [],
2325
+ },
2326
+ ],
2327
+ },
2328
+ {
2329
+ _type: 'cell',
2330
+ _key: 'k19',
2331
+ value: [
2332
+ {
2333
+ _type: 'block',
2334
+ _key: 'k17',
2335
+ style: 'normal',
2336
+ children: [
2337
+ {
2338
+ _type: 'span',
2339
+ _key: 'k18',
2340
+ text: 'Cell 4',
2341
+ marks: ['em'],
2342
+ },
2343
+ ],
2344
+ markDefs: [],
2345
+ },
2346
+ ],
2347
+ },
2348
+ ],
2349
+ },
2350
+ ],
2351
+ },
2352
+ ])
2353
+ })
2354
+
2355
+ test('table with image', () => {
2356
+ const keyGenerator = createTestKeyGenerator()
2357
+ const markdown = [
2358
+ '| Block image | Inline image |',
2359
+ '| --- | --- |',
2360
+ '| ![Block image](https://example.com/block.png) | foo ![Inline image](https://example.com/inline.png) bar |',
2361
+ ].join('\n')
2362
+ expect(
2363
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2364
+ ).toEqual([
2365
+ {
2366
+ _type: 'table',
2367
+ _key: 'k16',
2368
+ headerRows: 1,
2369
+ rows: [
2370
+ {
2371
+ _key: 'k6',
2372
+ _type: 'row',
2373
+ cells: [
2374
+ {
2375
+ _type: 'cell',
2376
+ _key: 'k2',
2377
+ value: [
2378
+ {
2379
+ _type: 'block',
2380
+ _key: 'k0',
2381
+ children: [
2382
+ {
2383
+ _type: 'span',
2384
+ _key: 'k1',
2385
+ text: 'Block image',
2386
+ marks: [],
2387
+ },
2388
+ ],
2389
+ style: 'normal',
2390
+ markDefs: [],
2391
+ },
2392
+ ],
2393
+ },
2394
+ {
2395
+ _type: 'cell',
2396
+ _key: 'k5',
2397
+ value: [
2398
+ {
2399
+ _type: 'block',
2400
+ _key: 'k3',
2401
+ children: [
2402
+ {
2403
+ _type: 'span',
2404
+ _key: 'k4',
2405
+ text: 'Inline image',
2406
+ marks: [],
2407
+ },
2408
+ ],
2409
+ style: 'normal',
2410
+ markDefs: [],
2411
+ },
2412
+ ],
2413
+ },
2414
+ ],
2415
+ },
2416
+ {
2417
+ _key: 'k15',
2418
+ _type: 'row',
2419
+ cells: [
2420
+ {
2421
+ _type: 'cell',
2422
+ _key: 'k9',
2423
+ value: [
2424
+ {
2425
+ _type: 'image',
2426
+ _key: 'k8',
2427
+ src: 'https://example.com/block.png',
2428
+ alt: 'Block image',
2429
+ },
2430
+ ],
2431
+ },
2432
+ {
2433
+ _type: 'cell',
2434
+ _key: 'k14',
2435
+ value: [
2436
+ {
2437
+ _type: 'block',
2438
+ _key: 'k10',
2439
+ children: [
2440
+ {
2441
+ _key: 'k11',
2442
+ _type: 'span',
2443
+ text: 'foo ',
2444
+ marks: [],
2445
+ },
2446
+ {
2447
+ _key: 'k12',
2448
+ _type: 'image',
2449
+ src: 'https://example.com/inline.png',
2450
+ alt: 'Inline image',
2451
+ },
2452
+ {
2453
+ _key: 'k13',
2454
+ _type: 'span',
2455
+ text: ' bar',
2456
+ marks: [],
2457
+ },
2458
+ ],
2459
+ style: 'normal',
2460
+ markDefs: [],
2461
+ },
2462
+ ],
2463
+ },
2464
+ ],
2465
+ },
2466
+ ],
2467
+ },
2468
+ ])
2469
+ })
2470
+
2471
+ test('table with images without inline image support', () => {
2472
+ const keyGenerator = createTestKeyGenerator()
2473
+ const markdown = [
2474
+ '| Block image | Inline image |',
2475
+ '| --- | --- |',
2476
+ '| ![Block image](https://example.com/block.png) | foo ![Inline image](https://example.com/inline.png) bar |',
2477
+ ].join('\n')
2478
+
2479
+ const schema = compileSchema(
2480
+ defineSchema({
2481
+ blockObjects: [
2482
+ {
2483
+ name: 'image',
2484
+ fields: [
2485
+ {name: 'src', type: 'string'},
2486
+ {name: 'alt', type: 'string'},
2487
+ ],
2488
+ },
2489
+ tableObjectDefinition,
2490
+ ],
2491
+ }),
2492
+ )
2493
+
2494
+ expect(
2495
+ markdownToPortableText(markdown, {
2496
+ keyGenerator,
2497
+ schema,
2498
+ types: {
2499
+ table: buildObjectMatcher(tableObjectDefinition),
2500
+ },
2501
+ }),
2502
+ ).toEqual([
2503
+ {
2504
+ _type: 'table',
2505
+ _key: 'k16',
2506
+ headerRows: 1,
2507
+ rows: [
2508
+ {
2509
+ _key: 'k6',
2510
+ _type: 'row',
2511
+ cells: [
2512
+ {
2513
+ _type: 'cell',
2514
+ _key: 'k2',
2515
+ value: [
2516
+ {
2517
+ _type: 'block',
2518
+ _key: 'k0',
2519
+ children: [
2520
+ {
2521
+ _type: 'span',
2522
+ _key: 'k1',
2523
+ text: 'Block image',
2524
+ marks: [],
2525
+ },
2526
+ ],
2527
+ style: 'normal',
2528
+ markDefs: [],
2529
+ },
2530
+ ],
2531
+ },
2532
+ {
2533
+ _type: 'cell',
2534
+ _key: 'k5',
2535
+ value: [
2536
+ {
2537
+ _type: 'block',
2538
+ _key: 'k3',
2539
+ children: [
2540
+ {
2541
+ _type: 'span',
2542
+ _key: 'k4',
2543
+ text: 'Inline image',
2544
+ marks: [],
2545
+ },
2546
+ ],
2547
+ style: 'normal',
2548
+ markDefs: [],
2549
+ },
2550
+ ],
2551
+ },
2552
+ ],
2553
+ },
2554
+ {
2555
+ _key: 'k15',
2556
+ _type: 'row',
2557
+ cells: [
2558
+ {
2559
+ _type: 'cell',
2560
+ _key: 'k9',
2561
+ value: [
2562
+ {
2563
+ _type: 'image',
2564
+ _key: 'k8',
2565
+ src: 'https://example.com/block.png',
2566
+ alt: 'Block image',
2567
+ },
2568
+ ],
2569
+ },
2570
+ {
2571
+ _type: 'cell',
2572
+ _key: 'k14',
2573
+ value: [
2574
+ {
2575
+ _type: 'block',
2576
+ _key: 'k10',
2577
+ children: [
2578
+ {
2579
+ _key: 'k11',
2580
+ _type: 'span',
2581
+ text: 'foo ',
2582
+ marks: [],
2583
+ },
2584
+ {
2585
+ _key: 'k12',
2586
+ _type: 'image',
2587
+ src: 'https://example.com/inline.png',
2588
+ alt: 'Inline image',
2589
+ },
2590
+ {
2591
+ _key: 'k13',
2592
+ _type: 'span',
2593
+ text: ' bar',
2594
+ marks: [],
2595
+ },
2596
+ ],
2597
+ style: 'normal',
2598
+ markDefs: [],
2599
+ },
2600
+ ],
2601
+ },
2602
+ ],
2603
+ },
2604
+ ],
2605
+ },
2606
+ ])
2607
+ })
2608
+
2609
+ test('table with empty cells', () => {
2610
+ const keyGenerator = createTestKeyGenerator()
2611
+ const markdown = ['| A | | C |', '|---|---|---|', '| 1 | | 3 |'].join(
2612
+ '\n',
2613
+ )
2614
+ expect(
2615
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2616
+ ).toEqual([
2617
+ {
2618
+ _type: 'table',
2619
+ _key: 'k20',
2620
+ headerRows: 1,
2621
+ rows: [
2622
+ {
2623
+ _key: 'k9',
2624
+ _type: 'row',
2625
+ cells: [
2626
+ {
2627
+ _type: 'cell',
2628
+ _key: 'k2',
2629
+ value: [
2630
+ {
2631
+ _type: 'block',
2632
+ _key: 'k0',
2633
+ style: 'normal',
2634
+ children: [
2635
+ {
2636
+ _type: 'span',
2637
+ _key: 'k1',
2638
+ text: 'A',
2639
+ marks: [],
2640
+ },
2641
+ ],
2642
+ markDefs: [],
2643
+ },
2644
+ ],
2645
+ },
2646
+ {
2647
+ _type: 'cell',
2648
+ _key: 'k5',
2649
+ value: [
2650
+ {
2651
+ _type: 'block',
2652
+ _key: 'k3',
2653
+ style: 'normal',
2654
+ children: [
2655
+ {
2656
+ _type: 'span',
2657
+ _key: 'k4',
2658
+ text: '',
2659
+ marks: [],
2660
+ },
2661
+ ],
2662
+ markDefs: [],
2663
+ },
2664
+ ],
2665
+ },
2666
+ {
2667
+ _type: 'cell',
2668
+ _key: 'k8',
2669
+ value: [
2670
+ {
2671
+ _type: 'block',
2672
+ _key: 'k6',
2673
+ style: 'normal',
2674
+ children: [
2675
+ {
2676
+ _type: 'span',
2677
+ _key: 'k7',
2678
+ text: 'C',
2679
+ marks: [],
2680
+ },
2681
+ ],
2682
+ markDefs: [],
2683
+ },
2684
+ ],
2685
+ },
2686
+ ],
2687
+ },
2688
+ {
2689
+ _key: 'k19',
2690
+ _type: 'row',
2691
+ cells: [
2692
+ {
2693
+ _type: 'cell',
2694
+ _key: 'k12',
2695
+ value: [
2696
+ {
2697
+ _type: 'block',
2698
+ _key: 'k10',
2699
+ style: 'normal',
2700
+ children: [
2701
+ {
2702
+ _type: 'span',
2703
+ _key: 'k11',
2704
+ text: '1',
2705
+ marks: [],
2706
+ },
2707
+ ],
2708
+ markDefs: [],
2709
+ },
2710
+ ],
2711
+ },
2712
+ {
2713
+ _type: 'cell',
2714
+ _key: 'k15',
2715
+ value: [
2716
+ {
2717
+ _type: 'block',
2718
+ _key: 'k13',
2719
+ style: 'normal',
2720
+ children: [
2721
+ {
2722
+ _type: 'span',
2723
+ _key: 'k14',
2724
+ text: '',
2725
+ marks: [],
2726
+ },
2727
+ ],
2728
+ markDefs: [],
2729
+ },
2730
+ ],
2731
+ },
2732
+ {
2733
+ _type: 'cell',
2734
+ _key: 'k18',
2735
+ value: [
2736
+ {
2737
+ _type: 'block',
2738
+ _key: 'k16',
2739
+ style: 'normal',
2740
+ children: [
2741
+ {
2742
+ _type: 'span',
2743
+ _key: 'k17',
2744
+ text: '3',
2745
+ marks: [],
2746
+ },
2747
+ ],
2748
+ markDefs: [],
2749
+ },
2750
+ ],
2751
+ },
2752
+ ],
2753
+ },
2754
+ ],
2755
+ },
2756
+ ])
2757
+ })
2758
+
2759
+ test('table with links', () => {
2760
+ const keyGenerator = createTestKeyGenerator()
2761
+ const markdown = [
2762
+ '| Link |',
2763
+ '| --- |',
2764
+ '| [Example](https://example.com) |',
2765
+ ].join('\n')
2766
+ expect(
2767
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2768
+ ).toEqual([
2769
+ {
2770
+ _type: 'table',
2771
+ _key: 'k9',
2772
+ headerRows: 1,
2773
+ rows: [
2774
+ {
2775
+ _key: 'k3',
2776
+ _type: 'row',
2777
+ cells: [
2778
+ {
2779
+ _type: 'cell',
2780
+ _key: 'k2',
2781
+ value: [
2782
+ {
2783
+ _type: 'block',
2784
+ _key: 'k0',
2785
+ style: 'normal',
2786
+ children: [
2787
+ {
2788
+ _type: 'span',
2789
+ _key: 'k1',
2790
+ text: 'Link',
2791
+ marks: [],
2792
+ },
2793
+ ],
2794
+ markDefs: [],
2795
+ },
2796
+ ],
2797
+ },
2798
+ ],
2799
+ },
2800
+ {
2801
+ _key: 'k8',
2802
+ _type: 'row',
2803
+ cells: [
2804
+ {
2805
+ _type: 'cell',
2806
+ _key: 'k7',
2807
+ value: [
2808
+ {
2809
+ _type: 'block',
2810
+ _key: 'k4',
2811
+ style: 'normal',
2812
+ children: [
2813
+ {
2814
+ _type: 'span',
2815
+ _key: 'k6',
2816
+ text: 'Example',
2817
+ marks: ['k5'],
2818
+ },
2819
+ ],
2820
+ markDefs: [
2821
+ {
2822
+ _type: 'link',
2823
+ _key: 'k5',
2824
+ href: 'https://example.com',
2825
+ },
2826
+ ],
2827
+ },
2828
+ ],
2829
+ },
2830
+ ],
2831
+ },
2832
+ ],
2833
+ },
2834
+ ])
2835
+ })
2836
+
2837
+ test('table with inline code', () => {
2838
+ const keyGenerator = createTestKeyGenerator()
2839
+ const markdown = ['| Code |', '| --- |', '| `const x = 1` |'].join('\n')
2840
+ expect(
2841
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2842
+ ).toEqual([
2843
+ {
2844
+ _type: 'table',
2845
+ _key: 'k8',
2846
+ headerRows: 1,
2847
+ rows: [
2848
+ {
2849
+ _key: 'k3',
2850
+ _type: 'row',
2851
+ cells: [
2852
+ {
2853
+ _type: 'cell',
2854
+ _key: 'k2',
2855
+ value: [
2856
+ {
2857
+ _type: 'block',
2858
+ _key: 'k0',
2859
+ style: 'normal',
2860
+ children: [
2861
+ {
2862
+ _type: 'span',
2863
+ _key: 'k1',
2864
+ text: 'Code',
2865
+ marks: [],
2866
+ },
2867
+ ],
2868
+ markDefs: [],
2869
+ },
2870
+ ],
2871
+ },
2872
+ ],
2873
+ },
2874
+ {
2875
+ _key: 'k7',
2876
+ _type: 'row',
2877
+ cells: [
2878
+ {
2879
+ _type: 'cell',
2880
+ _key: 'k6',
2881
+ value: [
2882
+ {
2883
+ _type: 'block',
2884
+ _key: 'k4',
2885
+ style: 'normal',
2886
+ children: [
2887
+ {
2888
+ _type: 'span',
2889
+ _key: 'k5',
2890
+ text: 'const x = 1',
2891
+ marks: ['code'],
2892
+ },
2893
+ ],
2894
+ markDefs: [],
2895
+ },
2896
+ ],
2897
+ },
2898
+ ],
2899
+ },
2900
+ ],
2901
+ },
2902
+ ])
2903
+ })
2904
+
2905
+ test('table with mixed formatting', () => {
2906
+ const keyGenerator = createTestKeyGenerator()
2907
+ const markdown = [
2908
+ '| Mixed |',
2909
+ '| --- |',
2910
+ '| **bold** and *italic* and [link](https://example.com) |',
2911
+ ].join('\n')
2912
+ expect(
2913
+ markdownToPortableText(markdown, getTableTestOptions(keyGenerator)),
2914
+ ).toEqual([
2915
+ {
2916
+ _type: 'table',
2917
+ _key: 'k13',
2918
+ headerRows: 1,
2919
+ rows: [
2920
+ {
2921
+ _key: 'k3',
2922
+ _type: 'row',
2923
+ cells: [
2924
+ {
2925
+ _type: 'cell',
2926
+ _key: 'k2',
2927
+ value: [
2928
+ {
2929
+ _type: 'block',
2930
+ _key: 'k0',
2931
+ style: 'normal',
2932
+ children: [
2933
+ {
2934
+ _type: 'span',
2935
+ _key: 'k1',
2936
+ text: 'Mixed',
2937
+ marks: [],
2938
+ },
2939
+ ],
2940
+ markDefs: [],
2941
+ },
2942
+ ],
2943
+ },
2944
+ ],
2945
+ },
2946
+ {
2947
+ _key: 'k12',
2948
+ _type: 'row',
2949
+ cells: [
2950
+ {
2951
+ _type: 'cell',
2952
+ _key: 'k11',
2953
+ value: [
2954
+ {
2955
+ _type: 'block',
2956
+ _key: 'k4',
2957
+ style: 'normal',
2958
+ children: [
2959
+ {
2960
+ _type: 'span',
2961
+ _key: 'k5',
2962
+ text: 'bold',
2963
+ marks: ['strong'],
2964
+ },
2965
+ {
2966
+ _type: 'span',
2967
+ _key: 'k6',
2968
+ text: ' and ',
2969
+ marks: [],
2970
+ },
2971
+ {
2972
+ _type: 'span',
2973
+ _key: 'k7',
2974
+ text: 'italic',
2975
+ marks: ['em'],
2976
+ },
2977
+ {
2978
+ _type: 'span',
2979
+ _key: 'k8',
2980
+ text: ' and ',
2981
+ marks: [],
2982
+ },
2983
+ {
2984
+ _type: 'span',
2985
+ _key: 'k10',
2986
+ text: 'link',
2987
+ marks: ['k9'],
2988
+ },
2989
+ ],
2990
+ markDefs: [
2991
+ {
2992
+ _type: 'link',
2993
+ _key: 'k9',
2994
+ href: 'https://example.com',
2995
+ },
2996
+ ],
2997
+ },
2998
+ ],
2999
+ },
3000
+ ],
3001
+ },
3002
+ ],
3003
+ },
3004
+ ])
3005
+ })
3006
+
3007
+ test('custom table definition', () => {
3008
+ const keyGenerator = createTestKeyGenerator()
3009
+ const markdown = ['| A | B |', '|---|---|', '| 1 | 2 |'].join('\n')
3010
+ expect(
3011
+ markdownToPortableText(markdown, {
3012
+ keyGenerator,
3013
+ schema: compileSchema(
3014
+ defineSchema({
3015
+ blockObjects: [
3016
+ {name: 'dataTable', fields: [{name: 'data', type: 'array'}]},
3017
+ ],
3018
+ }),
3019
+ ),
3020
+ types: {
3021
+ table: ({context, value}) => ({
3022
+ _key: context.keyGenerator(),
3023
+ _type: 'dataTable',
3024
+ data: value.rows,
3025
+ }),
3026
+ },
3027
+ }),
3028
+ ).toEqual([
3029
+ {
3030
+ _type: 'dataTable',
3031
+ _key: 'k14',
3032
+ data: [
3033
+ {
3034
+ _key: 'k6',
3035
+ _type: 'row',
3036
+ cells: [
3037
+ {
3038
+ _type: 'cell',
3039
+ _key: 'k2',
3040
+ value: [
3041
+ {
3042
+ _type: 'block',
3043
+ _key: 'k0',
3044
+ style: 'normal',
3045
+ children: [
3046
+ {
3047
+ _type: 'span',
3048
+ _key: 'k1',
3049
+ text: 'A',
3050
+ marks: [],
3051
+ },
3052
+ ],
3053
+ markDefs: [],
3054
+ },
3055
+ ],
3056
+ },
3057
+ {
3058
+ _type: 'cell',
3059
+ _key: 'k5',
3060
+ value: [
3061
+ {
3062
+ _type: 'block',
3063
+ _key: 'k3',
3064
+ style: 'normal',
3065
+ children: [
3066
+ {
3067
+ _type: 'span',
3068
+ _key: 'k4',
3069
+ text: 'B',
3070
+ marks: [],
3071
+ },
3072
+ ],
3073
+ markDefs: [],
3074
+ },
3075
+ ],
3076
+ },
3077
+ ],
3078
+ },
3079
+ {
3080
+ _key: 'k13',
3081
+ _type: 'row',
3082
+ cells: [
3083
+ {
3084
+ _type: 'cell',
3085
+ _key: 'k9',
3086
+ value: [
3087
+ {
3088
+ _type: 'block',
3089
+ _key: 'k7',
3090
+ style: 'normal',
3091
+ children: [
3092
+ {
3093
+ _type: 'span',
3094
+ _key: 'k8',
3095
+ text: '1',
3096
+ marks: [],
3097
+ },
3098
+ ],
3099
+ markDefs: [],
3100
+ },
3101
+ ],
3102
+ },
3103
+ {
3104
+ _type: 'cell',
3105
+ _key: 'k12',
3106
+ value: [
3107
+ {
3108
+ _type: 'block',
3109
+ _key: 'k10',
3110
+ style: 'normal',
3111
+ children: [
3112
+ {
3113
+ _type: 'span',
3114
+ _key: 'k11',
3115
+ text: '2',
3116
+ marks: [],
3117
+ },
3118
+ ],
3119
+ markDefs: [],
3120
+ },
3121
+ ],
3122
+ },
3123
+ ],
3124
+ },
3125
+ ],
3126
+ },
3127
+ ])
3128
+ })
3129
+
3130
+ test('no table matcher', () => {
3131
+ const keyGenerator = createTestKeyGenerator()
3132
+ const markdown = ['| A | B |', '|---|---|', '| 1 | 2 |'].join('\n')
3133
+ expect(
3134
+ markdownToPortableText(markdown, {
3135
+ keyGenerator,
3136
+ }),
3137
+ ).toEqual([
3138
+ {
3139
+ _type: 'block',
3140
+ _key: 'k0',
3141
+ style: 'normal',
3142
+ children: [
3143
+ {
3144
+ _type: 'span',
3145
+ _key: 'k1',
3146
+ text: 'A',
3147
+ marks: [],
3148
+ },
3149
+ ],
3150
+ markDefs: [],
3151
+ },
3152
+ {
3153
+ _type: 'block',
3154
+ _key: 'k3',
3155
+ style: 'normal',
3156
+ children: [
3157
+ {
3158
+ _type: 'span',
3159
+ _key: 'k4',
3160
+ text: 'B',
3161
+ marks: [],
3162
+ },
3163
+ ],
3164
+ markDefs: [],
3165
+ },
3166
+ {
3167
+ _type: 'block',
3168
+ _key: 'k7',
3169
+ style: 'normal',
3170
+ children: [
3171
+ {
3172
+ _type: 'span',
3173
+ _key: 'k8',
3174
+ text: '1',
3175
+ marks: [],
3176
+ },
3177
+ ],
3178
+ markDefs: [],
3179
+ },
3180
+ {
3181
+ _type: 'block',
3182
+ _key: 'k10',
3183
+ style: 'normal',
3184
+ children: [
3185
+ {
3186
+ _type: 'span',
3187
+ _key: 'k11',
3188
+ text: '2',
3189
+ marks: [],
3190
+ },
3191
+ ],
3192
+ markDefs: [],
3193
+ },
3194
+ ])
3195
+ })
3196
+
3197
+ test('no table definition with formatting', () => {
3198
+ const keyGenerator = createTestKeyGenerator()
3199
+ const markdown = [
3200
+ '| **Bold** | _Italic_ |',
3201
+ '| -------- | -------- |',
3202
+ '| `Code` | Normal |',
3203
+ ].join('\n')
3204
+ expect(
3205
+ markdownToPortableText(markdown, {
3206
+ keyGenerator,
3207
+ schema: compileSchema(
3208
+ defineSchema({
3209
+ decorators: [{name: 'strong'}, {name: 'em'}, {name: 'code'}],
3210
+ }),
3211
+ ),
3212
+ }),
3213
+ ).toEqual([
3214
+ {
3215
+ _type: 'block',
3216
+ _key: 'k0',
3217
+ style: 'normal',
3218
+ children: [
3219
+ {
3220
+ _type: 'span',
3221
+ _key: 'k1',
3222
+ text: 'Bold',
3223
+ marks: ['strong'],
3224
+ },
3225
+ ],
3226
+ markDefs: [],
3227
+ },
3228
+ {
3229
+ _type: 'block',
3230
+ _key: 'k3',
3231
+ style: 'normal',
3232
+ children: [
3233
+ {
3234
+ _type: 'span',
3235
+ _key: 'k4',
3236
+ text: 'Italic',
3237
+ marks: ['em'],
3238
+ },
3239
+ ],
3240
+ markDefs: [],
3241
+ },
3242
+ {
3243
+ _type: 'block',
3244
+ _key: 'k7',
3245
+ style: 'normal',
3246
+ children: [
3247
+ {
3248
+ _type: 'span',
3249
+ _key: 'k8',
3250
+ text: 'Code',
3251
+ marks: ['code'],
3252
+ },
3253
+ ],
3254
+ markDefs: [],
3255
+ },
3256
+ {
3257
+ _type: 'block',
3258
+ _key: 'k10',
3259
+ style: 'normal',
3260
+ children: [
3261
+ {
3262
+ _type: 'span',
3263
+ _key: 'k11',
3264
+ text: 'Normal',
3265
+ marks: [],
3266
+ },
3267
+ ],
3268
+ markDefs: [],
3269
+ },
3270
+ ])
3271
+ })
3272
+ })
3273
+ })