@tinacms/mdx 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -8,14 +8,15 @@ var __publicField = (obj, key, value) => {
8
8
  // src/parse/index.ts
9
9
  import { remark } from "remark";
10
10
  import remarkMdx from "remark-mdx";
11
+ import { fromMarkdown } from "mdast-util-from-markdown";
11
12
 
12
13
  // src/parse/remarkToPlate.ts
13
14
  import { flatten } from "lodash-es";
14
15
 
15
16
  // src/parse/acorn.ts
16
- var extractAttributes = (attributes, fields, imageCallback) => {
17
+ var extractAttributes = (attributes2, fields, imageCallback) => {
17
18
  const properties = {};
18
- attributes.forEach((attribute) => {
19
+ attributes2?.forEach((attribute) => {
19
20
  assertType(attribute, "mdxJsxAttribute");
20
21
  const field = fields.find((field2) => field2.name === attribute.name);
21
22
  if (!field) {
@@ -46,8 +47,8 @@ var extractAttribute = (attribute, field, imageCallback) => {
46
47
  }
47
48
  case "image":
48
49
  if (field.list) {
49
- const values = extractScalar(extractExpression(attribute), field);
50
- return values.split(",").map((value) => imageCallback(value));
50
+ const values2 = extractScalar(extractExpression(attribute), field);
51
+ return values2.split(",").map((value) => imageCallback(value));
51
52
  } else {
52
53
  const value = extractString(attribute, field);
53
54
  return imageCallback(value);
@@ -99,7 +100,7 @@ var extractObject = (attribute, field) => {
99
100
  };
100
101
  var extractObjectExpression = (expression, field) => {
101
102
  const properties = {};
102
- expression.properties.forEach((property) => {
103
+ expression.properties?.forEach((property) => {
103
104
  assertType(property, "Property");
104
105
  const { key, value } = extractKeyValue(property, field);
105
106
  properties[key] = value;
@@ -204,114 +205,942 @@ var trimFragments = (string) => {
204
205
  return value;
205
206
  };
206
207
 
207
- // src/parse/mdx.ts
208
+ // src/stringify/index.ts
208
209
  import { toMarkdown } from "mdast-util-to-markdown";
209
- import { mdxJsxToMarkdown } from "mdast-util-mdx-jsx";
210
- function mdxJsxElement(node, field, imageCallback) {
211
- try {
212
- const template = field.templates?.find((template2) => {
213
- const templateName = typeof template2 === "string" ? template2 : template2.name;
214
- return templateName === node.name;
210
+ import { text as text2 } from "mdast-util-to-markdown/lib/handle/text";
211
+ import {
212
+ mdxJsxToMarkdown
213
+ } from "mdast-util-mdx-jsx";
214
+
215
+ // src/stringify/acorn.ts
216
+ import { format } from "prettier";
217
+ var stringifyPropsInline = (element, field, imageCallback) => {
218
+ return stringifyProps(element, field, true, imageCallback);
219
+ };
220
+ function stringifyProps(element, parentField, flatten2, imageCallback) {
221
+ const attributes2 = [];
222
+ const children = [];
223
+ let template;
224
+ let useDirective = false;
225
+ let directiveType = "leaf";
226
+ template = parentField.templates?.find((template2) => {
227
+ if (typeof template2 === "string") {
228
+ throw new Error("Global templates not supported");
229
+ }
230
+ return template2.name === element.name;
231
+ });
232
+ if (!template) {
233
+ template = parentField.templates?.find((template2) => {
234
+ const templateName = template2?.match?.name;
235
+ return templateName === element.name;
215
236
  });
237
+ }
238
+ if (!template || typeof template === "string") {
239
+ throw new Error(`Unable to find template for JSX element ${element.name}`);
240
+ }
241
+ if (template.fields.find((f) => f.name === "children")) {
242
+ directiveType = "block";
243
+ }
244
+ useDirective = !!template.match;
245
+ Object.entries(element.props).forEach(([name, value]) => {
216
246
  if (typeof template === "string") {
217
- throw new Error("Global templates not yet supported");
218
- }
219
- if (!template) {
220
- const string = toMarkdown({ type: "root", children: [node] }, {
221
- extensions: [mdxJsxToMarkdown()],
222
- listItemIndent: "one"
223
- });
224
- return {
225
- type: node.type === "mdxJsxFlowElement" ? "html" : "html_inline",
226
- value: string.trim(),
227
- children: [{ type: "text", text: "" }]
228
- };
247
+ throw new Error(`Unable to find template for JSX element ${name}`);
229
248
  }
230
- const props = extractAttributes(node.attributes, template.fields, imageCallback);
231
- const childField = template.fields.find((field2) => field2.name === "children");
232
- if (childField) {
233
- if (childField.type === "rich-text") {
234
- props.children = remarkToSlate(node, childField, imageCallback);
249
+ const field = template?.fields?.find((field2) => field2.name === name);
250
+ if (!field) {
251
+ if (name === "children") {
252
+ return;
235
253
  }
254
+ return;
236
255
  }
237
- return {
238
- type: node.type,
239
- name: node.name,
240
- children: [{ type: "text", text: "" }],
241
- props
242
- };
243
- } catch (e) {
244
- if (e instanceof Error) {
245
- throw new RichTextParseError(e.message, node.position);
246
- }
247
- throw e;
248
- }
249
- }
250
-
251
- // src/parse/remarkToPlate.ts
252
- var remarkToSlate = (root, field, imageCallback) => {
253
- const content = (content2) => {
254
- switch (content2.type) {
255
- case "blockquote":
256
- const children = [];
257
- content2.children.map((child) => {
258
- const inlineElements = unwrapBlockContent(child);
259
- inlineElements.forEach((child2) => {
260
- children.push(child2);
256
+ switch (field.type) {
257
+ case "reference":
258
+ if (field.list) {
259
+ if (Array.isArray(value)) {
260
+ attributes2.push({
261
+ type: "mdxJsxAttribute",
262
+ name,
263
+ value: {
264
+ type: "mdxJsxAttributeValueExpression",
265
+ value: `[${value.map((item) => `"${item}"`).join(", ")}]`
266
+ }
267
+ });
268
+ }
269
+ } else {
270
+ if (typeof value === "string") {
271
+ attributes2.push({
272
+ type: "mdxJsxAttribute",
273
+ name,
274
+ value
275
+ });
276
+ }
277
+ }
278
+ break;
279
+ case "datetime":
280
+ case "string":
281
+ if (field.list) {
282
+ if (Array.isArray(value)) {
283
+ attributes2.push({
284
+ type: "mdxJsxAttribute",
285
+ name,
286
+ value: {
287
+ type: "mdxJsxAttributeValueExpression",
288
+ value: `[${value.map((item) => `"${item}"`).join(", ")}]`
289
+ }
290
+ });
291
+ }
292
+ } else {
293
+ if (typeof value === "string") {
294
+ attributes2.push({
295
+ type: "mdxJsxAttribute",
296
+ name,
297
+ value
298
+ });
299
+ } else {
300
+ throw new Error(`Expected string for attribute on field ${field.name}`);
301
+ }
302
+ }
303
+ break;
304
+ case "image":
305
+ if (field.list) {
306
+ if (Array.isArray(value)) {
307
+ attributes2.push({
308
+ type: "mdxJsxAttribute",
309
+ name,
310
+ value: {
311
+ type: "mdxJsxAttributeValueExpression",
312
+ value: `[${value.map((item) => `"${imageCallback(item)}"`).join(", ")}]`
313
+ }
314
+ });
315
+ }
316
+ } else {
317
+ attributes2.push({
318
+ type: "mdxJsxAttribute",
319
+ name,
320
+ value: imageCallback(String(value))
261
321
  });
322
+ }
323
+ break;
324
+ case "number":
325
+ case "boolean":
326
+ if (field.list) {
327
+ if (Array.isArray(value)) {
328
+ attributes2.push({
329
+ type: "mdxJsxAttribute",
330
+ name,
331
+ value: {
332
+ type: "mdxJsxAttributeValueExpression",
333
+ value: `[${value.map((item) => `${item}`).join(", ")}]`
334
+ }
335
+ });
336
+ }
337
+ } else {
338
+ attributes2.push({
339
+ type: "mdxJsxAttribute",
340
+ name,
341
+ value: {
342
+ type: "mdxJsxAttributeValueExpression",
343
+ value: String(value)
344
+ }
345
+ });
346
+ }
347
+ break;
348
+ case "object":
349
+ attributes2.push({
350
+ type: "mdxJsxAttribute",
351
+ name,
352
+ value: {
353
+ type: "mdxJsxAttributeValueExpression",
354
+ value: stringifyObj(value, flatten2)
355
+ }
262
356
  });
263
- return {
264
- type: "blockquote",
265
- children
266
- };
267
- case "heading":
268
- return heading(content2);
269
- case "code":
270
- return code(content2);
271
- case "paragraph":
272
- return paragraph(content2);
273
- case "mdxJsxFlowElement":
274
- return mdxJsxElement(content2, field, imageCallback);
275
- case "thematicBreak":
276
- return {
277
- type: "hr",
278
- children: [{ type: "text", text: "" }]
279
- };
280
- case "listItem":
281
- return {
282
- type: "li",
283
- children: [
284
- {
285
- type: "lic",
286
- children: flatten(content2.children.map((child) => unwrapBlockContent(child)))
357
+ break;
358
+ case "rich-text":
359
+ if (typeof value === "string") {
360
+ throw new Error(`Unexpected string for rich-text, ensure the value has been properly parsed`);
361
+ }
362
+ if (field.list) {
363
+ throw new Error(`Rich-text list is not supported`);
364
+ } else {
365
+ const joiner = flatten2 ? " " : "\n";
366
+ let val = "";
367
+ assertShape(value, (value2) => value2.type === "root" && Array.isArray(value2.children), `Nested rich-text element is not a valid shape for field ${field.name}`);
368
+ if (field.name === "children") {
369
+ const root = rootElement(value, field, imageCallback);
370
+ root.children.forEach((child) => {
371
+ children.push(child);
372
+ });
373
+ return;
374
+ } else {
375
+ const stringValue = stringifyMDX(value, field, imageCallback);
376
+ if (stringValue) {
377
+ val = stringValue.trim().split("\n").map((str) => ` ${str.trim()}`).join(joiner);
287
378
  }
288
- ]
289
- };
290
- case "list":
291
- return list(content2);
292
- case "html":
293
- return html(content2);
294
- case "mdxFlowExpression":
295
- case "mdxjsEsm":
296
- throw new RichTextParseError(`Unexpected expression ${content2.value}.`, content2.position);
379
+ }
380
+ if (flatten2) {
381
+ attributes2.push({
382
+ type: "mdxJsxAttribute",
383
+ name,
384
+ value: {
385
+ type: "mdxJsxAttributeValueExpression",
386
+ value: `<>${val.trim()}</>`
387
+ }
388
+ });
389
+ } else {
390
+ attributes2.push({
391
+ type: "mdxJsxAttribute",
392
+ name,
393
+ value: {
394
+ type: "mdxJsxAttributeValueExpression",
395
+ value: `<>
396
+ ${val}
397
+ </>`
398
+ }
399
+ });
400
+ }
401
+ }
402
+ break;
297
403
  default:
298
- throw new RichTextParseError(`Content: ${content2.type} is not yet supported`, content2.position);
404
+ throw new Error(`Stringify props: ${field.type} not yet supported`);
299
405
  }
300
- };
301
- const html = (content2) => {
406
+ });
407
+ if (template.match) {
302
408
  return {
303
- type: "html",
304
- value: content2.value,
305
- children: [{ type: "text", text: "" }]
409
+ useDirective,
410
+ directiveType,
411
+ attributes: attributes2,
412
+ children: children && children.length ? children : [
413
+ {
414
+ type: "paragraph",
415
+ children: [
416
+ {
417
+ type: "text",
418
+ value: ""
419
+ }
420
+ ]
421
+ }
422
+ ]
306
423
  };
307
- };
308
- const html_inline = (content2) => {
424
+ }
425
+ return { attributes: attributes2, children, useDirective, directiveType };
426
+ }
427
+ function stringifyObj(obj, flatten2) {
428
+ if (typeof obj === "object" && obj !== null) {
429
+ const dummyFunc = `const dummyFunc = `;
430
+ const res = format(`${dummyFunc}${JSON.stringify(obj)}`, {
431
+ parser: "acorn",
432
+ trailingComma: "none",
433
+ semi: false
434
+ }).trim().replace(dummyFunc, "");
435
+ return flatten2 ? res.replaceAll("\n", "").replaceAll(" ", " ") : res;
436
+ } else {
437
+ throw new Error(`stringifyObj must be passed an object or an array of objects, received ${typeof obj}`);
438
+ }
439
+ }
440
+ function assertShape(value, callback, errorMessage) {
441
+ if (!callback(value)) {
442
+ throw new Error(errorMessage || `Failed to assert shape`);
443
+ }
444
+ }
445
+
446
+ // src/stringify/marks.ts
447
+ var matches = (a, b) => {
448
+ return a.some((v) => b.includes(v));
449
+ };
450
+ var replaceLinksWithTextNodes = (content) => {
451
+ const newItems = [];
452
+ content?.forEach((item) => {
453
+ if (item.type === "a") {
454
+ if (item.children.length === 1) {
455
+ const firstChild = item.children[0];
456
+ if (firstChild?.type === "text") {
457
+ newItems.push({
458
+ ...firstChild,
459
+ linkifyTextNode: (a) => {
460
+ return {
461
+ type: "link",
462
+ url: item.url,
463
+ title: item.title,
464
+ children: [a]
465
+ };
466
+ }
467
+ });
468
+ } else {
469
+ newItems.push(item);
470
+ }
471
+ } else {
472
+ newItems.push(item);
473
+ }
474
+ } else {
475
+ newItems.push(item);
476
+ }
477
+ });
478
+ return newItems;
479
+ };
480
+ var inlineElementExceptLink = (content, field, imageCallback) => {
481
+ switch (content.type) {
482
+ case "a":
483
+ throw new Error(`Unexpected node of type "a", link elements should be processed after all inline elements have resolved`);
484
+ case "img":
485
+ return {
486
+ type: "image",
487
+ url: imageCallback(content.url),
488
+ alt: content.alt,
489
+ title: content.caption
490
+ };
491
+ case "break":
492
+ return {
493
+ type: "break"
494
+ };
495
+ case "mdxJsxTextElement": {
496
+ const { attributes: attributes2, children } = stringifyPropsInline(content, field, imageCallback);
497
+ return {
498
+ type: "mdxJsxTextElement",
499
+ name: content.name,
500
+ attributes: attributes2,
501
+ children
502
+ };
503
+ }
504
+ case "html_inline": {
505
+ return {
506
+ type: "html",
507
+ value: content.value
508
+ };
509
+ }
510
+ default:
511
+ if (!content.type && typeof content.text === "string") {
512
+ return text(content);
513
+ }
514
+ throw new Error(`InlineElement: ${content.type} is not supported`);
515
+ }
516
+ };
517
+ var text = (content) => {
518
+ return {
519
+ type: "text",
520
+ value: content.text
521
+ };
522
+ };
523
+ var eat = (c, field, imageCallback) => {
524
+ const content = replaceLinksWithTextNodes(c);
525
+ const first = content[0];
526
+ if (!first) {
527
+ return [];
528
+ }
529
+ if (first && first?.type !== "text") {
530
+ if (first.type === "a") {
531
+ return [
532
+ {
533
+ type: "link",
534
+ url: first.url,
535
+ title: first.title,
536
+ children: eat(first.children, field, imageCallback)
537
+ },
538
+ ...eat(content.slice(1), field, imageCallback)
539
+ ];
540
+ }
541
+ return [
542
+ inlineElementExceptLink(first, field, imageCallback),
543
+ ...eat(content.slice(1), field, imageCallback)
544
+ ];
545
+ }
546
+ const marks = getMarks(first);
547
+ if (marks.length === 0) {
548
+ if (first.linkifyTextNode) {
549
+ return [
550
+ first.linkifyTextNode(text(first)),
551
+ ...eat(content.slice(1), field, imageCallback)
552
+ ];
553
+ } else {
554
+ return [text(first), ...eat(content.slice(1), field, imageCallback)];
555
+ }
556
+ }
557
+ let nonMatchingSiblingIndex = 0;
558
+ if (content.slice(1).every((content2, index) => {
559
+ if (matches(marks, getMarks(content2))) {
560
+ return true;
561
+ } else {
562
+ nonMatchingSiblingIndex = index;
563
+ return false;
564
+ }
565
+ })) {
566
+ nonMatchingSiblingIndex = content.length - 1;
567
+ }
568
+ const matchingSiblings = content.slice(1, nonMatchingSiblingIndex + 1);
569
+ const markCounts = {};
570
+ marks.forEach((mark) => {
571
+ let count2 = 1;
572
+ matchingSiblings.every((sibling, index) => {
573
+ if (getMarks(sibling).includes(mark)) {
574
+ count2 = index + 1;
575
+ return true;
576
+ }
577
+ });
578
+ markCounts[mark] = count2;
579
+ });
580
+ let count = 0;
581
+ let markToProcess = null;
582
+ Object.entries(markCounts).forEach(([mark, markCount]) => {
583
+ const m = mark;
584
+ if (markCount > count) {
585
+ count = markCount;
586
+ markToProcess = m;
587
+ }
588
+ });
589
+ if (!markToProcess) {
590
+ return [text(first), ...eat(content.slice(1), field, imageCallback)];
591
+ }
592
+ if (markToProcess === "inlineCode") {
593
+ if (nonMatchingSiblingIndex) {
594
+ throw new Error(`Marks inside inline code are not supported`);
595
+ }
596
+ const node = {
597
+ type: markToProcess,
598
+ value: first.text
599
+ };
600
+ return [
601
+ first.linkifyTextNode?.(node) ?? node,
602
+ ...eat(content.slice(nonMatchingSiblingIndex + 1), field, imageCallback)
603
+ ];
604
+ }
605
+ return [
606
+ {
607
+ type: markToProcess,
608
+ children: eat([
609
+ ...[first, ...matchingSiblings].map((sibling) => cleanNode(sibling, markToProcess))
610
+ ], field, imageCallback)
611
+ },
612
+ ...eat(content.slice(nonMatchingSiblingIndex + 1), field, imageCallback)
613
+ ];
614
+ };
615
+ var cleanNode = (node, mark) => {
616
+ if (!mark) {
617
+ return node;
618
+ }
619
+ const cleanedNode = {};
620
+ const markToClear = {
621
+ strong: "bold",
622
+ emphasis: "italic",
623
+ inlineCode: "code"
624
+ }[mark];
625
+ Object.entries(node).map(([key, value]) => {
626
+ if (key !== markToClear) {
627
+ cleanedNode[key] = value;
628
+ }
629
+ });
630
+ if (node.linkifyTextNode) {
631
+ cleanedNode.callback = node.linkifyTextNode;
632
+ }
633
+ return cleanedNode;
634
+ };
635
+
636
+ // src/extensions/tina-shortcodes/to-markdown.ts
637
+ import { stringifyEntitiesLight } from "stringify-entities";
638
+ import { containerFlow } from "mdast-util-to-markdown/lib/util/container-flow";
639
+ import { containerPhrasing } from "mdast-util-to-markdown/lib/util/container-phrasing";
640
+ import { checkQuote } from "mdast-util-to-markdown/lib/util/check-quote";
641
+ import { track } from "mdast-util-to-markdown/lib/util/track";
642
+ var own = {}.hasOwnProperty;
643
+ var directiveToMarkdown = (patterns) => ({
644
+ unsafe: [
645
+ {
646
+ character: "\r",
647
+ inConstruct: ["leafDirectiveLabel", "containerDirectiveLabel"]
648
+ },
649
+ {
650
+ character: "\n",
651
+ inConstruct: ["leafDirectiveLabel", "containerDirectiveLabel"]
652
+ },
653
+ {
654
+ before: "[^:]",
655
+ character: ":",
656
+ after: "[A-Za-z]",
657
+ inConstruct: ["phrasing"]
658
+ },
659
+ { atBreak: true, character: ":", after: ":" }
660
+ ],
661
+ handlers: {
662
+ containerDirective: handleDirective(patterns),
663
+ leafDirective: handleDirective(patterns),
664
+ textDirective: handleDirective(patterns)
665
+ }
666
+ });
667
+ var handleDirective = function(patterns) {
668
+ const handleDirective2 = function(node, _, state, safeOptions) {
669
+ const tracker = track(safeOptions);
670
+ const exit2 = state.enter(node.type);
671
+ const pattern = patterns.find((p) => p.name === node.name || p.templateName === node.name);
672
+ if (!pattern) {
673
+ console.log("no pattern found for directive", node.name);
674
+ exit2();
675
+ return "";
676
+ }
677
+ const patternName = pattern.name || pattern.templateName;
678
+ const sequence = pattern.start;
679
+ let value = tracker.move(sequence + " " + patternName);
680
+ let label;
681
+ if (label && label.children && label.children.length > 0) {
682
+ const exit3 = state.enter("label");
683
+ const labelType = `${node.type}Label`;
684
+ const subexit = state.enter(labelType);
685
+ value += tracker.move("[");
686
+ value += tracker.move(containerPhrasing(label, state, {
687
+ ...tracker.current(),
688
+ before: value,
689
+ after: "]"
690
+ }));
691
+ value += tracker.move("]");
692
+ subexit();
693
+ exit3();
694
+ }
695
+ value += tracker.move(" ");
696
+ value += tracker.move(attributes(node, state));
697
+ value += tracker.move(pattern.end);
698
+ if (node.type === "containerDirective") {
699
+ const head = (node.children || [])[0];
700
+ let shallow = node;
701
+ if (inlineDirectiveLabel(head)) {
702
+ shallow = Object.assign({}, node, { children: node.children.slice(1) });
703
+ }
704
+ if (shallow && shallow.children && shallow.children.length > 0) {
705
+ value += tracker.move("\n");
706
+ value += tracker.move(containerFlow(shallow, state, tracker.current()));
707
+ }
708
+ value += tracker.move("\n" + sequence);
709
+ value += tracker.move(" \\" + patternName + " " + pattern.end);
710
+ }
711
+ exit2();
712
+ return value;
713
+ };
714
+ handleDirective2.peek = peekDirective;
715
+ return handleDirective2;
716
+ };
717
+ function peekDirective() {
718
+ return ":";
719
+ }
720
+ function attributes(node, state) {
721
+ const quote = checkQuote(state);
722
+ const subset = node.type === "textDirective" ? [quote] : [quote, "\n", "\r"];
723
+ const attrs = node.attributes || {};
724
+ const values2 = [];
725
+ let key;
726
+ for (key in attrs) {
727
+ if (own.call(attrs, key) && attrs[key] !== void 0 && attrs[key] !== null) {
728
+ const value = String(attrs[key]);
729
+ values2.push(quoted(key, value));
730
+ }
731
+ }
732
+ return values2.length > 0 ? values2.join(" ") + " " : "";
733
+ function quoted(key2, value) {
734
+ const v = quote + stringifyEntitiesLight(value, { subset }) + quote;
735
+ if (key2 === "_value") {
736
+ return v;
737
+ }
738
+ return key2 + (value ? "=" + v : "");
739
+ }
740
+ }
741
+ function inlineDirectiveLabel(node) {
742
+ return Boolean(node && node.type === "paragraph" && node.data && node.data.directiveLabel);
743
+ }
744
+
745
+ // src/stringify/stringifyShortcode.ts
746
+ function stringifyShortcode(preprocessedString, template) {
747
+ const match = template.match;
748
+ const unkeyedAttributes = !!template.fields.find((t) => t.name == "_value");
749
+ const regex = `<[\\s]*${template.name}[\\s]*${unkeyedAttributes ? "(?:_value=(.*?))?" : "(.+?)?"}[\\s]*>[\\s]*((?:.|
750
+ )*?)[\\s]*</[\\s]*${template.name}[\\s]*>`;
751
+ const closingRegex = `
752
+ $2
753
+ ${match.start} /${match.name || template.name} ${match.end}`;
754
+ const replace = `${match.start} ${match.name || template.name} $1 ${match.end}${template.fields.find((t) => t.name == "children") ? closingRegex : ""}`;
755
+ return replaceAll(preprocessedString, regex, replace);
756
+ }
757
+
758
+ // src/stringify/index.ts
759
+ var stringifyMDX = (value, field, imageCallback) => {
760
+ if (!value) {
761
+ return;
762
+ }
763
+ if (typeof value === "string") {
764
+ throw new Error("Expected an object to stringify, but received a string");
765
+ }
766
+ if (value?.children[0]) {
767
+ if (value?.children[0].type === "invalid_markdown") {
768
+ return value.children[0].value;
769
+ }
770
+ }
771
+ const tree = rootElement(value, field, imageCallback);
772
+ const res = toTinaMarkdown(tree, field);
773
+ const templatesWithMatchers = field.templates?.filter((template) => template.match);
774
+ let preprocessedString = res;
775
+ templatesWithMatchers?.forEach((template) => {
776
+ if (typeof template === "string") {
777
+ throw new Error("Global templates are not supported");
778
+ }
779
+ if (template.match) {
780
+ preprocessedString = stringifyShortcode(preprocessedString, template);
781
+ }
782
+ });
783
+ return preprocessedString;
784
+ };
785
+ var toTinaMarkdown = (tree, field) => {
786
+ const patterns = [];
787
+ field.templates?.forEach((template) => {
788
+ if (typeof template === "string") {
789
+ return;
790
+ }
791
+ if (template && template.match) {
792
+ const pattern = template.match;
793
+ pattern.templateName = template.name;
794
+ patterns.push(pattern);
795
+ }
796
+ });
797
+ const handlers = {};
798
+ handlers["text"] = (node, parent, context, safeOptions) => {
799
+ context.unsafe = context.unsafe.filter((unsafeItem) => {
800
+ if (unsafeItem.character === " " && unsafeItem.inConstruct === "phrasing") {
801
+ return false;
802
+ }
803
+ return true;
804
+ });
805
+ if (field.parser?.type === "markdown") {
806
+ if (field.parser.skipEscaping === "all") {
807
+ return node.value;
808
+ }
809
+ if (field.parser.skipEscaping === "html") {
810
+ context.unsafe = context.unsafe.filter((unsafeItem) => {
811
+ if (unsafeItem.character === "<") {
812
+ return false;
813
+ }
814
+ return true;
815
+ });
816
+ }
817
+ }
818
+ return text2(node, parent, context, safeOptions);
819
+ };
820
+ return toMarkdown(tree, {
821
+ extensions: [directiveToMarkdown(patterns), mdxJsxToMarkdown()],
822
+ listItemIndent: "one",
823
+ handlers
824
+ });
825
+ };
826
+ var rootElement = (content, field, imageCallback) => {
827
+ const children = [];
828
+ content.children?.forEach((child) => {
829
+ const value = blockElement(child, field, imageCallback);
830
+ if (value) {
831
+ children.push(value);
832
+ }
833
+ });
834
+ return {
835
+ type: "root",
836
+ children
837
+ };
838
+ };
839
+ var blockElement = (content, field, imageCallback) => {
840
+ switch (content.type) {
841
+ case "h1":
842
+ case "h2":
843
+ case "h3":
844
+ case "h4":
845
+ case "h5":
846
+ case "h6":
847
+ return {
848
+ type: "heading",
849
+ depth: { h1: 1, h2: 2, h3: 3, h4: 4, h5: 5, h6: 6 }[content.type],
850
+ children: eat(content.children, field, imageCallback)
851
+ };
852
+ case "p":
853
+ if (content.children.length === 1) {
854
+ const onlyChild = content.children[0];
855
+ if (onlyChild && (onlyChild.type === "text" || !onlyChild.type) && onlyChild.text === "") {
856
+ return null;
857
+ }
858
+ }
859
+ return {
860
+ type: "paragraph",
861
+ children: eat(content.children, field, imageCallback)
862
+ };
863
+ case "code_block":
864
+ return {
865
+ type: "code",
866
+ lang: content.lang,
867
+ value: content.value
868
+ };
869
+ case "mdxJsxFlowElement":
870
+ const { children, attributes: attributes2, useDirective, directiveType } = stringifyProps(content, field, false, imageCallback);
871
+ if (useDirective) {
872
+ const name = content.name;
873
+ if (!name) {
874
+ throw new Error(`Expective shortcode to have a name but it was not defined`);
875
+ }
876
+ const directiveAttributes = {};
877
+ attributes2?.forEach((att) => {
878
+ if (att.value && typeof att.value === "string") {
879
+ directiveAttributes[att.name] = att.value;
880
+ }
881
+ });
882
+ if (directiveType === "leaf") {
883
+ return {
884
+ type: "leafDirective",
885
+ name,
886
+ attributes: directiveAttributes,
887
+ children: []
888
+ };
889
+ } else {
890
+ return {
891
+ type: "containerDirective",
892
+ name,
893
+ attributes: directiveAttributes,
894
+ children
895
+ };
896
+ }
897
+ }
898
+ return {
899
+ type: "mdxJsxFlowElement",
900
+ name: content.name,
901
+ attributes: attributes2,
902
+ children
903
+ };
904
+ case "blockquote":
905
+ return {
906
+ type: "blockquote",
907
+ children: [
908
+ {
909
+ type: "paragraph",
910
+ children: eat(content.children, field, imageCallback)
911
+ }
912
+ ]
913
+ };
914
+ case "hr":
915
+ return {
916
+ type: "thematicBreak"
917
+ };
918
+ case "ol":
919
+ case "ul":
920
+ return {
921
+ type: "list",
922
+ ordered: content.type === "ol",
923
+ spread: false,
924
+ children: content.children.map((child) => listItemElement(child, field, imageCallback))
925
+ };
926
+ case "html": {
927
+ return {
928
+ type: "html",
929
+ value: content.value
930
+ };
931
+ }
932
+ case "img":
933
+ return {
934
+ type: "image",
935
+ url: imageCallback(content.url),
936
+ alt: content.alt,
937
+ title: content.caption
938
+ };
939
+ default:
940
+ throw new Error(`BlockElement: ${content.type} is not yet supported`);
941
+ }
942
+ };
943
+ var listItemElement = (content, field, imageCallback) => {
944
+ return {
945
+ type: "listItem",
946
+ spread: false,
947
+ children: content.children.map((child) => {
948
+ if (child.type === "lic") {
949
+ return {
950
+ type: "paragraph",
951
+ children: eat(child.children, field, imageCallback)
952
+ };
953
+ }
954
+ return blockContentElement(child, field, imageCallback);
955
+ })
956
+ };
957
+ };
958
+ var blockContentElement = (content, field, imageCallback) => {
959
+ switch (content.type) {
960
+ case "blockquote":
961
+ return {
962
+ type: "blockquote",
963
+ children: content.children.map((child) => blockContentElement(child, field, imageCallback))
964
+ };
965
+ case "p":
966
+ return {
967
+ type: "paragraph",
968
+ children: eat(content.children, field, imageCallback)
969
+ };
970
+ case "ol":
971
+ case "ul":
972
+ return {
973
+ type: "list",
974
+ ordered: content.type === "ol",
975
+ spread: false,
976
+ children: content.children.map((child) => listItemElement(child, field, imageCallback))
977
+ };
978
+ default:
979
+ throw new Error(`BlockContentElement: ${content.type} is not yet supported`);
980
+ }
981
+ };
982
+ var getMarks = (content) => {
983
+ const marks = [];
984
+ if (content.type !== "text") {
985
+ return [];
986
+ }
987
+ if (content.bold) {
988
+ marks.push("strong");
989
+ }
990
+ if (content.italic) {
991
+ marks.push("emphasis");
992
+ }
993
+ if (content.code) {
994
+ marks.push("inlineCode");
995
+ }
996
+ return marks;
997
+ };
998
+
999
+ // src/parse/mdx.ts
1000
+ import { source } from "unist-util-source";
1001
+ function mdxJsxElement(node, field, imageCallback) {
1002
+ try {
1003
+ const template = field.templates?.find((template2) => {
1004
+ const templateName = typeof template2 === "string" ? template2 : template2.name;
1005
+ return templateName === node.name;
1006
+ });
1007
+ if (typeof template === "string") {
1008
+ throw new Error("Global templates not yet supported");
1009
+ }
1010
+ if (!template) {
1011
+ const string = toTinaMarkdown({ type: "root", children: [node] }, field);
1012
+ return {
1013
+ type: node.type === "mdxJsxFlowElement" ? "html" : "html_inline",
1014
+ value: string.trim(),
1015
+ children: [{ type: "text", text: "" }]
1016
+ };
1017
+ }
1018
+ const props = extractAttributes(node.attributes, template.fields, imageCallback);
1019
+ const childField = template.fields.find((field2) => field2.name === "children");
1020
+ if (childField) {
1021
+ if (childField.type === "rich-text") {
1022
+ props.children = remarkToSlate(node, childField, imageCallback);
1023
+ }
1024
+ }
309
1025
  return {
310
- type: "html_inline",
311
- value: content2.value,
312
- children: [{ type: "text", text: "" }]
1026
+ type: node.type,
1027
+ name: node.name,
1028
+ children: [{ type: "text", text: "" }],
1029
+ props
1030
+ };
1031
+ } catch (e) {
1032
+ if (e instanceof Error) {
1033
+ throw new RichTextParseError(e.message, node.position);
1034
+ }
1035
+ throw e;
1036
+ }
1037
+ }
1038
+ var directiveElement = (node, field, imageCallback, raw) => {
1039
+ let template;
1040
+ template = field.templates?.find((template2) => {
1041
+ const templateName = typeof template2 === "string" ? template2 : template2.name;
1042
+ return templateName === node.name;
1043
+ });
1044
+ if (typeof template === "string") {
1045
+ throw new Error("Global templates not yet supported");
1046
+ }
1047
+ if (!template) {
1048
+ template = field.templates?.find((template2) => {
1049
+ const templateName = template2?.match?.name;
1050
+ return templateName === node.name;
1051
+ });
1052
+ }
1053
+ if (!template) {
1054
+ return {
1055
+ type: "p",
1056
+ children: [{ type: "text", text: source(node, raw || "") || "" }]
1057
+ };
1058
+ }
1059
+ if (typeof template === "string") {
1060
+ throw new Error(`Global templates not supported`);
1061
+ }
1062
+ const props = node.attributes || {};
1063
+ const childField = template.fields.find((field2) => field2.name === "children");
1064
+ if (childField) {
1065
+ if (childField.type === "rich-text") {
1066
+ if (node.type === "containerDirective") {
1067
+ props.children = remarkToSlate(node, childField, imageCallback, raw);
1068
+ }
1069
+ }
1070
+ }
1071
+ return {
1072
+ type: "mdxJsxFlowElement",
1073
+ name: template.name,
1074
+ props,
1075
+ children: [{ type: "text", text: "" }]
1076
+ };
1077
+ };
1078
+
1079
+ // src/parse/remarkToPlate.ts
1080
+ var remarkToSlate = (root, field, imageCallback, raw) => {
1081
+ const content = (content2) => {
1082
+ switch (content2.type) {
1083
+ case "blockquote":
1084
+ const children = [];
1085
+ content2.children.map((child) => {
1086
+ const inlineElements = unwrapBlockContent(child);
1087
+ inlineElements.forEach((child2) => {
1088
+ children.push(child2);
1089
+ });
1090
+ });
1091
+ return {
1092
+ type: "blockquote",
1093
+ children
1094
+ };
1095
+ case "heading":
1096
+ return heading(content2);
1097
+ case "code":
1098
+ return code(content2);
1099
+ case "paragraph":
1100
+ return paragraph(content2);
1101
+ case "mdxJsxFlowElement":
1102
+ return mdxJsxElement(content2, field, imageCallback);
1103
+ case "thematicBreak":
1104
+ return {
1105
+ type: "hr",
1106
+ children: [{ type: "text", text: "" }]
1107
+ };
1108
+ case "listItem":
1109
+ return {
1110
+ type: "li",
1111
+ children: [
1112
+ {
1113
+ type: "lic",
1114
+ children: flatten(content2.children.map((child) => unwrapBlockContent(child)))
1115
+ }
1116
+ ]
1117
+ };
1118
+ case "list":
1119
+ return list(content2);
1120
+ case "html":
1121
+ return html(content2);
1122
+ case "mdxFlowExpression":
1123
+ case "mdxjsEsm":
1124
+ throw new RichTextParseError(`Unexpected expression ${content2.value}.`, content2.position);
1125
+ case "leafDirective": {
1126
+ return directiveElement(content2, field, imageCallback, raw);
1127
+ }
1128
+ case "containerDirective": {
1129
+ return directiveElement(content2, field, imageCallback, raw);
1130
+ }
1131
+ default:
1132
+ throw new RichTextParseError(`Content: ${content2.type} is not yet supported`, content2.position);
1133
+ }
1134
+ };
1135
+ const html = (content2) => {
1136
+ return {
1137
+ type: "p",
1138
+ children: [{ type: "text", text: content2.value }]
313
1139
  };
314
1140
  };
1141
+ const html_inline = (content2) => {
1142
+ return { type: "text", text: content2.value };
1143
+ };
315
1144
  const list = (content2) => {
316
1145
  return {
317
1146
  type: content2.ordered ? "ol" : "ul",
@@ -344,10 +1173,20 @@ var remarkToSlate = (root, field, imageCallback) => {
344
1173
  mdxJsxElement({ ...child, type: "mdxJsxTextElement" }, field, imageCallback)
345
1174
  ]
346
1175
  };
1176
+ case "html":
1177
+ return {
1178
+ type: "lic",
1179
+ children: html_inline(child)
1180
+ };
1181
+ case "leafDirective": {
1182
+ return {
1183
+ type: "lic",
1184
+ children: [directiveElement(child, field, imageCallback)]
1185
+ };
1186
+ }
347
1187
  case "code":
348
1188
  case "thematicBreak":
349
1189
  case "table":
350
- case "html":
351
1190
  throw new RichTextParseError(`${child.type} inside list item is not supported`, child.position);
352
1191
  default:
353
1192
  throw new RichTextParseError(`Unknown list item of type ${child.type}`, child.position);
@@ -356,878 +1195,1066 @@ var remarkToSlate = (root, field, imageCallback) => {
356
1195
  };
357
1196
  };
358
1197
  const unwrapBlockContent = (content2) => {
359
- const flattenPhrasingContent = (children) => {
360
- const children2 = children.map((child) => phrasingContent(child));
361
- return flatten(Array.isArray(children2) ? children2 : [children2]);
362
- };
363
- switch (content2.type) {
364
- case "heading":
365
- case "paragraph":
366
- return flattenPhrasingContent(content2.children);
367
- default:
368
- throw new Error(`UnwrapBlock: Unknown block content of type ${content2.type}`);
369
- }
370
- };
371
- const code = (content2) => {
372
- const extra = {};
373
- if (content2.lang)
374
- extra["lang"] = content2.lang;
375
- return {
376
- type: "code_block",
377
- ...extra,
378
- value: content2.value,
379
- children: [{ type: "text", text: "" }]
380
- };
381
- };
382
- const link = (content2) => {
383
- return {
384
- type: "a",
385
- url: content2.url,
386
- title: content2.title,
387
- children: flatten(content2.children.map((child) => staticPhrasingContent(child)))
388
- };
389
- };
390
- const heading = (content2) => {
391
- return {
392
- type: ["h1", "h2", "h3", "h4", "h5", "h6"][content2.depth - 1],
393
- children: flatten(content2.children.map(phrasingContent))
394
- };
395
- };
396
- const staticPhrasingContent = (content2) => {
397
- switch (content2.type) {
398
- case "mdxJsxTextElement":
399
- return mdxJsxElement(content2, field, imageCallback);
400
- case "text":
401
- return text2(content2);
402
- case "inlineCode":
403
- case "emphasis":
404
- case "image":
405
- case "strong":
406
- return phrashingMark(content2);
407
- default:
408
- throw new Error(`StaticPhrasingContent: ${content2.type} is not yet supported`);
409
- }
410
- };
411
- const phrasingContent = (content2) => {
412
- switch (content2.type) {
413
- case "text":
414
- return text2(content2);
415
- case "link":
416
- return link(content2);
417
- case "image":
418
- return image(content2);
419
- case "mdxJsxTextElement":
420
- return mdxJsxElement(content2, field, imageCallback);
421
- case "emphasis":
422
- return phrashingMark(content2);
423
- case "strong":
424
- return phrashingMark(content2);
425
- case "break":
426
- return breakContent();
427
- case "inlineCode":
428
- return phrashingMark(content2);
429
- case "html":
430
- return html_inline(content2);
431
- case "mdxTextExpression":
432
- throw new RichTextParseError(`Unexpected expression ${content2.value}.`, content2.position);
433
- default:
434
- throw new Error(`PhrasingContent: ${content2.type} is not yet supported`);
435
- }
436
- };
437
- const breakContent = () => {
438
- return {
439
- type: "break",
440
- children: [
441
- {
442
- type: "text",
443
- text: ""
444
- }
445
- ]
446
- };
447
- };
448
- const phrashingMark = (node, marks = []) => {
449
- const accum = [];
450
- switch (node.type) {
451
- case "emphasis": {
452
- const children = flatten(node.children.map((child) => phrashingMark(child, [...marks, "italic"])));
453
- children.forEach((child) => {
454
- accum.push(child);
455
- });
456
- break;
457
- }
458
- case "inlineCode": {
459
- const markProps2 = {};
460
- marks.forEach((mark) => markProps2[mark] = true);
461
- accum.push({
462
- type: "text",
463
- text: node.value,
464
- code: true,
465
- ...markProps2
466
- });
467
- break;
468
- }
469
- case "strong": {
470
- const children = flatten(node.children.map((child) => phrashingMark(child, [...marks, "bold"])));
471
- children.forEach((child) => {
472
- accum.push(child);
473
- });
474
- break;
475
- }
476
- case "image": {
477
- accum.push(image(node));
478
- break;
479
- }
480
- case "link": {
481
- const children = flatten(node.children.map((child) => phrashingMark(child, marks)));
482
- accum.push({ type: "a", url: node.url, title: node.title, children });
483
- break;
484
- }
485
- case "text":
486
- const markProps = {};
487
- marks.forEach((mark) => markProps[mark] = true);
488
- accum.push({ type: "text", text: node.value, ...markProps });
489
- break;
1198
+ const flattenPhrasingContent = (children) => {
1199
+ const children2 = children.map((child) => phrasingContent(child));
1200
+ return flatten(Array.isArray(children2) ? children2 : [children2]);
1201
+ };
1202
+ switch (content2.type) {
1203
+ case "heading":
1204
+ case "paragraph":
1205
+ return flattenPhrasingContent(content2.children);
1206
+ case "html":
1207
+ return [html_inline(content2)];
1208
+ case "blockquote":
490
1209
  default:
491
- throw new Error(`Unexpected inline element of type ${node.type}`);
1210
+ throw new RichTextParseError(`UnwrapBlock: Unknown block content of type ${content2.type}`, content2.position);
492
1211
  }
493
- return accum;
494
1212
  };
495
- const image = (content2) => {
1213
+ const code = (content2) => {
1214
+ const extra = {};
1215
+ if (content2.lang)
1216
+ extra["lang"] = content2.lang;
496
1217
  return {
497
- type: "img",
498
- url: imageCallback(content2.url),
499
- alt: content2.alt,
500
- caption: content2.title,
1218
+ type: "code_block",
1219
+ ...extra,
1220
+ value: content2.value,
501
1221
  children: [{ type: "text", text: "" }]
502
1222
  };
503
1223
  };
504
- const text2 = (content2) => {
505
- return {
506
- type: "text",
507
- text: content2.value
508
- };
509
- };
510
- const blockquote = (content2) => {
511
- const children = [];
512
- content2.children.map((child) => {
513
- const inlineElements = unwrapBlockContent(child);
514
- inlineElements.forEach((child2) => {
515
- children.push(child2);
516
- });
517
- });
1224
+ const link = (content2) => {
518
1225
  return {
519
- type: "blockquote",
520
- children
1226
+ type: "a",
1227
+ url: content2.url,
1228
+ title: content2.title,
1229
+ children: flatten(content2.children.map((child) => staticPhrasingContent(child)))
521
1230
  };
522
1231
  };
523
- const paragraph = (content2) => {
524
- const children = flatten(content2.children.map(phrasingContent));
525
- if (children.length === 1) {
526
- if (children[0]) {
527
- if (children[0].type === "html_inline") {
528
- return {
529
- ...children[0],
530
- type: "html"
531
- };
532
- }
533
- }
534
- }
1232
+ const heading = (content2) => {
535
1233
  return {
536
- type: "p",
537
- children
1234
+ type: ["h1", "h2", "h3", "h4", "h5", "h6"][content2.depth - 1],
1235
+ children: flatten(content2.children.map(phrasingContent))
538
1236
  };
539
1237
  };
540
- return {
541
- type: "root",
542
- children: root.children.map((child) => {
543
- return content(child);
544
- })
545
- };
546
- };
547
- var RichTextParseError = class extends Error {
548
- constructor(message, position) {
549
- super(message);
550
- __publicField(this, "position");
551
- if (Error.captureStackTrace) {
552
- Error.captureStackTrace(this, RichTextParseError);
553
- }
554
- this.name = "RichTextParseError";
555
- this.position = position;
556
- }
557
- };
558
-
559
- // src/parse/parseShortcode.ts
560
- function parseShortcode(preprocessedString, template) {
561
- const match = template.match;
562
- const unkeyedAttributes = !!template.fields.find((t) => t.name === "_value");
563
- const hasChildren = !!template.fields.find((t) => t.name == "children");
564
- const replacement = `<${template.name} ${unkeyedAttributes ? '_value="$1"' : "$1"}>${hasChildren ? "$2" : "\n"}</${template.name}>`;
565
- const endRegex = `((?:.|\\n)*)${match.start}\\s/\\s*${match.name || template.name}[\\s]*${match.end}`;
566
- const regex = `${match.start}\\s*${match.name || template.name}[\\s]+${unkeyedAttributes ? `['"]?(.*?)['"]?` : "(.*?)"}[\\s]*${match.end}${hasChildren ? endRegex : ""}`;
567
- return replaceAll(preprocessedString, regex, replacement);
568
- }
569
-
570
- // src/parse/index.ts
571
- var markdownToAst = (value, field) => {
572
- const templatesWithMatchers = field.templates?.filter((template) => template.match);
573
- let preprocessedString = value;
574
- templatesWithMatchers?.forEach((template) => {
575
- if (typeof template === "string") {
576
- throw new Error("Global templates are not supported");
577
- }
578
- if (template.match) {
579
- if (preprocessedString) {
580
- preprocessedString = parseShortcode(preprocessedString, template);
581
- }
582
- }
583
- });
584
- try {
585
- const tree = remark().use(remarkMdx).parse(preprocessedString);
586
- if (!tree) {
587
- throw new Error("Error parsing markdown");
588
- }
589
- return tree;
590
- } catch (e) {
591
- console.error("error parsing file: ", e);
592
- throw new RichTextParseError(e, e.position);
593
- }
594
- };
595
- var MDX_PARSE_ERROR_MSG = "TinaCMS supports a stricter version of markdown and a subset of MDX. https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations";
596
- var parseMDX = (value, field, imageCallback) => {
597
- let tree;
598
- try {
599
- tree = markdownToAst(value, field);
600
- if (tree) {
601
- return remarkToSlate(tree, field, imageCallback);
602
- } else {
603
- return { type: "root", children: [] };
604
- }
605
- } catch (e) {
606
- if (e instanceof RichTextParseError) {
607
- return invalidMarkdown(e, value);
1238
+ const staticPhrasingContent = (content2) => {
1239
+ switch (content2.type) {
1240
+ case "mdxJsxTextElement":
1241
+ return mdxJsxElement(content2, field, imageCallback);
1242
+ case "text":
1243
+ return text3(content2);
1244
+ case "inlineCode":
1245
+ case "emphasis":
1246
+ case "image":
1247
+ case "strong":
1248
+ return phrashingMark(content2);
1249
+ case "html":
1250
+ return html_inline(content2);
1251
+ default:
1252
+ throw new Error(`StaticPhrasingContent: ${content2.type} is not yet supported`);
608
1253
  }
609
- return invalidMarkdown(new RichTextParseError(e.message), value);
610
- }
611
- };
612
- var invalidMarkdown = (e, value) => {
613
- const extra = {};
614
- if (e.position && Object.keys(e.position).length) {
615
- extra["position"] = e.position;
616
- }
617
- return {
618
- type: "root",
619
- children: [
620
- {
621
- type: "invalid_markdown",
622
- value,
623
- message: e.message || `Error parsing markdown ${MDX_PARSE_ERROR_MSG}`,
624
- children: [{ type: "text", text: "" }],
625
- ...extra
626
- }
627
- ]
628
1254
  };
629
- };
630
- var replaceAll = (string, target, value) => {
631
- const regex = new RegExp(target, "g");
632
- return string.valueOf().replace(regex, value);
633
- };
634
-
635
- // src/stringify/index.ts
636
- import { toMarkdown as toMarkdown2 } from "mdast-util-to-markdown";
637
- import {
638
- mdxJsxToMarkdown as mdxJsxToMarkdown2
639
- } from "mdast-util-mdx-jsx";
640
-
641
- // src/stringify/acorn.ts
642
- import { format } from "prettier";
643
- var stringifyPropsInline = (element, field, imageCallback) => {
644
- return stringifyProps(element, field, true, imageCallback);
645
- };
646
- function stringifyProps(element, parentField, flatten2, imageCallback) {
647
- const attributes = [];
648
- const children = [];
649
- const template = parentField.templates?.find((template2) => {
650
- if (typeof template2 === "string") {
651
- throw new Error("Global templates not supported");
652
- }
653
- return template2.name === element.name;
654
- });
655
- if (!template || typeof template === "string") {
656
- throw new Error(`Unable to find template for JSX element ${element.name}`);
657
- }
658
- Object.entries(element.props).forEach(([name, value]) => {
659
- const field = template.fields.find((field2) => field2.name === name);
660
- if (!field) {
661
- if (name === "children") {
662
- return;
663
- }
664
- throw new Error(`No field definition found for property ${name}`);
665
- }
666
- switch (field.type) {
667
- case "reference":
668
- if (field.list) {
669
- if (Array.isArray(value)) {
670
- attributes.push({
671
- type: "mdxJsxAttribute",
672
- name,
673
- value: {
674
- type: "mdxJsxAttributeValueExpression",
675
- value: `[${value.map((item) => `"${item}"`).join(", ")}]`
676
- }
677
- });
678
- }
679
- } else {
680
- if (typeof value === "string") {
681
- attributes.push({
682
- type: "mdxJsxAttribute",
683
- name,
684
- value
685
- });
686
- }
687
- }
688
- break;
689
- case "datetime":
690
- case "string":
691
- if (field.list) {
692
- if (Array.isArray(value)) {
693
- attributes.push({
694
- type: "mdxJsxAttribute",
695
- name,
696
- value: {
697
- type: "mdxJsxAttributeValueExpression",
698
- value: `[${value.map((item) => `"${item}"`).join(", ")}]`
699
- }
700
- });
701
- }
702
- } else {
703
- if (typeof value === "string") {
704
- attributes.push({
705
- type: "mdxJsxAttribute",
706
- name,
707
- value
708
- });
709
- } else {
710
- throw new Error(`Expected string for attribute on field ${field.name}`);
711
- }
712
- }
713
- break;
1255
+ const phrasingContent = (content2) => {
1256
+ switch (content2.type) {
1257
+ case "text":
1258
+ return text3(content2);
1259
+ case "link":
1260
+ return link(content2);
714
1261
  case "image":
715
- if (field.list) {
716
- if (Array.isArray(value)) {
717
- attributes.push({
718
- type: "mdxJsxAttribute",
719
- name,
720
- value: {
721
- type: "mdxJsxAttributeValueExpression",
722
- value: `[${value.map((item) => `"${imageCallback(item)}"`).join(", ")}]`
723
- }
724
- });
725
- }
726
- } else {
727
- attributes.push({
728
- type: "mdxJsxAttribute",
729
- name,
730
- value: imageCallback(String(value))
731
- });
1262
+ return image(content2);
1263
+ case "mdxJsxTextElement":
1264
+ return mdxJsxElement(content2, field, imageCallback);
1265
+ case "emphasis":
1266
+ return phrashingMark(content2);
1267
+ case "strong":
1268
+ return phrashingMark(content2);
1269
+ case "break":
1270
+ return breakContent();
1271
+ case "inlineCode":
1272
+ return phrashingMark(content2);
1273
+ case "html":
1274
+ return html_inline(content2);
1275
+ case "mdxTextExpression":
1276
+ throw new RichTextParseError(`Unexpected expression ${content2.value}.`, content2.position);
1277
+ default:
1278
+ throw new Error(`PhrasingContent: ${content2.type} is not yet supported`);
1279
+ }
1280
+ };
1281
+ const breakContent = () => {
1282
+ return {
1283
+ type: "break",
1284
+ children: [
1285
+ {
1286
+ type: "text",
1287
+ text: ""
732
1288
  }
1289
+ ]
1290
+ };
1291
+ };
1292
+ const phrashingMark = (node, marks = []) => {
1293
+ const accum = [];
1294
+ switch (node.type) {
1295
+ case "emphasis": {
1296
+ const children = flatten(node.children.map((child) => phrashingMark(child, [...marks, "italic"])));
1297
+ children.forEach((child) => {
1298
+ accum.push(child);
1299
+ });
733
1300
  break;
734
- case "number":
735
- case "boolean":
736
- if (field.list) {
737
- if (Array.isArray(value)) {
738
- attributes.push({
739
- type: "mdxJsxAttribute",
740
- name,
741
- value: {
742
- type: "mdxJsxAttributeValueExpression",
743
- value: `[${value.map((item) => `${item}`).join(", ")}]`
744
- }
745
- });
746
- }
747
- } else {
748
- attributes.push({
749
- type: "mdxJsxAttribute",
750
- name,
751
- value: {
752
- type: "mdxJsxAttributeValueExpression",
753
- value: String(value)
754
- }
755
- });
756
- }
1301
+ }
1302
+ case "inlineCode": {
1303
+ const markProps2 = {};
1304
+ marks.forEach((mark) => markProps2[mark] = true);
1305
+ accum.push({
1306
+ type: "text",
1307
+ text: node.value,
1308
+ code: true,
1309
+ ...markProps2
1310
+ });
757
1311
  break;
758
- case "object":
759
- attributes.push({
760
- type: "mdxJsxAttribute",
761
- name,
762
- value: {
763
- type: "mdxJsxAttributeValueExpression",
764
- value: stringifyObj(value, flatten2)
765
- }
1312
+ }
1313
+ case "strong": {
1314
+ const children = flatten(node.children.map((child) => phrashingMark(child, [...marks, "bold"])));
1315
+ children.forEach((child) => {
1316
+ accum.push(child);
766
1317
  });
767
1318
  break;
768
- case "rich-text":
769
- if (typeof value === "string") {
770
- throw new Error(`Unexpected string for rich-text, ensure the value has been properly parsed`);
771
- }
772
- if (field.list) {
773
- throw new Error(`Rich-text list is not supported`);
774
- } else {
775
- const joiner = flatten2 ? " " : "\n";
776
- let val = "";
777
- assertShape(value, (value2) => value2.type === "root" && Array.isArray(value2.children), `Nested rich-text element is not a valid shape for field ${field.name}`);
778
- if (field.name === "children") {
779
- const root = rootElement(value, field, imageCallback);
780
- root.children.forEach((child) => {
781
- children.push(child);
782
- });
783
- return;
784
- } else {
785
- const stringValue = stringifyMDX(value, field, imageCallback);
786
- if (stringValue) {
787
- val = stringValue.trim().split("\n").map((str) => ` ${str.trim()}`).join(joiner);
788
- }
789
- }
790
- if (flatten2) {
791
- attributes.push({
792
- type: "mdxJsxAttribute",
793
- name,
794
- value: {
795
- type: "mdxJsxAttributeValueExpression",
796
- value: `<>${val.trim()}</>`
797
- }
798
- });
799
- } else {
800
- attributes.push({
801
- type: "mdxJsxAttribute",
802
- name,
803
- value: {
804
- type: "mdxJsxAttributeValueExpression",
805
- value: `<>
806
- ${val}
807
- </>`
808
- }
809
- });
810
- }
811
- }
1319
+ }
1320
+ case "image": {
1321
+ accum.push(image(node));
1322
+ break;
1323
+ }
1324
+ case "link": {
1325
+ const children = flatten(node.children.map((child) => phrashingMark(child, marks)));
1326
+ accum.push({ type: "a", url: node.url, title: node.title, children });
1327
+ break;
1328
+ }
1329
+ case "html":
1330
+ case "text":
1331
+ const markProps = {};
1332
+ marks.forEach((mark) => markProps[mark] = true);
1333
+ accum.push({ type: "text", text: node.value, ...markProps });
1334
+ break;
1335
+ case "break":
1336
+ accum.push(breakContent());
812
1337
  break;
813
1338
  default:
814
- throw new Error(`Stringify props: ${field.type} not yet supported`);
1339
+ throw new RichTextParseError(`Unexpected inline element of type ${node.type}`, node?.position);
815
1340
  }
816
- });
817
- if (template.match) {
1341
+ return accum;
1342
+ };
1343
+ const image = (content2) => {
818
1344
  return {
819
- attributes,
820
- children: children && children.length ? children : [
821
- {
822
- type: "paragraph",
823
- children: [
824
- {
825
- type: "text",
826
- value: ""
827
- }
828
- ]
829
- }
830
- ]
1345
+ type: "img",
1346
+ url: imageCallback(content2.url),
1347
+ alt: content2.alt || void 0,
1348
+ caption: content2.title,
1349
+ children: [{ type: "text", text: "" }]
831
1350
  };
832
- }
833
- return { attributes, children };
834
- }
835
- function stringifyObj(obj, flatten2) {
836
- if (typeof obj === "object" && obj !== null) {
837
- const dummyFunc = `const dummyFunc = `;
838
- const res = format(`${dummyFunc}${JSON.stringify(obj)}`, {
839
- parser: "acorn",
840
- trailingComma: "none",
841
- semi: false
842
- }).trim().replace(dummyFunc, "");
843
- return flatten2 ? res.replaceAll("\n", "").replaceAll(" ", " ") : res;
844
- } else {
845
- console.log(obj);
846
- throw new Error(`stringifyObj must be passed an object or an array of objects, received ${typeof obj}`);
847
- }
848
- }
849
- function assertShape(value, callback, errorMessage) {
850
- if (!callback(value)) {
851
- throw new Error(errorMessage || `Failed to assert shape`);
852
- }
853
- }
854
-
855
- // src/stringify/marks.ts
856
- var matches = (a, b) => {
857
- return a.some((v) => b.includes(v));
858
- };
859
- var replaceLinksWithTextNodes = (content) => {
860
- const newItems = [];
861
- content.forEach((item) => {
862
- if (item.type === "a") {
863
- if (item.children.length === 1) {
864
- const firstChild = item.children[0];
865
- if (firstChild?.type === "text") {
866
- newItems.push({
867
- ...firstChild,
868
- linkifyTextNode: (a) => {
869
- return {
870
- type: "link",
871
- url: item.url,
872
- title: item.title,
873
- children: [a]
874
- };
875
- }
876
- });
877
- } else {
878
- newItems.push(item);
879
- }
880
- } else {
881
- newItems.push(item);
882
- }
883
- } else {
884
- newItems.push(item);
885
- }
886
- });
887
- return newItems;
888
- };
889
- var inlineElementExceptLink = (content, field, imageCallback) => {
890
- switch (content.type) {
891
- case "a":
892
- throw new Error(`Unexpected node of type "a", link elements should be processed after all inline elements have resolved`);
893
- case "img":
894
- return {
895
- type: "image",
896
- url: imageCallback(content.url),
897
- alt: content.alt,
898
- title: content.caption
899
- };
900
- case "break":
901
- return {
902
- type: "break"
903
- };
904
- case "mdxJsxTextElement": {
905
- const { attributes, children } = stringifyPropsInline(content, field, imageCallback);
906
- return {
907
- type: "mdxJsxTextElement",
908
- name: content.name,
909
- attributes,
910
- children
911
- };
912
- }
913
- case "html_inline": {
914
- return {
915
- type: "html",
916
- value: content.value
917
- };
918
- }
919
- default:
920
- if (!content.type && typeof content.text === "string") {
921
- return text(content);
1351
+ };
1352
+ const text3 = (content2) => {
1353
+ return {
1354
+ type: "text",
1355
+ text: content2.value
1356
+ };
1357
+ };
1358
+ const blockquote = (content2) => {
1359
+ const children = [];
1360
+ content2.children.map((child) => {
1361
+ const inlineElements = unwrapBlockContent(child);
1362
+ inlineElements.forEach((child2) => {
1363
+ children.push(child2);
1364
+ });
1365
+ });
1366
+ return {
1367
+ type: "blockquote",
1368
+ children
1369
+ };
1370
+ };
1371
+ const paragraph = (content2) => {
1372
+ const children = flatten(content2.children.map(phrasingContent));
1373
+ if (children.length === 1) {
1374
+ if (children[0]) {
1375
+ if (children[0].type === "html_inline") {
1376
+ return {
1377
+ ...children[0],
1378
+ type: "html"
1379
+ };
1380
+ }
922
1381
  }
923
- throw new Error(`InlineElement: ${content.type} is not supported`);
924
- }
925
- };
926
- var text = (content) => {
1382
+ }
1383
+ return {
1384
+ type: "p",
1385
+ children
1386
+ };
1387
+ };
927
1388
  return {
928
- type: "text",
929
- value: content.text
1389
+ type: "root",
1390
+ children: root.children.map((child) => {
1391
+ return content(child);
1392
+ })
930
1393
  };
931
1394
  };
932
- var eat = (c, field, imageCallback) => {
933
- const content = replaceLinksWithTextNodes(c);
934
- const first = content[0];
935
- if (!first) {
936
- return [];
1395
+ var RichTextParseError = class extends Error {
1396
+ constructor(message, position) {
1397
+ super(message);
1398
+ __publicField(this, "position");
1399
+ if (Error.captureStackTrace) {
1400
+ Error.captureStackTrace(this, RichTextParseError);
1401
+ }
1402
+ this.name = "RichTextParseError";
1403
+ this.position = position;
937
1404
  }
938
- if (first && first?.type !== "text") {
939
- if (first.type === "a") {
940
- return [
941
- {
942
- type: "link",
943
- url: first.url,
944
- title: first.title,
945
- children: eat(first.children, field, imageCallback)
946
- },
947
- ...eat(content.slice(1), field, imageCallback)
948
- ];
1405
+ };
1406
+
1407
+ // src/extensions/tina-shortcodes/from-markdown.ts
1408
+ import { parseEntities } from "parse-entities";
1409
+ var enterContainer = function(token) {
1410
+ enter.call(this, "containerDirective", token);
1411
+ };
1412
+ var enterLeaf = function(token) {
1413
+ enter.call(this, "leafDirective", token);
1414
+ };
1415
+ var enterText = function(token) {
1416
+ enter.call(this, "textDirective", token);
1417
+ };
1418
+ var enter = function(type, token) {
1419
+ this.enter({ type, name: "", attributes: {}, children: [] }, token);
1420
+ };
1421
+ function exitName(token) {
1422
+ const node = this.stack[this.stack.length - 1];
1423
+ node.name = this.sliceSerialize(token);
1424
+ }
1425
+ var enterContainerLabel = function(token) {
1426
+ this.enter({ type: "paragraph", data: { directiveLabel: true }, children: [] }, token);
1427
+ };
1428
+ var exitContainerLabel = function(token) {
1429
+ this.exit(token);
1430
+ };
1431
+ var enterAttributes = function() {
1432
+ this.setData("directiveAttributes", []);
1433
+ this.buffer();
1434
+ };
1435
+ var exitAttributeIdValue = function(token) {
1436
+ const list = this.getData("directiveAttributes");
1437
+ if (list) {
1438
+ list.push([
1439
+ "id",
1440
+ parseEntities(this.sliceSerialize(token), {
1441
+ attribute: true
1442
+ })
1443
+ ]);
1444
+ }
1445
+ };
1446
+ var exitAttributeClassValue = function(token) {
1447
+ const list = this.getData("directiveAttributes");
1448
+ if (list) {
1449
+ list.push([
1450
+ "class",
1451
+ parseEntities(this.sliceSerialize(token), {
1452
+ attribute: true
1453
+ })
1454
+ ]);
1455
+ }
1456
+ };
1457
+ var exitAttributeValue = function(token) {
1458
+ const list = this.getData("directiveAttributes");
1459
+ if (list) {
1460
+ const item = list[list.length - 1];
1461
+ if (item) {
1462
+ item[1] = parseEntities(this.sliceSerialize(token), {
1463
+ attribute: true
1464
+ });
949
1465
  }
950
- return [
951
- inlineElementExceptLink(first, field, imageCallback),
952
- ...eat(content.slice(1), field, imageCallback)
953
- ];
954
1466
  }
955
- const marks = getMarks(first);
956
- if (marks.length === 0) {
957
- if (first.linkifyTextNode) {
958
- return [
959
- first.linkifyTextNode(text(first)),
960
- ...eat(content.slice(1), field, imageCallback)
961
- ];
1467
+ };
1468
+ var exitAttributeName = function(token) {
1469
+ const list = this.getData("directiveAttributes");
1470
+ if (list) {
1471
+ const name = this.sliceSerialize(token);
1472
+ if (!name) {
1473
+ list.push(["_value", ""]);
962
1474
  } else {
963
- return [text(first), ...eat(content.slice(1), field, imageCallback)];
1475
+ list.push([this.sliceSerialize(token), ""]);
964
1476
  }
965
1477
  }
966
- let nonMatchingSiblingIndex = 0;
967
- if (content.slice(1).every((content2, index) => {
968
- if (matches(marks, getMarks(content2))) {
969
- return true;
970
- } else {
971
- nonMatchingSiblingIndex = index;
972
- return false;
1478
+ };
1479
+ function exitAttributes() {
1480
+ const list = this.getData("directiveAttributes");
1481
+ const cleaned = {};
1482
+ let index = -1;
1483
+ if (list) {
1484
+ while (++index < list.length) {
1485
+ const attribute = list[index];
1486
+ if (attribute) {
1487
+ if (attribute[0] === "class" && cleaned.class) {
1488
+ cleaned.class += " " + attribute[1];
1489
+ } else {
1490
+ cleaned[attribute[0]] = attribute[1];
1491
+ }
1492
+ }
973
1493
  }
974
- })) {
975
- nonMatchingSiblingIndex = content.length - 1;
976
1494
  }
977
- const matchingSiblings = content.slice(1, nonMatchingSiblingIndex + 1);
978
- const markCounts = {};
979
- marks.forEach((mark) => {
980
- let count2 = 1;
981
- matchingSiblings.every((sibling, index) => {
982
- if (getMarks(sibling).includes(mark)) {
983
- count2 = index + 1;
984
- return true;
1495
+ this.setData("directiveAttributes");
1496
+ this.resume();
1497
+ const node = this.stack[this.stack.length - 1];
1498
+ node.attributes = cleaned;
1499
+ }
1500
+ function exit(token) {
1501
+ this.exit(token);
1502
+ }
1503
+ var directiveFromMarkdown = {
1504
+ canContainEols: ["textDirective"],
1505
+ enter: {
1506
+ directiveContainer: enterContainer,
1507
+ directiveContainerAttributes: enterAttributes,
1508
+ directiveContainerLabel: enterContainerLabel,
1509
+ directiveLeaf: enterLeaf,
1510
+ directiveLeafAttributes: enterAttributes,
1511
+ directiveText: enterText,
1512
+ directiveTextAttributes: enterAttributes
1513
+ },
1514
+ exit: {
1515
+ directiveContainer: exit,
1516
+ directiveContainerAttributeClassValue: exitAttributeClassValue,
1517
+ directiveContainerAttributeIdValue: exitAttributeIdValue,
1518
+ directiveContainerAttributeName: exitAttributeName,
1519
+ directiveContainerAttributeValue: exitAttributeValue,
1520
+ directiveContainerAttributes: exitAttributes,
1521
+ directiveContainerLabel: exitContainerLabel,
1522
+ directiveContainerName: exitName,
1523
+ directiveLeaf: exit,
1524
+ directiveLeafAttributeClassValue: exitAttributeClassValue,
1525
+ directiveLeafAttributeIdValue: exitAttributeIdValue,
1526
+ directiveLeafAttributeName: exitAttributeName,
1527
+ directiveLeafAttributeValue: exitAttributeValue,
1528
+ directiveLeafAttributes: exitAttributes,
1529
+ directiveLeafName: exitName,
1530
+ directiveText: exit,
1531
+ directiveTextAttributeClassValue: exitAttributeClassValue,
1532
+ directiveTextAttributeIdValue: exitAttributeIdValue,
1533
+ directiveTextAttributeName: exitAttributeName,
1534
+ directiveTextAttributeValue: exitAttributeValue,
1535
+ directiveTextAttributes: exitAttributes,
1536
+ directiveTextName: exitName
1537
+ }
1538
+ };
1539
+
1540
+ // src/extensions/tina-shortcodes/shortcode-leaf.ts
1541
+ import { factorySpace as factorySpace2 } from "micromark-factory-space";
1542
+ import { markdownLineEnding as markdownLineEnding2, markdownSpace as markdownSpace2 } from "micromark-util-character";
1543
+ import { codes as codes3 } from "micromark-util-symbol/codes";
1544
+ import { values } from "micromark-util-symbol/values";
1545
+ import { types as types2 } from "micromark-util-symbol/types";
1546
+
1547
+ // src/extensions/tina-shortcodes/factory-attributes.ts
1548
+ import { factorySpace } from "micromark-factory-space";
1549
+ import { factoryWhitespace } from "micromark-factory-whitespace";
1550
+ import {
1551
+ asciiAlpha,
1552
+ asciiAlphanumeric,
1553
+ markdownLineEnding,
1554
+ markdownLineEndingOrSpace,
1555
+ markdownSpace
1556
+ } from "micromark-util-character";
1557
+ import { codes } from "micromark-util-symbol/codes";
1558
+ import { types } from "micromark-util-symbol/types";
1559
+ function factoryAttributes(effects, ok, nnok, attributesType, attributesMarkerType, attributeType, attributeIdType, attributeClassType, attributeNameType, attributeInitializerType, attributeValueLiteralType, attributeValueType, attributeValueMarker, attributeValueData, disallowEol) {
1560
+ let type;
1561
+ let marker;
1562
+ const nok = function(code) {
1563
+ return nnok(code);
1564
+ };
1565
+ const start = function(code) {
1566
+ effects.enter(attributesType);
1567
+ return between(code);
1568
+ };
1569
+ const between = function(code) {
1570
+ if (code === codes.numberSign) {
1571
+ type = attributeIdType;
1572
+ return shortcutStart(code);
1573
+ }
1574
+ if (code === codes.dot) {
1575
+ type = attributeClassType;
1576
+ return shortcutStart(code);
1577
+ }
1578
+ if (code === codes.colon || code === codes.underscore || asciiAlpha(code)) {
1579
+ effects.enter(attributeType);
1580
+ effects.enter(attributeNameType);
1581
+ effects.consume(code);
1582
+ return name;
1583
+ }
1584
+ if (code === codes.quotationMark || code === codes.apostrophe) {
1585
+ effects.enter(attributeNameType);
1586
+ effects.exit(attributeNameType);
1587
+ effects.enter(attributeType);
1588
+ return valueBefore(code);
1589
+ }
1590
+ if (disallowEol && markdownSpace(code)) {
1591
+ return factorySpace(effects, between, types.whitespace)(code);
1592
+ }
1593
+ if (!disallowEol && markdownLineEndingOrSpace(code)) {
1594
+ return factoryWhitespace(effects, between)(code);
1595
+ }
1596
+ return end(code);
1597
+ };
1598
+ const shortcutStart = function(code) {
1599
+ effects.enter(attributeType);
1600
+ effects.enter(type);
1601
+ effects.enter(type + "Marker");
1602
+ effects.consume(code);
1603
+ effects.exit(type + "Marker");
1604
+ return shortcutStartAfter;
1605
+ };
1606
+ const shortcutStartAfter = function(code) {
1607
+ if (code === codes.eof || code === codes.quotationMark || code === codes.numberSign || code === codes.apostrophe || code === codes.dot || code === codes.lessThan || code === codes.equalsTo || code === codes.greaterThan || code === codes.graveAccent || code === codes.rightCurlyBrace || markdownLineEndingOrSpace(code)) {
1608
+ return nok(code);
1609
+ }
1610
+ effects.enter(type + "Value");
1611
+ effects.consume(code);
1612
+ return shortcut;
1613
+ };
1614
+ const shortcut = function(code) {
1615
+ if (code === codes.eof || code === codes.quotationMark || code === codes.apostrophe || code === codes.lessThan || code === codes.equalsTo || code === codes.greaterThan || code === codes.graveAccent) {
1616
+ return nok(code);
1617
+ }
1618
+ if (code === codes.numberSign || code === codes.dot || code === codes.rightCurlyBrace || markdownLineEndingOrSpace(code)) {
1619
+ effects.exit(type + "Value");
1620
+ effects.exit(type);
1621
+ effects.exit(attributeType);
1622
+ return between(code);
1623
+ }
1624
+ effects.consume(code);
1625
+ return shortcut;
1626
+ };
1627
+ const name = function(code) {
1628
+ if (code === codes.dash || code === codes.dot || code === codes.colon || code === codes.underscore || asciiAlphanumeric(code)) {
1629
+ effects.consume(code);
1630
+ return name;
1631
+ }
1632
+ effects.exit(attributeNameType);
1633
+ if (disallowEol && markdownSpace(code)) {
1634
+ return factorySpace(effects, nameAfter, types.whitespace)(code);
1635
+ }
1636
+ if (!disallowEol && markdownLineEndingOrSpace(code)) {
1637
+ return factoryWhitespace(effects, nameAfter)(code);
1638
+ }
1639
+ return nameAfter(code);
1640
+ };
1641
+ const nameAfter = function(code) {
1642
+ if (code === codes.equalsTo) {
1643
+ effects.enter(attributeInitializerType);
1644
+ effects.consume(code);
1645
+ effects.exit(attributeInitializerType);
1646
+ return valueBefore;
1647
+ }
1648
+ effects.exit(attributeType);
1649
+ return between(code);
1650
+ };
1651
+ const valueBefore = function(code) {
1652
+ if (code === codes.eof || code === codes.lessThan || code === codes.equalsTo || code === codes.greaterThan || code === codes.graveAccent || code === codes.rightCurlyBrace || disallowEol && markdownLineEnding(code)) {
1653
+ return nok(code);
1654
+ }
1655
+ if (code === codes.quotationMark || code === codes.apostrophe) {
1656
+ effects.enter(attributeValueLiteralType);
1657
+ effects.enter(attributeValueMarker);
1658
+ effects.consume(code);
1659
+ effects.exit(attributeValueMarker);
1660
+ marker = code;
1661
+ return valueQuotedStart;
1662
+ }
1663
+ if (disallowEol && markdownSpace(code)) {
1664
+ return factorySpace(effects, valueBefore, types.whitespace)(code);
1665
+ }
1666
+ if (!disallowEol && markdownLineEndingOrSpace(code)) {
1667
+ return factoryWhitespace(effects, valueBefore)(code);
1668
+ }
1669
+ effects.enter(attributeValueType);
1670
+ effects.enter(attributeValueData);
1671
+ effects.consume(code);
1672
+ marker = void 0;
1673
+ return valueUnquoted;
1674
+ };
1675
+ const valueUnquoted = function(code) {
1676
+ if (code === codes.eof || code === codes.quotationMark || code === codes.apostrophe || code === codes.lessThan || code === codes.equalsTo || code === codes.greaterThan || code === codes.graveAccent) {
1677
+ return nok(code);
1678
+ }
1679
+ if (code === codes.rightCurlyBrace || markdownLineEndingOrSpace(code)) {
1680
+ effects.exit(attributeValueData);
1681
+ effects.exit(attributeValueType);
1682
+ effects.exit(attributeType);
1683
+ return between(code);
1684
+ }
1685
+ effects.consume(code);
1686
+ return valueUnquoted;
1687
+ };
1688
+ const valueQuotedStart = function(code) {
1689
+ if (code === marker) {
1690
+ effects.enter(attributeValueMarker);
1691
+ effects.consume(code);
1692
+ effects.exit(attributeValueMarker);
1693
+ effects.exit(attributeValueLiteralType);
1694
+ effects.exit(attributeType);
1695
+ return valueQuotedAfter;
1696
+ }
1697
+ effects.enter(attributeValueType);
1698
+ return valueQuotedBetween(code);
1699
+ };
1700
+ const valueQuotedBetween = function(code) {
1701
+ if (code === marker) {
1702
+ effects.exit(attributeValueType);
1703
+ return valueQuotedStart(code);
1704
+ }
1705
+ if (code === codes.eof) {
1706
+ return nok(code);
1707
+ }
1708
+ if (markdownLineEnding(code)) {
1709
+ return disallowEol ? nok(code) : factoryWhitespace(effects, valueQuotedBetween)(code);
1710
+ }
1711
+ effects.enter(attributeValueData);
1712
+ effects.consume(code);
1713
+ return valueQuoted;
1714
+ };
1715
+ const valueQuoted = function(code) {
1716
+ if (code === marker || code === codes.eof || markdownLineEnding(code)) {
1717
+ effects.exit(attributeValueData);
1718
+ return valueQuotedBetween(code);
1719
+ }
1720
+ effects.consume(code);
1721
+ return valueQuoted;
1722
+ };
1723
+ const valueQuotedAfter = function(code) {
1724
+ return code === codes.rightCurlyBrace || markdownLineEndingOrSpace(code) ? between(code) : end(code);
1725
+ };
1726
+ const end = function(code) {
1727
+ if (!asciiAlpha(code)) {
1728
+ effects.enter(attributesMarkerType);
1729
+ effects.exit(attributesMarkerType);
1730
+ effects.exit(attributesType);
1731
+ return ok(code);
1732
+ }
1733
+ return nok(code);
1734
+ };
1735
+ return start;
1736
+ }
1737
+
1738
+ // src/extensions/tina-shortcodes/factory-name.ts
1739
+ import { asciiAlpha as asciiAlpha2, asciiAlphanumeric as asciiAlphanumeric2 } from "micromark-util-character";
1740
+ import { codes as codes2 } from "micromark-util-symbol/codes";
1741
+ function factoryName(effects, ok, nok, type, patternName) {
1742
+ const self = this;
1743
+ let nameIndex = 0;
1744
+ const start = function(code) {
1745
+ const character = patternName[nameIndex];
1746
+ if (asciiAlpha2(code) && findCode(character) === code) {
1747
+ nameIndex++;
1748
+ effects.enter(type);
1749
+ effects.consume(code);
1750
+ return name;
1751
+ }
1752
+ return nok(code);
1753
+ };
1754
+ const name = function(code) {
1755
+ const character = patternName[nameIndex];
1756
+ if (code === codes2.dash || code === codes2.underscore || asciiAlphanumeric2(code)) {
1757
+ if (findCode(character) === code) {
1758
+ effects.consume(code);
1759
+ nameIndex++;
1760
+ return name;
985
1761
  }
986
- });
987
- markCounts[mark] = count2;
988
- });
989
- let count = 0;
990
- let markToProcess = null;
991
- Object.entries(markCounts).forEach(([mark, markCount]) => {
992
- const m = mark;
993
- if (markCount > count) {
994
- count = markCount;
995
- markToProcess = m;
1762
+ return nok(code);
1763
+ }
1764
+ effects.exit(type);
1765
+ return self.previous === codes2.dash || self.previous === codes2.underscore ? nok(code) : ok(code);
1766
+ };
1767
+ return start;
1768
+ }
1769
+
1770
+ // src/extensions/tina-shortcodes/shortcode-leaf.ts
1771
+ var findValue = (string) => {
1772
+ let lookupValue = null;
1773
+ Object.entries(values).forEach(([key, value]) => {
1774
+ if (value === string) {
1775
+ lookupValue = key;
996
1776
  }
997
1777
  });
998
- if (!markToProcess) {
999
- return [text(first), ...eat(content.slice(1), field, imageCallback)];
1778
+ return lookupValue;
1779
+ };
1780
+ var findCode = (string) => {
1781
+ if (!string) {
1782
+ return null;
1000
1783
  }
1001
- if (markToProcess === "inlineCode") {
1002
- if (nonMatchingSiblingIndex) {
1003
- throw new Error(`Marks inside inline code are not supported`);
1004
- }
1005
- const node = {
1006
- type: markToProcess,
1007
- value: first.text
1784
+ const lookup = findValue(string);
1785
+ let lookupValue = null;
1786
+ if (lookup) {
1787
+ Object.entries(codes3).forEach(([key, value]) => {
1788
+ if (key === lookup) {
1789
+ lookupValue = value;
1790
+ }
1791
+ });
1792
+ }
1793
+ return lookupValue;
1794
+ };
1795
+ var directiveLeaf = (pattern) => {
1796
+ const tokenizeDirectiveLeaf = function(effects, ook, nnok) {
1797
+ const self = this;
1798
+ let startSequenceIndex = 1;
1799
+ let endSequenceIndex = 0;
1800
+ const ok = function(code) {
1801
+ return ook(code);
1802
+ };
1803
+ const nok = function(code) {
1804
+ return nnok(code);
1805
+ };
1806
+ const start = function(code) {
1807
+ const firstCharacter = pattern.start[0];
1808
+ if (findCode(firstCharacter) === code) {
1809
+ effects.enter("directiveLeaf");
1810
+ effects.enter("directiveLeafFence");
1811
+ effects.enter("directiveLeafSequence");
1812
+ effects.consume(code);
1813
+ return sequenceOpen(code);
1814
+ }
1815
+ return nok(code);
1816
+ };
1817
+ const sequenceOpen = function(code) {
1818
+ const nextCharacter = pattern.start[startSequenceIndex];
1819
+ if (findCode(nextCharacter) === code) {
1820
+ effects.consume(code);
1821
+ startSequenceIndex++;
1822
+ return sequenceOpen;
1823
+ }
1824
+ if (startSequenceIndex < pattern.start.length) {
1825
+ return nok(code);
1826
+ }
1827
+ effects.exit("directiveLeafSequence");
1828
+ return factorName(code);
1829
+ };
1830
+ const factorName = (code) => {
1831
+ if (markdownSpace2(code)) {
1832
+ return factorySpace2(effects, factorName, types2.whitespace)(code);
1833
+ }
1834
+ return factoryName.call(self, effects, afterName, nok, "directiveLeafName", pattern.name || pattern.templateName)(code);
1835
+ };
1836
+ const afterName = function(code) {
1837
+ if (markdownSpace2(code)) {
1838
+ return factorySpace2(effects, afterName, types2.whitespace)(code);
1839
+ }
1840
+ if (markdownLineEnding2(code)) {
1841
+ return nok;
1842
+ }
1843
+ return startAttributes;
1844
+ };
1845
+ const startAttributes = function(code) {
1846
+ const nextCharacter = pattern.end[endSequenceIndex];
1847
+ if (findCode(nextCharacter) === code) {
1848
+ return afterAttributes(code);
1849
+ }
1850
+ return effects.attempt(attributes2, afterAttributes, afterAttributes)(code);
1851
+ };
1852
+ const end = function(code) {
1853
+ effects.exit("directiveLeafFence");
1854
+ effects.exit("directiveLeaf");
1855
+ return ok(code);
1856
+ };
1857
+ const afterAttributes = function(code) {
1858
+ const nextCharacter = pattern.end[endSequenceIndex];
1859
+ if (pattern.end.length === endSequenceIndex) {
1860
+ return factorySpace2(effects, end, types2.whitespace)(code);
1861
+ }
1862
+ if (code === codes3.eof) {
1863
+ return nok;
1864
+ }
1865
+ if (findCode(nextCharacter) === code) {
1866
+ effects.consume(code);
1867
+ endSequenceIndex++;
1868
+ return afterAttributes;
1869
+ }
1870
+ return nok;
1871
+ };
1872
+ return start;
1873
+ };
1874
+ const tokenizeAttributes = function(effects, ok, nok) {
1875
+ return factoryAttributes(effects, ok, nok, "directiveLeafAttributes", "directiveLeafAttributesMarker", "directiveLeafAttribute", "directiveLeafAttributeId", "directiveLeafAttributeClass", "directiveLeafAttributeName", "directiveLeafAttributeInitializerMarker", "directiveLeafAttributeValueLiteral", "directiveLeafAttributeValue", "directiveLeafAttributeValueMarker", "directiveLeafAttributeValueData", true);
1876
+ };
1877
+ const attributes2 = { tokenize: tokenizeAttributes, partial: true };
1878
+ return {
1879
+ tokenize: tokenizeDirectiveLeaf
1880
+ };
1881
+ };
1882
+
1883
+ // src/extensions/tina-shortcodes/shortcode-container.ts
1884
+ import { ok as assert } from "uvu/assert";
1885
+ import { factorySpace as factorySpace3 } from "micromark-factory-space";
1886
+ import { markdownLineEnding as markdownLineEnding3, markdownSpace as markdownSpace3 } from "micromark-util-character";
1887
+ import { codes as codes4 } from "micromark-util-symbol/codes";
1888
+ import { constants } from "micromark-util-symbol/constants";
1889
+ import { types as types3 } from "micromark-util-symbol/types";
1890
+ var directiveContainer = (pattern) => {
1891
+ const tokenizeDirectiveContainer = function(effects, ook, nnok) {
1892
+ const self = this;
1893
+ const tail = self.events[self.events.length - 1];
1894
+ const initialSize = tail && tail[1].type === types3.linePrefix ? tail[2].sliceSerialize(tail[1], true).length : 0;
1895
+ let previous;
1896
+ let startSequenceIndex = 1;
1897
+ let closeStartSequenceIndex = 0;
1898
+ let endNameIndex = 0;
1899
+ let endSequenceIndex = 0;
1900
+ let closeEndSequenceIndex = 0;
1901
+ const ok = function(code) {
1902
+ return ook(code);
1903
+ };
1904
+ const nok = function(code) {
1905
+ return nnok(code);
1906
+ };
1907
+ const start = function(code) {
1908
+ const firstCharacter = pattern.start[0];
1909
+ if (findCode(firstCharacter) === code) {
1910
+ effects.enter("directiveContainer");
1911
+ effects.enter("directiveContainerFence");
1912
+ effects.enter("directiveContainerSequence");
1913
+ effects.consume(code);
1914
+ return sequenceOpen(code);
1915
+ }
1916
+ return nok(code);
1917
+ };
1918
+ const sequenceOpen = function(code) {
1919
+ const nextCharacter = pattern.start[startSequenceIndex];
1920
+ if (findCode(nextCharacter) === code) {
1921
+ effects.consume(code);
1922
+ startSequenceIndex++;
1923
+ return sequenceOpen;
1924
+ }
1925
+ if (startSequenceIndex < pattern.start.length) {
1926
+ return nok(code);
1927
+ }
1928
+ effects.exit("directiveContainerSequence");
1929
+ return factorName(code);
1930
+ };
1931
+ const factorName = (code) => {
1932
+ if (markdownSpace3(code)) {
1933
+ return factorySpace3(effects, factorName, types3.whitespace)(code);
1934
+ }
1935
+ return factoryName.call(self, effects, afterName, nok, "directiveContainerName", pattern.name || pattern.templateName)(code);
1936
+ };
1937
+ const afterName = function(code) {
1938
+ if (markdownSpace3(code)) {
1939
+ return factorySpace3(effects, afterName, types3.whitespace)(code);
1940
+ }
1941
+ if (markdownLineEnding3(code)) {
1942
+ return nok;
1943
+ }
1944
+ return startAttributes;
1945
+ };
1946
+ const startAttributes = function(code) {
1947
+ const nextCharacter = pattern.end[endSequenceIndex];
1948
+ if (findCode(nextCharacter) === code) {
1949
+ return afterAttributes(code);
1950
+ }
1951
+ return effects.attempt(attributes2, afterAttributes, afterAttributes)(code);
1952
+ };
1953
+ const afterAttributes = function(code) {
1954
+ const nextCharacter = pattern.end[endSequenceIndex];
1955
+ if (code === codes4.eof) {
1956
+ return nok;
1957
+ }
1958
+ if (findCode(nextCharacter) === code) {
1959
+ effects.consume(code);
1960
+ endSequenceIndex++;
1961
+ return afterAttributes;
1962
+ }
1963
+ if (pattern.end.length === endSequenceIndex) {
1964
+ return factorySpace3(effects, openAfter, types3.whitespace)(code);
1965
+ }
1966
+ return nok;
1967
+ };
1968
+ const openAfter = function(code) {
1969
+ effects.exit("directiveContainerFence");
1970
+ if (code === codes4.eof) {
1971
+ return afterOpening(code);
1972
+ }
1973
+ if (markdownLineEnding3(code)) {
1974
+ if (self.interrupt) {
1975
+ return nok(code);
1976
+ }
1977
+ return effects.attempt(nonLazyLine, contentStart, afterOpening)(code);
1978
+ }
1979
+ return nok(code);
1980
+ };
1981
+ const afterOpening = function(code) {
1982
+ return nok(code);
1983
+ };
1984
+ const contentStart = function(code) {
1985
+ if (code === codes4.eof) {
1986
+ return nok(code);
1987
+ }
1988
+ effects.enter("directiveContainerContent");
1989
+ return lineStart(code);
1990
+ };
1991
+ const lineStart = function(code) {
1992
+ if (code === codes4.eof) {
1993
+ return nok(code);
1994
+ }
1995
+ return effects.attempt({ tokenize: tokenizeClosingFence, partial: true }, after, initialSize ? factorySpace3(effects, chunkStart, types3.linePrefix, initialSize + 1) : chunkStart)(code);
1996
+ };
1997
+ const chunkStart = function(code) {
1998
+ if (code === codes4.eof) {
1999
+ return nok(code);
2000
+ }
2001
+ const token = effects.enter(types3.chunkDocument, {
2002
+ contentType: constants.contentTypeDocument,
2003
+ previous
2004
+ });
2005
+ if (previous)
2006
+ previous.next = token;
2007
+ previous = token;
2008
+ return contentContinue(code);
2009
+ };
2010
+ const contentContinue = function(code) {
2011
+ if (code === codes4.eof) {
2012
+ const t = effects.exit(types3.chunkDocument);
2013
+ self.parser.lazy[t.start.line] = false;
2014
+ return nok(code);
2015
+ }
2016
+ if (markdownLineEnding3(code)) {
2017
+ return effects.check(nonLazyLine, nonLazyLineAfter, lineAfter)(code);
2018
+ }
2019
+ effects.consume(code);
2020
+ return contentContinue;
2021
+ };
2022
+ const nonLazyLineAfter = function(code) {
2023
+ effects.consume(code);
2024
+ const t = effects.exit(types3.chunkDocument);
2025
+ self.parser.lazy[t.start.line] = false;
2026
+ return lineStart;
2027
+ };
2028
+ const lineAfter = function(code) {
2029
+ const t = effects.exit(types3.chunkDocument);
2030
+ self.parser.lazy[t.start.line] = false;
2031
+ return after(code);
2032
+ };
2033
+ const after = function(code) {
2034
+ effects.exit("directiveContainerContent");
2035
+ effects.exit("directiveContainer");
2036
+ return ok(code);
2037
+ };
2038
+ const tokenizeClosingFence = function(effects2, ok2, nok2) {
2039
+ const closingPrefixAfter = function(code) {
2040
+ effects2.enter("directiveContainerFence");
2041
+ effects2.enter("directiveContainerSequence");
2042
+ return closingSequence(code);
2043
+ };
2044
+ const closingSequence = function(code) {
2045
+ const nextCharacter = pattern.start[closeStartSequenceIndex];
2046
+ if (findCode(nextCharacter) === code) {
2047
+ effects2.consume(code);
2048
+ closeStartSequenceIndex++;
2049
+ return closingSequence;
2050
+ }
2051
+ if (closeStartSequenceIndex < pattern.end.length - 1) {
2052
+ return nok2(code);
2053
+ }
2054
+ effects2.exit("directiveContainerSequence");
2055
+ return factorySpace3(effects2, closingSequenceNameStart, types3.whitespace)(code);
2056
+ };
2057
+ const closingSequenceName = function(code) {
2058
+ const patternName = pattern.name || pattern.templateName;
2059
+ const nextCharacter = patternName[endNameIndex];
2060
+ if (code === codes4.eof) {
2061
+ return nok2;
2062
+ }
2063
+ if (markdownLineEnding3(code)) {
2064
+ return nok2;
2065
+ }
2066
+ if (findCode(nextCharacter) === code) {
2067
+ effects2.consume(code);
2068
+ endNameIndex++;
2069
+ return closingSequenceName;
2070
+ }
2071
+ if (patternName.length === endNameIndex) {
2072
+ return closingSequenceEnd;
2073
+ }
2074
+ return nok2;
2075
+ };
2076
+ const closingSequenceNameStart = function(code) {
2077
+ if (markdownSpace3(code)) {
2078
+ return factorySpace3(effects2, closingSequenceNameStart, types3.whitespace);
2079
+ }
2080
+ if (code === codes4.backslash) {
2081
+ effects2.consume(code);
2082
+ return closingSequenceName;
2083
+ }
2084
+ return nok2(code);
2085
+ };
2086
+ const closingSequenceEnd = function(code) {
2087
+ if (markdownSpace3(code)) {
2088
+ return factorySpace3(effects2, closingSequenceEnd, types3.whitespace);
2089
+ }
2090
+ if (code === codes4.eof) {
2091
+ return nok2;
2092
+ }
2093
+ if (pattern.end.length - 1 === closeEndSequenceIndex) {
2094
+ effects2.exit("directiveContainerFence");
2095
+ return ok2(code);
2096
+ }
2097
+ const nextCharacter = pattern.end[closeEndSequenceIndex];
2098
+ if (findCode(nextCharacter) === code) {
2099
+ effects2.consume(code);
2100
+ closeEndSequenceIndex++;
2101
+ return closingSequenceEnd;
2102
+ }
2103
+ return nok2(code);
2104
+ };
2105
+ return factorySpace3(effects2, closingPrefixAfter, types3.linePrefix, constants.tabSize);
2106
+ };
2107
+ return start;
2108
+ };
2109
+ const tokenizeAttributes = function(effects, ok, nok) {
2110
+ return factoryAttributes(effects, ok, nok, "directiveContainerAttributes", "directiveContainerAttributesMarker", "directiveContainerAttribute", "directiveContainerAttributeId", "directiveContainerAttributeClass", "directiveContainerAttributeName", "directiveContainerAttributeInitializerMarker", "directiveContainerAttributeValueLiteral", "directiveContainerAttributeValue", "directiveContainerAttributeValueMarker", "directiveContainerAttributeValueData", true);
2111
+ };
2112
+ const tokenizeNonLazyLine = function(effects, ok, nok) {
2113
+ const self = this;
2114
+ const lineStart = function(code) {
2115
+ return self.parser.lazy[self.now().line] ? nok(code) : ok(code);
1008
2116
  };
1009
- return [
1010
- first.linkifyTextNode?.(node) ?? node,
1011
- ...eat(content.slice(nonMatchingSiblingIndex + 1), field, imageCallback)
1012
- ];
1013
- }
1014
- return [
1015
- {
1016
- type: markToProcess,
1017
- children: eat([
1018
- ...[first, ...matchingSiblings].map((sibling) => cleanNode(sibling, markToProcess))
1019
- ], field, imageCallback)
1020
- },
1021
- ...eat(content.slice(nonMatchingSiblingIndex + 1), field, imageCallback)
1022
- ];
2117
+ const start = function(code) {
2118
+ assert(markdownLineEnding3(code), "expected eol");
2119
+ effects.enter(types3.lineEnding);
2120
+ effects.consume(code);
2121
+ effects.exit(types3.lineEnding);
2122
+ return lineStart;
2123
+ };
2124
+ return start;
2125
+ };
2126
+ const attributes2 = { tokenize: tokenizeAttributes, partial: true };
2127
+ const nonLazyLine = { tokenize: tokenizeNonLazyLine, partial: true };
2128
+ return {
2129
+ tokenize: tokenizeDirectiveContainer,
2130
+ concrete: true
2131
+ };
1023
2132
  };
1024
- var cleanNode = (node, mark) => {
1025
- if (!mark) {
1026
- return node;
1027
- }
1028
- const cleanedNode = {};
1029
- const markToClear = {
1030
- strong: "bold",
1031
- emphasis: "italic",
1032
- inlineCode: "code"
1033
- }[mark];
1034
- Object.entries(node).map(([key, value]) => {
1035
- if (key !== markToClear) {
1036
- cleanedNode[key] = value;
2133
+
2134
+ // src/extensions/tina-shortcodes/extension.ts
2135
+ var tinaDirective = function(patterns) {
2136
+ const rules = {};
2137
+ patterns.forEach((pattern) => {
2138
+ const firstKey = pattern.start[0];
2139
+ if (firstKey) {
2140
+ const code = findCode(firstKey);
2141
+ if (code) {
2142
+ if (pattern.type === "leaf") {
2143
+ const directive = directiveLeaf(pattern);
2144
+ if (rules[code]) {
2145
+ rules[code] = [...rules[code] || [], directive];
2146
+ } else {
2147
+ rules[code] = [directive];
2148
+ }
2149
+ }
2150
+ if (pattern.type === "block") {
2151
+ const directive = directiveContainer(pattern);
2152
+ if (rules[code]) {
2153
+ rules[code] = [...rules[code] || [], directive];
2154
+ } else {
2155
+ rules[code] = [directive];
2156
+ }
2157
+ }
2158
+ }
1037
2159
  }
1038
2160
  });
1039
- if (node.linkifyTextNode) {
1040
- cleanedNode.callback = node.linkifyTextNode;
1041
- }
1042
- return cleanedNode;
2161
+ return {
2162
+ flow: rules
2163
+ };
1043
2164
  };
1044
2165
 
1045
- // src/stringify/stringifyShortcode.ts
1046
- function stringifyShortcode(preprocessedString, template) {
2166
+ // src/parse/parseShortcode.ts
2167
+ function parseShortcode(preprocessedString, template) {
1047
2168
  const match = template.match;
1048
- const unkeyedAttributes = !!template.fields.find((t) => t.name == "_value");
1049
- const regex = `<[\\s]*${template.name}[\\s]*${unkeyedAttributes ? "(?:_value=(.*?))?" : "(.+?)?"}[\\s]*>[\\s]*((?:.|
1050
- )*?)[\\s]*</[\\s]*${template.name}[\\s]*>`;
1051
- const closingRegex = `
1052
- $2
1053
- ${match.start} /${match.name || template.name} ${match.end}`;
1054
- const replace = `${match.start} ${match.name || template.name} $1 ${match.end}${template.fields.find((t) => t.name == "children") ? closingRegex : ""}`;
1055
- return replaceAll(preprocessedString, regex, replace);
2169
+ const unkeyedAttributes = !!template.fields.find((t) => t.name === "_value");
2170
+ const hasChildren = !!template.fields.find((t) => t.name == "children");
2171
+ const replacement = `<${template.name} ${unkeyedAttributes ? '_value="$1"' : "$1"}>${hasChildren ? "$2" : "\n"}</${template.name}>`;
2172
+ const endRegex = `((?:.|\\n)*)${match.start}\\s/\\s*${match.name || template.name}[\\s]*${match.end}`;
2173
+ const regex = `${match.start}\\s*${match.name || template.name}[\\s]+${unkeyedAttributes ? `['"]?(.*?)['"]?` : "(.*?)"}[\\s]*${match.end}${hasChildren ? endRegex : ""}`;
2174
+ return replaceAll(preprocessedString, regex, replacement);
1056
2175
  }
1057
2176
 
1058
- // src/stringify/index.ts
1059
- var stringifyMDX = (value, field, imageCallback) => {
1060
- if (!value) {
1061
- return;
1062
- }
1063
- if (typeof value === "string") {
1064
- throw new Error("Expected an object to stringify, but received a string");
1065
- }
1066
- if (value?.children[0]) {
1067
- if (value?.children[0].type === "invalid_markdown") {
1068
- return value.children[0].value;
1069
- }
1070
- }
1071
- const res = toMarkdown2(rootElement(value, field, imageCallback), {
1072
- extensions: [mdxJsxToMarkdown2()],
1073
- listItemIndent: "one"
1074
- });
1075
- const templatesWithMatchers = field.templates?.filter((template) => template.match);
1076
- let preprocessedString = res;
1077
- templatesWithMatchers?.forEach((template) => {
2177
+ // src/parse/index.ts
2178
+ var markdownToAst = (value, field) => {
2179
+ const patterns = [];
2180
+ field.templates?.forEach((template) => {
1078
2181
  if (typeof template === "string") {
1079
- throw new Error("Global templates are not supported");
2182
+ return;
1080
2183
  }
1081
- if (template.match) {
1082
- preprocessedString = stringifyShortcode(preprocessedString, template);
2184
+ if (template && template.match) {
2185
+ patterns.push({
2186
+ ...template.match,
2187
+ name: template.match?.name || template.name,
2188
+ templateName: template.name,
2189
+ type: template.fields.find((f) => f.name === "children") ? "block" : "leaf"
2190
+ });
1083
2191
  }
1084
2192
  });
1085
- return preprocessedString;
1086
- };
1087
- var rootElement = (content, field, imageCallback) => {
1088
- const children = [];
1089
- content.children.forEach((child) => {
1090
- const value = blockElement(child, field, imageCallback);
1091
- if (value) {
1092
- children.push(value);
1093
- }
2193
+ return fromMarkdown(value, {
2194
+ extensions: [tinaDirective(patterns)],
2195
+ mdastExtensions: [directiveFromMarkdown]
1094
2196
  });
1095
- return {
1096
- type: "root",
1097
- children
1098
- };
1099
2197
  };
1100
- var blockElement = (content, field, imageCallback) => {
1101
- switch (content.type) {
1102
- case "h1":
1103
- case "h2":
1104
- case "h3":
1105
- case "h4":
1106
- case "h5":
1107
- case "h6":
1108
- return {
1109
- type: "heading",
1110
- depth: { h1: 1, h2: 2, h3: 3, h4: 4, h5: 5, h6: 6 }[content.type],
1111
- children: eat(content.children, field, imageCallback)
1112
- };
1113
- case "p":
1114
- if (content.children.length === 1) {
1115
- const onlyChild = content.children[0];
1116
- if (onlyChild && onlyChild.type === "text" && onlyChild.text === "") {
1117
- return null;
2198
+ var mdxToAst = (value) => {
2199
+ return remark().use(remarkMdx).parse(value);
2200
+ };
2201
+ var MDX_PARSE_ERROR_MSG = "TinaCMS supports a stricter version of markdown and a subset of MDX. https://tina.io/docs/editing/mdx/#differences-from-other-mdx-implementations";
2202
+ var parseMDX = (value, field, imageCallback) => {
2203
+ if (!value) {
2204
+ return { type: "root", children: [] };
2205
+ }
2206
+ let tree;
2207
+ try {
2208
+ if (field.parser?.type === "markdown") {
2209
+ tree = markdownToAst(value, field);
2210
+ } else {
2211
+ let preprocessedString = value;
2212
+ const templatesWithMatchers = field.templates?.filter((template) => template.match);
2213
+ templatesWithMatchers?.forEach((template) => {
2214
+ if (typeof template === "string") {
2215
+ throw new Error("Global templates are not supported");
1118
2216
  }
1119
- }
1120
- return {
1121
- type: "paragraph",
1122
- children: eat(content.children, field, imageCallback)
1123
- };
1124
- case "code_block":
1125
- return {
1126
- type: "code",
1127
- lang: content.lang,
1128
- value: content.value
1129
- };
1130
- case "mdxJsxFlowElement":
1131
- const { children, attributes } = stringifyProps(content, field, false, imageCallback);
1132
- return {
1133
- type: "mdxJsxFlowElement",
1134
- name: content.name,
1135
- attributes,
1136
- children
1137
- };
1138
- case "blockquote":
1139
- return {
1140
- type: "blockquote",
1141
- children: [
1142
- {
1143
- type: "paragraph",
1144
- children: eat(content.children, field, imageCallback)
2217
+ if (template.match) {
2218
+ if (preprocessedString) {
2219
+ preprocessedString = parseShortcode(preprocessedString, template);
1145
2220
  }
1146
- ]
1147
- };
1148
- case "hr":
1149
- return {
1150
- type: "thematicBreak"
1151
- };
1152
- case "ol":
1153
- case "ul":
1154
- return {
1155
- type: "list",
1156
- ordered: content.type === "ol",
1157
- spread: false,
1158
- children: content.children.map((child) => listItemElement(child, field, imageCallback))
1159
- };
1160
- case "html": {
1161
- return {
1162
- type: "html",
1163
- value: content.value
1164
- };
2221
+ }
2222
+ });
2223
+ tree = mdxToAst(preprocessedString);
1165
2224
  }
1166
- case "img":
1167
- return {
1168
- type: "image",
1169
- url: imageCallback(content.url),
1170
- alt: content.alt,
1171
- title: content.caption
1172
- };
1173
- default:
1174
- throw new Error(`BlockElement: ${content.type} is not yet supported`);
2225
+ if (tree) {
2226
+ return remarkToSlate(tree, field, imageCallback, value);
2227
+ } else {
2228
+ return { type: "root", children: [] };
2229
+ }
2230
+ } catch (e) {
2231
+ if (e instanceof RichTextParseError) {
2232
+ return invalidMarkdown(e, value);
2233
+ }
2234
+ return invalidMarkdown(new RichTextParseError(e.message), value);
1175
2235
  }
1176
2236
  };
1177
- var listItemElement = (content, field, imageCallback) => {
2237
+ var invalidMarkdown = (e, value) => {
2238
+ const extra = {};
2239
+ if (e.position && Object.keys(e.position).length) {
2240
+ extra["position"] = e.position;
2241
+ }
1178
2242
  return {
1179
- type: "listItem",
1180
- spread: false,
1181
- children: content.children.map((child) => {
1182
- if (child.type === "lic") {
1183
- return {
1184
- type: "paragraph",
1185
- children: eat(child.children, field, imageCallback)
1186
- };
2243
+ type: "root",
2244
+ children: [
2245
+ {
2246
+ type: "invalid_markdown",
2247
+ value,
2248
+ message: e.message || `Error parsing markdown ${MDX_PARSE_ERROR_MSG}`,
2249
+ children: [{ type: "text", text: "" }],
2250
+ ...extra
1187
2251
  }
1188
- return blockContentElement(child, field, imageCallback);
1189
- })
2252
+ ]
1190
2253
  };
1191
2254
  };
1192
- var blockContentElement = (content, field, imageCallback) => {
1193
- switch (content.type) {
1194
- case "blockquote":
1195
- return {
1196
- type: "blockquote",
1197
- children: content.children.map((child) => blockContentElement(child, field, imageCallback))
1198
- };
1199
- case "p":
1200
- return {
1201
- type: "paragraph",
1202
- children: eat(content.children, field, imageCallback)
1203
- };
1204
- case "ol":
1205
- case "ul":
1206
- return {
1207
- type: "list",
1208
- ordered: content.type === "ol",
1209
- spread: false,
1210
- children: content.children.map((child) => listItemElement(child, field, imageCallback))
1211
- };
1212
- default:
1213
- throw new Error(`BlockContentElement: ${content.type} is not yet supported`);
1214
- }
1215
- };
1216
- var getMarks = (content) => {
1217
- const marks = [];
1218
- if (content.type !== "text") {
1219
- return [];
1220
- }
1221
- if (content.bold) {
1222
- marks.push("strong");
1223
- }
1224
- if (content.italic) {
1225
- marks.push("emphasis");
1226
- }
1227
- if (content.code) {
1228
- marks.push("inlineCode");
1229
- }
1230
- return marks;
2255
+ var replaceAll = (string, target, value) => {
2256
+ const regex = new RegExp(target, "g");
2257
+ return string.valueOf().replace(regex, value);
1231
2258
  };
1232
2259
  export {
1233
2260
  parseMDX,