@tinacms/mdx 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/dist/index.d.ts +0 -12
- package/dist/index.es.js +1235 -0
- package/dist/parse/acorn.d.ts +0 -12
- package/dist/parse/index.d.ts +0 -12
- package/dist/parse/mdx.d.ts +0 -12
- package/dist/parse/parseShortcode.d.ts +0 -12
- package/dist/parse/plate.d.ts +0 -12
- package/dist/parse/remarkToPlate.d.ts +0 -12
- package/dist/stringify/index.d.ts +0 -12
- package/dist/stringify/marks.d.ts +0 -12
- package/dist/stringify/stringifyShortcode.d.ts +0 -12
- package/dist/tests/autotest/_config.d.ts +0 -12
- package/dist/tests/setup.d.ts +0 -12
- package/package.json +7 -3
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,1235 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/parse/index.ts
|
|
9
|
+
import { remark } from "remark";
|
|
10
|
+
import remarkMdx from "remark-mdx";
|
|
11
|
+
|
|
12
|
+
// src/parse/remarkToPlate.ts
|
|
13
|
+
import { flatten } from "lodash-es";
|
|
14
|
+
|
|
15
|
+
// src/parse/acorn.ts
|
|
16
|
+
var extractAttributes = (attributes, fields, imageCallback) => {
|
|
17
|
+
const properties = {};
|
|
18
|
+
attributes.forEach((attribute) => {
|
|
19
|
+
assertType(attribute, "mdxJsxAttribute");
|
|
20
|
+
const field = fields.find((field2) => field2.name === attribute.name);
|
|
21
|
+
if (!field) {
|
|
22
|
+
throw new Error(`Unable to find field definition for property "${attribute.name}"`);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
properties[attribute.name] = extractAttribute(attribute, field, imageCallback);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
if (e instanceof Error) {
|
|
28
|
+
throw new Error(`Unable to parse field value for field "${field.name}" (type: ${field.type}). ${e.message}`);
|
|
29
|
+
}
|
|
30
|
+
throw e;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return properties;
|
|
34
|
+
};
|
|
35
|
+
var extractAttribute = (attribute, field, imageCallback) => {
|
|
36
|
+
switch (field.type) {
|
|
37
|
+
case "boolean":
|
|
38
|
+
case "number":
|
|
39
|
+
return extractScalar(extractExpression(attribute), field);
|
|
40
|
+
case "datetime":
|
|
41
|
+
case "string":
|
|
42
|
+
if (field.list) {
|
|
43
|
+
return extractScalar(extractExpression(attribute), field);
|
|
44
|
+
} else {
|
|
45
|
+
return extractString(attribute, field);
|
|
46
|
+
}
|
|
47
|
+
case "image":
|
|
48
|
+
if (field.list) {
|
|
49
|
+
const values = extractScalar(extractExpression(attribute), field);
|
|
50
|
+
return values.split(",").map((value) => imageCallback(value));
|
|
51
|
+
} else {
|
|
52
|
+
const value = extractString(attribute, field);
|
|
53
|
+
return imageCallback(value);
|
|
54
|
+
}
|
|
55
|
+
case "reference":
|
|
56
|
+
if (field.list) {
|
|
57
|
+
return extractScalar(extractExpression(attribute), field);
|
|
58
|
+
} else {
|
|
59
|
+
return extractString(attribute, field);
|
|
60
|
+
}
|
|
61
|
+
case "object":
|
|
62
|
+
return extractObject(extractExpression(attribute), field);
|
|
63
|
+
case "rich-text":
|
|
64
|
+
const JSXString = extractRaw(attribute);
|
|
65
|
+
if (JSXString) {
|
|
66
|
+
return parseMDX(JSXString, field, imageCallback);
|
|
67
|
+
} else {
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Extract attribute: Unhandled field type ${field.type}`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var extractScalar = (attribute, field) => {
|
|
75
|
+
if (field.list) {
|
|
76
|
+
assertType(attribute.expression, "ArrayExpression");
|
|
77
|
+
return attribute.expression.elements.map((element) => {
|
|
78
|
+
assertHasType(element);
|
|
79
|
+
assertType(element, "Literal");
|
|
80
|
+
return element.value;
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
assertType(attribute.expression, "Literal");
|
|
84
|
+
return attribute.expression.value;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var extractObject = (attribute, field) => {
|
|
88
|
+
if (field.list) {
|
|
89
|
+
assertType(attribute.expression, "ArrayExpression");
|
|
90
|
+
return attribute.expression.elements.map((element) => {
|
|
91
|
+
assertHasType(element);
|
|
92
|
+
assertType(element, "ObjectExpression");
|
|
93
|
+
return extractObjectExpression(element, field);
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
assertType(attribute.expression, "ObjectExpression");
|
|
97
|
+
return extractObjectExpression(attribute.expression, field);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var extractObjectExpression = (expression, field) => {
|
|
101
|
+
const properties = {};
|
|
102
|
+
expression.properties.forEach((property) => {
|
|
103
|
+
assertType(property, "Property");
|
|
104
|
+
const { key, value } = extractKeyValue(property, field);
|
|
105
|
+
properties[key] = value;
|
|
106
|
+
});
|
|
107
|
+
return properties;
|
|
108
|
+
};
|
|
109
|
+
var getField = (objectField, name) => {
|
|
110
|
+
if (objectField.fields) {
|
|
111
|
+
if (typeof objectField.fields === "string") {
|
|
112
|
+
throw new Error("Global templates not supported");
|
|
113
|
+
}
|
|
114
|
+
return objectField.fields.find((f) => f.name === name);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var extractKeyValue = (property, parentField) => {
|
|
118
|
+
assertType(property.key, "Identifier");
|
|
119
|
+
const key = property.key.name;
|
|
120
|
+
const field = getField(parentField, key);
|
|
121
|
+
if (field?.type === "object") {
|
|
122
|
+
if (field.list) {
|
|
123
|
+
assertType(property.value, "ArrayExpression");
|
|
124
|
+
const value = property.value.elements.map((element) => {
|
|
125
|
+
assertHasType(element);
|
|
126
|
+
assertType(element, "ObjectExpression");
|
|
127
|
+
return extractObjectExpression(element, field);
|
|
128
|
+
});
|
|
129
|
+
return { key, value };
|
|
130
|
+
} else {
|
|
131
|
+
assertType(property.value, "ObjectExpression");
|
|
132
|
+
const value = extractObjectExpression(property.value, field);
|
|
133
|
+
return { key, value };
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
assertType(property.value, "Literal");
|
|
137
|
+
return { key, value: property.value.value };
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var extractStatement = (attribute) => {
|
|
141
|
+
const body = attribute.data?.estree?.body;
|
|
142
|
+
if (body) {
|
|
143
|
+
if (body[0]) {
|
|
144
|
+
assertType(body[0], "ExpressionStatement");
|
|
145
|
+
return body[0];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
throw new Error(`Unable to extract body from expression`);
|
|
149
|
+
};
|
|
150
|
+
var extractString = (attribute, field) => {
|
|
151
|
+
if (attribute.type === "mdxJsxAttribute") {
|
|
152
|
+
if (typeof attribute.value === "string") {
|
|
153
|
+
return attribute.value;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return extractScalar(extractExpression(attribute), field);
|
|
157
|
+
};
|
|
158
|
+
var extractExpression = (attribute) => {
|
|
159
|
+
assertType(attribute, "mdxJsxAttribute");
|
|
160
|
+
assertHasType(attribute.value);
|
|
161
|
+
assertType(attribute.value, "mdxJsxAttributeValueExpression");
|
|
162
|
+
return extractStatement(attribute.value);
|
|
163
|
+
};
|
|
164
|
+
var extractRaw = (attribute) => {
|
|
165
|
+
assertType(attribute, "mdxJsxAttribute");
|
|
166
|
+
assertHasType(attribute.value);
|
|
167
|
+
assertType(attribute.value, "mdxJsxAttributeValueExpression");
|
|
168
|
+
const rawValue = attribute.value.value;
|
|
169
|
+
return trimFragments(rawValue);
|
|
170
|
+
};
|
|
171
|
+
function assertType(val, type) {
|
|
172
|
+
if (val.type !== type) {
|
|
173
|
+
throw new Error(`Expected type to be ${type} but received ${val.type}. ${MDX_PARSE_ERROR_MSG}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function assertHasType(val) {
|
|
177
|
+
if (val) {
|
|
178
|
+
if (typeof val !== "string") {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
throw new Error(`Expect value to be an object with property "type"`);
|
|
183
|
+
}
|
|
184
|
+
var trimFragments = (string) => {
|
|
185
|
+
const rawArr = string.split("\n");
|
|
186
|
+
let openingFragmentIndex = null;
|
|
187
|
+
let closingFragmentIndex = null;
|
|
188
|
+
rawArr.forEach((item, index) => {
|
|
189
|
+
if (item.trim() === "<>") {
|
|
190
|
+
if (!openingFragmentIndex) {
|
|
191
|
+
openingFragmentIndex = index + 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
rawArr.reverse().forEach((item, index) => {
|
|
196
|
+
if (item.trim() === "</>") {
|
|
197
|
+
const length = rawArr.length - 1;
|
|
198
|
+
if (!closingFragmentIndex) {
|
|
199
|
+
closingFragmentIndex = length - index;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
const value = rawArr.reverse().slice(openingFragmentIndex || 0, closingFragmentIndex || rawArr.length - 1).join("\n");
|
|
204
|
+
return value;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// src/parse/mdx.ts
|
|
208
|
+
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;
|
|
215
|
+
});
|
|
216
|
+
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
|
+
};
|
|
229
|
+
}
|
|
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);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
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);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
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)))
|
|
287
|
+
}
|
|
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);
|
|
297
|
+
default:
|
|
298
|
+
throw new RichTextParseError(`Content: ${content2.type} is not yet supported`, content2.position);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
const html = (content2) => {
|
|
302
|
+
return {
|
|
303
|
+
type: "html",
|
|
304
|
+
value: content2.value,
|
|
305
|
+
children: [{ type: "text", text: "" }]
|
|
306
|
+
};
|
|
307
|
+
};
|
|
308
|
+
const html_inline = (content2) => {
|
|
309
|
+
return {
|
|
310
|
+
type: "html_inline",
|
|
311
|
+
value: content2.value,
|
|
312
|
+
children: [{ type: "text", text: "" }]
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
const list = (content2) => {
|
|
316
|
+
return {
|
|
317
|
+
type: content2.ordered ? "ol" : "ul",
|
|
318
|
+
children: content2.children.map((child) => listItem(child))
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
const listItem = (content2) => {
|
|
322
|
+
return {
|
|
323
|
+
type: "li",
|
|
324
|
+
children: content2.children.map((child) => {
|
|
325
|
+
switch (child.type) {
|
|
326
|
+
case "list":
|
|
327
|
+
return list(child);
|
|
328
|
+
case "heading":
|
|
329
|
+
case "paragraph":
|
|
330
|
+
return {
|
|
331
|
+
type: "lic",
|
|
332
|
+
children: flatten(child.children.map((child2) => phrasingContent(child2)))
|
|
333
|
+
};
|
|
334
|
+
case "blockquote": {
|
|
335
|
+
return {
|
|
336
|
+
...blockquote(child),
|
|
337
|
+
type: "lic"
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
case "mdxJsxFlowElement":
|
|
341
|
+
return {
|
|
342
|
+
type: "lic",
|
|
343
|
+
children: [
|
|
344
|
+
mdxJsxElement({ ...child, type: "mdxJsxTextElement" }, field, imageCallback)
|
|
345
|
+
]
|
|
346
|
+
};
|
|
347
|
+
case "code":
|
|
348
|
+
case "thematicBreak":
|
|
349
|
+
case "table":
|
|
350
|
+
case "html":
|
|
351
|
+
throw new RichTextParseError(`${child.type} inside list item is not supported`, child.position);
|
|
352
|
+
default:
|
|
353
|
+
throw new RichTextParseError(`Unknown list item of type ${child.type}`, child.position);
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
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;
|
|
490
|
+
default:
|
|
491
|
+
throw new Error(`Unexpected inline element of type ${node.type}`);
|
|
492
|
+
}
|
|
493
|
+
return accum;
|
|
494
|
+
};
|
|
495
|
+
const image = (content2) => {
|
|
496
|
+
return {
|
|
497
|
+
type: "img",
|
|
498
|
+
url: imageCallback(content2.url),
|
|
499
|
+
alt: content2.alt,
|
|
500
|
+
caption: content2.title,
|
|
501
|
+
children: [{ type: "text", text: "" }]
|
|
502
|
+
};
|
|
503
|
+
};
|
|
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
|
+
});
|
|
518
|
+
return {
|
|
519
|
+
type: "blockquote",
|
|
520
|
+
children
|
|
521
|
+
};
|
|
522
|
+
};
|
|
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
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
type: "p",
|
|
537
|
+
children
|
|
538
|
+
};
|
|
539
|
+
};
|
|
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);
|
|
608
|
+
}
|
|
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
|
+
};
|
|
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;
|
|
714
|
+
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
|
+
});
|
|
732
|
+
}
|
|
733
|
+
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
|
+
}
|
|
757
|
+
break;
|
|
758
|
+
case "object":
|
|
759
|
+
attributes.push({
|
|
760
|
+
type: "mdxJsxAttribute",
|
|
761
|
+
name,
|
|
762
|
+
value: {
|
|
763
|
+
type: "mdxJsxAttributeValueExpression",
|
|
764
|
+
value: stringifyObj(value, flatten2)
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
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
|
+
}
|
|
812
|
+
break;
|
|
813
|
+
default:
|
|
814
|
+
throw new Error(`Stringify props: ${field.type} not yet supported`);
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
if (template.match) {
|
|
818
|
+
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
|
+
]
|
|
831
|
+
};
|
|
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);
|
|
922
|
+
}
|
|
923
|
+
throw new Error(`InlineElement: ${content.type} is not supported`);
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
var text = (content) => {
|
|
927
|
+
return {
|
|
928
|
+
type: "text",
|
|
929
|
+
value: content.text
|
|
930
|
+
};
|
|
931
|
+
};
|
|
932
|
+
var eat = (c, field, imageCallback) => {
|
|
933
|
+
const content = replaceLinksWithTextNodes(c);
|
|
934
|
+
const first = content[0];
|
|
935
|
+
if (!first) {
|
|
936
|
+
return [];
|
|
937
|
+
}
|
|
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
|
+
];
|
|
949
|
+
}
|
|
950
|
+
return [
|
|
951
|
+
inlineElementExceptLink(first, field, imageCallback),
|
|
952
|
+
...eat(content.slice(1), field, imageCallback)
|
|
953
|
+
];
|
|
954
|
+
}
|
|
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
|
+
];
|
|
962
|
+
} else {
|
|
963
|
+
return [text(first), ...eat(content.slice(1), field, imageCallback)];
|
|
964
|
+
}
|
|
965
|
+
}
|
|
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;
|
|
973
|
+
}
|
|
974
|
+
})) {
|
|
975
|
+
nonMatchingSiblingIndex = content.length - 1;
|
|
976
|
+
}
|
|
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;
|
|
985
|
+
}
|
|
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;
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
if (!markToProcess) {
|
|
999
|
+
return [text(first), ...eat(content.slice(1), field, imageCallback)];
|
|
1000
|
+
}
|
|
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
|
|
1008
|
+
};
|
|
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
|
+
];
|
|
1023
|
+
};
|
|
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;
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
if (node.linkifyTextNode) {
|
|
1040
|
+
cleanedNode.callback = node.linkifyTextNode;
|
|
1041
|
+
}
|
|
1042
|
+
return cleanedNode;
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
// src/stringify/stringifyShortcode.ts
|
|
1046
|
+
function stringifyShortcode(preprocessedString, template) {
|
|
1047
|
+
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);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
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) => {
|
|
1078
|
+
if (typeof template === "string") {
|
|
1079
|
+
throw new Error("Global templates are not supported");
|
|
1080
|
+
}
|
|
1081
|
+
if (template.match) {
|
|
1082
|
+
preprocessedString = stringifyShortcode(preprocessedString, template);
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
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
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
return {
|
|
1096
|
+
type: "root",
|
|
1097
|
+
children
|
|
1098
|
+
};
|
|
1099
|
+
};
|
|
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;
|
|
1118
|
+
}
|
|
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)
|
|
1145
|
+
}
|
|
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
|
+
};
|
|
1165
|
+
}
|
|
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`);
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
var listItemElement = (content, field, imageCallback) => {
|
|
1178
|
+
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
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
return blockContentElement(child, field, imageCallback);
|
|
1189
|
+
})
|
|
1190
|
+
};
|
|
1191
|
+
};
|
|
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;
|
|
1231
|
+
};
|
|
1232
|
+
export {
|
|
1233
|
+
parseMDX,
|
|
1234
|
+
stringifyMDX
|
|
1235
|
+
};
|