@portabletext/block-tools 5.0.4 → 5.1.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/README.md +29 -140
- package/lib/index.d.ts +85 -6
- package/lib/index.js +32 -1212
- package/lib/index.js.map +1 -1
- package/lib/rules/index.d.ts +22 -1
- package/lib/rules/index.js +1 -66
- package/lib/rules/index.js.map +1 -1
- package/package.json +3 -2
- package/lib/_chunks-dts/types.d.ts +0 -85
- package/lib/_chunks-es/helpers.js +0 -297
- package/lib/_chunks-es/helpers.js.map +0 -1
package/lib/index.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
+
import { htmlToPortableText } from "@portabletext/html";
|
|
1
2
|
import { sanitySchemaToPortableTextSchema } from "@portabletext/sanity-bridge";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
function M(t) {
|
|
14
|
-
return t && JSON.parse(D(JSON.stringify(t)).cleaned);
|
|
3
|
+
import { isSpan } from "@portabletext/schema";
|
|
4
|
+
function isEqualMarks(a, b) {
|
|
5
|
+
if (!a || !b)
|
|
6
|
+
return a === b;
|
|
7
|
+
if (a.length !== b.length)
|
|
8
|
+
return !1;
|
|
9
|
+
for (let index = 0; index < a.length; index++)
|
|
10
|
+
if (a[index] !== b[index])
|
|
11
|
+
return !1;
|
|
12
|
+
return !0;
|
|
15
13
|
}
|
|
16
14
|
function keyGenerator() {
|
|
17
15
|
return randomKey(12);
|
|
@@ -26,1204 +24,6 @@ for (let i = 0; i < 256; ++i)
|
|
|
26
24
|
function randomKey(length) {
|
|
27
25
|
return whatwgRNG(length).reduce((str, n) => str + byteToHex[n], "").slice(0, length);
|
|
28
26
|
}
|
|
29
|
-
function isWordOnlineHtml(html) {
|
|
30
|
-
return /class="(?:TextRun|NormalTextRun)[^"]*SCXW\d+[^"]*BCX\d+/.test(html) || /class="EOP[^"]*SCXW\d+/.test(html);
|
|
31
|
-
}
|
|
32
|
-
function isWordOnlineTextRun(el) {
|
|
33
|
-
return !isElement(el) || tagName(el) !== "span" ? !1 : el.classList.contains("TextRun") && !el.classList.contains("EOP");
|
|
34
|
-
}
|
|
35
|
-
function isNormalTextRun(el) {
|
|
36
|
-
return !isElement(el) || tagName(el) !== "span" ? !1 : el.classList.contains("NormalTextRun");
|
|
37
|
-
}
|
|
38
|
-
function isTextRunSpan(el) {
|
|
39
|
-
return !isElement(el) || tagName(el) !== "span" ? !1 : el.classList.contains("TextRun") && !el.classList.contains("NormalTextRun") && !el.classList.contains("EOP");
|
|
40
|
-
}
|
|
41
|
-
function isFindHit(el) {
|
|
42
|
-
return !isElement(el) || tagName(el) !== "span" ? !1 : el.classList.contains("FindHit");
|
|
43
|
-
}
|
|
44
|
-
function isInHeading(el) {
|
|
45
|
-
let current = el;
|
|
46
|
-
for (; current; ) {
|
|
47
|
-
if (isElement(current) && tagName(current) === "word-online-block" && /^heading \d$/.test(current.getAttribute("data-parastyle") ?? ""))
|
|
48
|
-
return !0;
|
|
49
|
-
current = current.parentNode;
|
|
50
|
-
}
|
|
51
|
-
return !1;
|
|
52
|
-
}
|
|
53
|
-
function isInBlockquote(el) {
|
|
54
|
-
let current = el;
|
|
55
|
-
for (; current; ) {
|
|
56
|
-
if (isElement(current) && tagName(current) === "word-online-block" && current.getAttribute("data-parastyle") === "Quote")
|
|
57
|
-
return !0;
|
|
58
|
-
current = current.parentNode;
|
|
59
|
-
}
|
|
60
|
-
return !1;
|
|
61
|
-
}
|
|
62
|
-
function hasStrongFormatting(el) {
|
|
63
|
-
const style = el.getAttribute("style") ?? "";
|
|
64
|
-
return el.classList.contains("MacChromeBold") || /font-weight\s*:\s*bold/.test(style);
|
|
65
|
-
}
|
|
66
|
-
function hasEmphasisFormatting(el) {
|
|
67
|
-
const style = el.getAttribute("style") ?? "";
|
|
68
|
-
return /font-style\s*:\s*italic/.test(style);
|
|
69
|
-
}
|
|
70
|
-
function hasUnderlineFormatting(el) {
|
|
71
|
-
const style = el.getAttribute("style") ?? "";
|
|
72
|
-
return el.classList.contains("Underlined") || /text-decoration\s*:\s*underline/.test(style);
|
|
73
|
-
}
|
|
74
|
-
function hasStrikethroughFormatting(el) {
|
|
75
|
-
const style = el.getAttribute("style") ?? "";
|
|
76
|
-
return el.classList.contains("Strikethrough") || /text-decoration\s*:\s*line-through/.test(style);
|
|
77
|
-
}
|
|
78
|
-
function hasFormatting(el) {
|
|
79
|
-
return hasStrongFormatting(el) || hasEmphasisFormatting(el) || hasUnderlineFormatting(el) || hasStrikethroughFormatting(el);
|
|
80
|
-
}
|
|
81
|
-
function preprocessWordOnline(html, doc) {
|
|
82
|
-
if (!isWordOnlineHtml(html))
|
|
83
|
-
return doc;
|
|
84
|
-
const paragraphs = Array.from(
|
|
85
|
-
doc.querySelectorAll('p.Paragraph[role="heading"]')
|
|
86
|
-
);
|
|
87
|
-
for (const paragraph of paragraphs) {
|
|
88
|
-
const ariaLevel = paragraph.getAttribute("aria-level");
|
|
89
|
-
if (ariaLevel) {
|
|
90
|
-
const wrapper = doc.createElement("word-online-block");
|
|
91
|
-
wrapper.setAttribute("data-parastyle", `heading ${ariaLevel}`);
|
|
92
|
-
const parent = paragraph.parentNode;
|
|
93
|
-
if (parent) {
|
|
94
|
-
for (parent.insertBefore(wrapper, paragraph); paragraph.firstChild; )
|
|
95
|
-
wrapper.appendChild(paragraph.firstChild);
|
|
96
|
-
parent.removeChild(paragraph);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
let child = doc.body.firstChild;
|
|
101
|
-
for (; child; ) {
|
|
102
|
-
const next = child.nextSibling;
|
|
103
|
-
if (!isElement(child) || !tagName(child)?.includes("span")) {
|
|
104
|
-
child = next;
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
const paraStyle = getParaStyle(child);
|
|
108
|
-
if (!paraStyle) {
|
|
109
|
-
child = next;
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
const group = [child];
|
|
113
|
-
let sibling = next;
|
|
114
|
-
for (; sibling && !(!isElement(sibling) || getParaStyle(sibling) !== paraStyle); )
|
|
115
|
-
group.push(sibling), sibling = sibling.nextSibling;
|
|
116
|
-
const wrapper = doc.createElement("word-online-block");
|
|
117
|
-
wrapper.setAttribute("data-parastyle", paraStyle), doc.body.insertBefore(wrapper, child);
|
|
118
|
-
for (const span of group)
|
|
119
|
-
wrapper.appendChild(span);
|
|
120
|
-
child = sibling;
|
|
121
|
-
}
|
|
122
|
-
const textRunSpans = Array.from(doc.body.querySelectorAll("span")).filter(
|
|
123
|
-
isTextRunSpan
|
|
124
|
-
);
|
|
125
|
-
for (const textRunSpan of textRunSpans) {
|
|
126
|
-
const normalTextRuns = Array.from(textRunSpan.childNodes).filter(
|
|
127
|
-
isNormalTextRun
|
|
128
|
-
);
|
|
129
|
-
for (const normalTextRun of normalTextRuns) {
|
|
130
|
-
let foundNestedSpan = !0;
|
|
131
|
-
for (; foundNestedSpan; ) {
|
|
132
|
-
const children = Array.from(normalTextRun.childNodes), nestedSpanIndex = children.findIndex(
|
|
133
|
-
(node) => isElement(node) && tagName(node) === "span" && node.textContent.trim() === ""
|
|
134
|
-
);
|
|
135
|
-
if (nestedSpanIndex === -1) {
|
|
136
|
-
foundNestedSpan = !1;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
const nestedSpan = children.at(nestedSpanIndex);
|
|
140
|
-
if (!nestedSpan) {
|
|
141
|
-
foundNestedSpan = !1;
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
const spaceText = nestedSpan.textContent?.replace(/\u00a0/g, " ") ?? "", isSpaceAtBeginning = !children.slice(0, nestedSpanIndex).some((n) => n.nodeType === 3);
|
|
145
|
-
if (normalTextRun.removeChild(nestedSpan), isSpaceAtBeginning) {
|
|
146
|
-
const firstTextNode = Array.from(normalTextRun.childNodes).find(
|
|
147
|
-
(n) => n.nodeType === 3
|
|
148
|
-
);
|
|
149
|
-
if (firstTextNode)
|
|
150
|
-
firstTextNode.textContent = spaceText + (firstTextNode.textContent || "");
|
|
151
|
-
else {
|
|
152
|
-
const spaceNode = doc.createTextNode(spaceText);
|
|
153
|
-
normalTextRun.insertBefore(spaceNode, normalTextRun.firstChild);
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
const nextSibling = textRunSpan.nextSibling, currentHasFormatting = hasFormatting(textRunSpan);
|
|
157
|
-
if (nextSibling && isElement(nextSibling) && isTextRunSpan(nextSibling)) {
|
|
158
|
-
const nextHasFormatting = hasFormatting(nextSibling);
|
|
159
|
-
if (currentHasFormatting && !nextHasFormatting) {
|
|
160
|
-
const nextNormalTextRun = Array.from(nextSibling.childNodes).find(
|
|
161
|
-
isNormalTextRun
|
|
162
|
-
);
|
|
163
|
-
if (nextNormalTextRun && isElement(nextNormalTextRun)) {
|
|
164
|
-
const firstChild = nextNormalTextRun.firstChild;
|
|
165
|
-
if (firstChild && firstChild.nodeType === 3)
|
|
166
|
-
firstChild.textContent = spaceText + (firstChild.textContent ?? "");
|
|
167
|
-
else {
|
|
168
|
-
const spaceNode = doc.createTextNode(spaceText);
|
|
169
|
-
nextNormalTextRun.insertBefore(
|
|
170
|
-
spaceNode,
|
|
171
|
-
nextNormalTextRun.firstChild
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
const lastTextNode = Array.from(normalTextRun.childNodes).find(
|
|
177
|
-
(n) => n.nodeType === 3
|
|
178
|
-
);
|
|
179
|
-
if (lastTextNode)
|
|
180
|
-
lastTextNode.textContent = (lastTextNode.textContent ?? "") + spaceText;
|
|
181
|
-
else {
|
|
182
|
-
const spaceNode = doc.createTextNode(spaceText);
|
|
183
|
-
normalTextRun.appendChild(spaceNode);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} else {
|
|
187
|
-
const lastTextNode = Array.from(normalTextRun.childNodes).find(
|
|
188
|
-
(n) => n.nodeType === 3
|
|
189
|
-
);
|
|
190
|
-
if (lastTextNode)
|
|
191
|
-
lastTextNode.textContent = (lastTextNode.textContent ?? "") + spaceText;
|
|
192
|
-
else {
|
|
193
|
-
const spaceNode = doc.createTextNode(spaceText);
|
|
194
|
-
normalTextRun.appendChild(spaceNode);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return doc;
|
|
202
|
-
}
|
|
203
|
-
function getParaStyle(element) {
|
|
204
|
-
const directStyle = element.getAttribute("data-ccp-parastyle");
|
|
205
|
-
if (directStyle)
|
|
206
|
-
return directStyle;
|
|
207
|
-
if (tagName(element) === "span" && element.classList.contains("TextRun")) {
|
|
208
|
-
const normalTextRuns = Array.from(
|
|
209
|
-
element.querySelectorAll(".NormalTextRun")
|
|
210
|
-
);
|
|
211
|
-
if (normalTextRuns.length > 0) {
|
|
212
|
-
const firstStyle = normalTextRuns[0].getAttribute("data-ccp-parastyle");
|
|
213
|
-
if (firstStyle && normalTextRuns.every(
|
|
214
|
-
(normalTextRun) => normalTextRun.getAttribute("data-ccp-parastyle") === firstStyle
|
|
215
|
-
))
|
|
216
|
-
return firstStyle;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const _XPathResult = {
|
|
221
|
-
BOOLEAN_TYPE: 3,
|
|
222
|
-
ORDERED_NODE_ITERATOR_TYPE: 5,
|
|
223
|
-
UNORDERED_NODE_SNAPSHOT_TYPE: 6
|
|
224
|
-
};
|
|
225
|
-
function preprocessGDocs(_html, doc) {
|
|
226
|
-
let gDocsRootOrSiblingNode = doc.evaluate(
|
|
227
|
-
'//*[@id and contains(@id, "docs-internal-guid")]',
|
|
228
|
-
doc,
|
|
229
|
-
null,
|
|
230
|
-
_XPathResult.ORDERED_NODE_ITERATOR_TYPE,
|
|
231
|
-
null
|
|
232
|
-
).iterateNext();
|
|
233
|
-
if (gDocsRootOrSiblingNode) {
|
|
234
|
-
const isWrappedRootTag = tagName(gDocsRootOrSiblingNode) === "b";
|
|
235
|
-
isWrappedRootTag || (gDocsRootOrSiblingNode = doc.body);
|
|
236
|
-
const childNodes = doc.evaluate(
|
|
237
|
-
"//*",
|
|
238
|
-
doc,
|
|
239
|
-
null,
|
|
240
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
241
|
-
null
|
|
242
|
-
);
|
|
243
|
-
for (let i = childNodes.snapshotLength - 1; i >= 0; i--) {
|
|
244
|
-
const elm = childNodes.snapshotItem(i);
|
|
245
|
-
elm?.setAttribute("data-is-google-docs", "true"), (elm?.parentElement === gDocsRootOrSiblingNode || !isWrappedRootTag && elm.parentElement === doc.body) && (elm?.setAttribute("data-is-root-node", "true"), tagName(elm)), tagName(elm) === "li" && elm.firstChild && tagName(elm?.firstChild) === "img" && elm.removeChild(elm.firstChild);
|
|
246
|
-
}
|
|
247
|
-
return isWrappedRootTag && doc.body.firstElementChild?.replaceWith(
|
|
248
|
-
...Array.from(gDocsRootOrSiblingNode.childNodes)
|
|
249
|
-
), doc;
|
|
250
|
-
}
|
|
251
|
-
return doc;
|
|
252
|
-
}
|
|
253
|
-
const unwantedWordDocumentPaths = [
|
|
254
|
-
"/html/text()",
|
|
255
|
-
"/html/head/text()",
|
|
256
|
-
"/html/body/text()",
|
|
257
|
-
"/html/body/ul/text()",
|
|
258
|
-
"/html/body/ol/text()",
|
|
259
|
-
"//comment()",
|
|
260
|
-
"//style",
|
|
261
|
-
"//xml",
|
|
262
|
-
"//script",
|
|
263
|
-
"//meta",
|
|
264
|
-
"//link"
|
|
265
|
-
];
|
|
266
|
-
function preprocessHTML(_html, doc) {
|
|
267
|
-
const bodyTextNodes = doc.evaluate(
|
|
268
|
-
"/html/body/text()",
|
|
269
|
-
doc,
|
|
270
|
-
null,
|
|
271
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
272
|
-
null
|
|
273
|
-
);
|
|
274
|
-
for (let i = bodyTextNodes.snapshotLength - 1; i >= 0; i--) {
|
|
275
|
-
const node = bodyTextNodes.snapshotItem(i), text = node.textContent || "";
|
|
276
|
-
if (text.replace(/[^\S\n]+$/g, "")) {
|
|
277
|
-
const newNode = doc.createElement("span");
|
|
278
|
-
newNode.appendChild(doc.createTextNode(text)), node.parentNode?.replaceChild(newNode, node);
|
|
279
|
-
} else
|
|
280
|
-
node.parentNode?.removeChild(node);
|
|
281
|
-
}
|
|
282
|
-
const unwantedNodes = doc.evaluate(
|
|
283
|
-
unwantedWordDocumentPaths.join("|"),
|
|
284
|
-
doc,
|
|
285
|
-
null,
|
|
286
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
287
|
-
null
|
|
288
|
-
);
|
|
289
|
-
for (let i = unwantedNodes.snapshotLength - 1; i >= 0; i--) {
|
|
290
|
-
const unwanted = unwantedNodes.snapshotItem(i);
|
|
291
|
-
unwanted && unwanted.parentNode?.removeChild(unwanted);
|
|
292
|
-
}
|
|
293
|
-
return doc;
|
|
294
|
-
}
|
|
295
|
-
function preprocessNotion(html, doc) {
|
|
296
|
-
const NOTION_REGEX = /<!-- notionvc:.*?-->/g;
|
|
297
|
-
if (html.match(NOTION_REGEX)) {
|
|
298
|
-
const childNodes = doc.evaluate(
|
|
299
|
-
"//*",
|
|
300
|
-
doc,
|
|
301
|
-
null,
|
|
302
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
303
|
-
null
|
|
304
|
-
);
|
|
305
|
-
for (let i = childNodes.snapshotLength - 1; i >= 0; i--)
|
|
306
|
-
childNodes.snapshotItem(i)?.setAttribute("data-is-notion", "true");
|
|
307
|
-
return doc;
|
|
308
|
-
}
|
|
309
|
-
return doc;
|
|
310
|
-
}
|
|
311
|
-
const BLOCK_CONTAINER_ELEMENTS = [
|
|
312
|
-
"body",
|
|
313
|
-
"table",
|
|
314
|
-
"tbody",
|
|
315
|
-
"thead",
|
|
316
|
-
"tfoot",
|
|
317
|
-
"tr",
|
|
318
|
-
"ul",
|
|
319
|
-
"ol"
|
|
320
|
-
];
|
|
321
|
-
function preprocessWhitespace(_2, doc) {
|
|
322
|
-
function processNode(node) {
|
|
323
|
-
if (node.nodeType === _XPathResult.BOOLEAN_TYPE && !PRESERVE_WHITESPACE_TAGS.includes(
|
|
324
|
-
node.parentElement?.tagName.toLowerCase() || ""
|
|
325
|
-
)) {
|
|
326
|
-
const normalized = node.textContent?.replace(/\s\s+/g, " ").replace(/[\r\n]+/g, " ") || "", parentTag = node.parentElement?.tagName.toLowerCase();
|
|
327
|
-
parentTag && BLOCK_CONTAINER_ELEMENTS.includes(parentTag) && normalized.trim() === "" ? node.parentNode?.removeChild(node) : node.textContent = normalized;
|
|
328
|
-
} else
|
|
329
|
-
for (let i = node.childNodes.length - 1; i >= 0; i--)
|
|
330
|
-
processNode(node.childNodes[i]);
|
|
331
|
-
}
|
|
332
|
-
return processNode(doc.body), doc;
|
|
333
|
-
}
|
|
334
|
-
const WORD_HTML_REGEX = /(class="?Mso|style=(?:"|')[^"]*?\bmso-|w:WordDocument|<o:\w+>|<\/font>)/, unwantedPaths = [
|
|
335
|
-
"//o:p",
|
|
336
|
-
"//span[@style='mso-list:Ignore']",
|
|
337
|
-
"//span[@style='mso-list: Ignore']"
|
|
338
|
-
], mappedPaths = [
|
|
339
|
-
"//p[@class='MsoTocHeading']",
|
|
340
|
-
"//p[@class='MsoTitle']",
|
|
341
|
-
"//p[@class='MsoToaHeading']",
|
|
342
|
-
"//p[@class='MsoSubtitle']",
|
|
343
|
-
"//span[@class='MsoSubtleEmphasis']",
|
|
344
|
-
"//span[@class='MsoIntenseEmphasis']"
|
|
345
|
-
], elementMap = {
|
|
346
|
-
MsoTocHeading: ["h3"],
|
|
347
|
-
MsoTitle: ["h1"],
|
|
348
|
-
MsoToaHeading: ["h2"],
|
|
349
|
-
MsoSubtitle: ["h5"],
|
|
350
|
-
MsoSubtleEmphasis: ["span", "em"],
|
|
351
|
-
MsoIntenseEmphasis: ["span", "em", "strong"]
|
|
352
|
-
// Remove cruft
|
|
353
|
-
};
|
|
354
|
-
function isWordHtml(html) {
|
|
355
|
-
return WORD_HTML_REGEX.test(html);
|
|
356
|
-
}
|
|
357
|
-
function preprocessWord(html, doc) {
|
|
358
|
-
if (!isWordHtml(html))
|
|
359
|
-
return doc;
|
|
360
|
-
const unwantedNodes = doc.evaluate(
|
|
361
|
-
unwantedPaths.join("|"),
|
|
362
|
-
doc,
|
|
363
|
-
(prefix) => prefix === "o" ? "urn:schemas-microsoft-com:office:office" : null,
|
|
364
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
365
|
-
null
|
|
366
|
-
);
|
|
367
|
-
for (let i = unwantedNodes.snapshotLength - 1; i >= 0; i--) {
|
|
368
|
-
const unwanted = unwantedNodes.snapshotItem(i);
|
|
369
|
-
unwanted?.parentNode && unwanted.parentNode.removeChild(unwanted);
|
|
370
|
-
}
|
|
371
|
-
const mappedElements = doc.evaluate(
|
|
372
|
-
mappedPaths.join("|"),
|
|
373
|
-
doc,
|
|
374
|
-
null,
|
|
375
|
-
_XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
376
|
-
null
|
|
377
|
-
);
|
|
378
|
-
for (let i = mappedElements.snapshotLength - 1; i >= 0; i--) {
|
|
379
|
-
const mappedElm = mappedElements.snapshotItem(i), tags = elementMap[mappedElm.className], text = doc.createTextNode(mappedElm.textContent || "");
|
|
380
|
-
if (!tags)
|
|
381
|
-
continue;
|
|
382
|
-
const parentElement = doc.createElement(tags[0]);
|
|
383
|
-
let parent = parentElement, child = parentElement;
|
|
384
|
-
tags.slice(1).forEach((tag) => {
|
|
385
|
-
child = doc.createElement(tag), parent.appendChild(child), parent = child;
|
|
386
|
-
}), child.appendChild(text), mappedElm?.parentNode?.replaceChild(parentElement, mappedElm);
|
|
387
|
-
}
|
|
388
|
-
return doc;
|
|
389
|
-
}
|
|
390
|
-
const preprocessors = [
|
|
391
|
-
preprocessWhitespace,
|
|
392
|
-
preprocessNotion,
|
|
393
|
-
preprocessWord,
|
|
394
|
-
preprocessWordOnline,
|
|
395
|
-
preprocessGDocs,
|
|
396
|
-
preprocessHTML
|
|
397
|
-
];
|
|
398
|
-
function mapParaStyleToBlockStyle(schema, paraStyle) {
|
|
399
|
-
const blockStyle = {
|
|
400
|
-
"heading 1": "h1",
|
|
401
|
-
"heading 2": "h2",
|
|
402
|
-
"heading 3": "h3",
|
|
403
|
-
"heading 4": "h4",
|
|
404
|
-
"heading 5": "h5",
|
|
405
|
-
"heading 6": "h6",
|
|
406
|
-
Quote: "blockquote"
|
|
407
|
-
}[paraStyle] ?? "normal";
|
|
408
|
-
return schema.styles.find((style) => style.name === blockStyle)?.name;
|
|
409
|
-
}
|
|
410
|
-
function createWordOnlineRules(schema, options) {
|
|
411
|
-
return [
|
|
412
|
-
// Image rule - handles bare Word Online <img> tags with WACImage class
|
|
413
|
-
{
|
|
414
|
-
deserialize(el) {
|
|
415
|
-
if (!isElement(el) || tagName(el) !== "img")
|
|
416
|
-
return;
|
|
417
|
-
const classNameRaw = el.className;
|
|
418
|
-
let className = "";
|
|
419
|
-
if (typeof classNameRaw == "string" ? className = classNameRaw : classNameRaw && typeof classNameRaw == "object" && (className = classNameRaw.baseVal || ""), !className.includes("WACImage"))
|
|
420
|
-
return;
|
|
421
|
-
const src = el.getAttribute("src") ?? void 0, alt = el.getAttribute("alt") ?? void 0, props = Object.fromEntries(
|
|
422
|
-
Array.from(el.attributes).map((attr) => [attr.name, attr.value])
|
|
423
|
-
), image = options.matchers?.image?.({
|
|
424
|
-
context: {
|
|
425
|
-
schema,
|
|
426
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
427
|
-
},
|
|
428
|
-
props: {
|
|
429
|
-
...props,
|
|
430
|
-
...src ? { src } : {},
|
|
431
|
-
...alt ? { alt } : {}
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
if (image)
|
|
435
|
-
return {
|
|
436
|
-
_type: "__block",
|
|
437
|
-
block: image
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
},
|
|
441
|
-
// Image rule - handles Word Online images wrapped in WACImageContainer
|
|
442
|
-
{
|
|
443
|
-
deserialize(el) {
|
|
444
|
-
if (!isElement(el))
|
|
445
|
-
return;
|
|
446
|
-
const classNameRaw = el.className;
|
|
447
|
-
let className = "";
|
|
448
|
-
if (typeof classNameRaw == "string" ? className = classNameRaw : classNameRaw && typeof classNameRaw == "object" && (className = classNameRaw.baseVal || ""), !className.includes("WACImageContainer"))
|
|
449
|
-
return;
|
|
450
|
-
const img = el.querySelector("img");
|
|
451
|
-
if (!img)
|
|
452
|
-
return;
|
|
453
|
-
const src = img.getAttribute("src") ?? void 0, alt = img.getAttribute("alt") ?? void 0, props = Object.fromEntries(
|
|
454
|
-
Array.from(img.attributes).map((attr) => [attr.name, attr.value])
|
|
455
|
-
), isInsideListItem = el.closest("li") !== null;
|
|
456
|
-
if (el.closest("p") === null || isInsideListItem) {
|
|
457
|
-
const inlineImage = options.matchers?.inlineImage?.({
|
|
458
|
-
context: {
|
|
459
|
-
schema,
|
|
460
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
461
|
-
},
|
|
462
|
-
props: {
|
|
463
|
-
...props,
|
|
464
|
-
...src ? { src } : {},
|
|
465
|
-
...alt ? { alt } : {}
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
if (inlineImage)
|
|
469
|
-
return inlineImage;
|
|
470
|
-
}
|
|
471
|
-
const image = options.matchers?.image?.({
|
|
472
|
-
context: {
|
|
473
|
-
schema,
|
|
474
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
475
|
-
},
|
|
476
|
-
props: {
|
|
477
|
-
...props,
|
|
478
|
-
...src ? { src } : {},
|
|
479
|
-
...alt ? { alt } : {}
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
if (image)
|
|
483
|
-
return {
|
|
484
|
-
_type: "__block",
|
|
485
|
-
block: image
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
},
|
|
489
|
-
// List item rule - handles <li> elements with aria-level
|
|
490
|
-
{
|
|
491
|
-
deserialize(el, next) {
|
|
492
|
-
if (!isElement(el) || tagName(el) !== "li")
|
|
493
|
-
return;
|
|
494
|
-
const ariaLevel = el.getAttribute("data-aria-level");
|
|
495
|
-
if (!ariaLevel)
|
|
496
|
-
return;
|
|
497
|
-
const listItem = tagName(el.parentNode) === "ol" ? "number" : "bullet";
|
|
498
|
-
let childNodesToProcess = el.childNodes, blockStyle = "normal";
|
|
499
|
-
if (el.childNodes.length === 1 && el.firstChild && isElement(el.firstChild)) {
|
|
500
|
-
const childTag = tagName(el.firstChild);
|
|
501
|
-
if (childTag && (HTML_BLOCK_TAGS[childTag] || HTML_HEADER_TAGS[childTag] || childTag === "word-online-block")) {
|
|
502
|
-
if (childTag === "word-online-block") {
|
|
503
|
-
const paraStyle = el.firstChild.getAttribute("data-parastyle"), foundBlockStyle = paraStyle ? mapParaStyleToBlockStyle(schema, paraStyle) : void 0;
|
|
504
|
-
foundBlockStyle && (blockStyle = foundBlockStyle);
|
|
505
|
-
}
|
|
506
|
-
childNodesToProcess = el.firstChild.childNodes;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
const children = next(childNodesToProcess);
|
|
510
|
-
let childArray = Array.isArray(children) ? children : [children].filter(Boolean);
|
|
511
|
-
for (; childArray.length > 0; ) {
|
|
512
|
-
const lastChild = childArray[childArray.length - 1];
|
|
513
|
-
if (lastChild && typeof lastChild == "object" && "text" in lastChild) {
|
|
514
|
-
const text = lastChild.text.trimEnd();
|
|
515
|
-
if (text === "")
|
|
516
|
-
childArray = childArray.slice(0, -1);
|
|
517
|
-
else if (text !== lastChild.text) {
|
|
518
|
-
lastChild.text = text;
|
|
519
|
-
break;
|
|
520
|
-
} else
|
|
521
|
-
break;
|
|
522
|
-
} else
|
|
523
|
-
break;
|
|
524
|
-
}
|
|
525
|
-
return {
|
|
526
|
-
_type: schema.block.name,
|
|
527
|
-
children: childArray,
|
|
528
|
-
markDefs: [],
|
|
529
|
-
style: blockStyle,
|
|
530
|
-
listItem,
|
|
531
|
-
level: parseInt(ariaLevel, 10)
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
},
|
|
535
|
-
// Block style rule - handles paragraph styles like Quote
|
|
536
|
-
// The preprocessor wraps grouped NormalTextRun spans in a word-online-block element
|
|
537
|
-
{
|
|
538
|
-
deserialize(el, next) {
|
|
539
|
-
if (!isElement(el))
|
|
540
|
-
return;
|
|
541
|
-
const paraStyle = el.getAttribute("data-parastyle"), blockStyle = paraStyle ? mapParaStyleToBlockStyle(schema, paraStyle) : void 0;
|
|
542
|
-
if (!blockStyle)
|
|
543
|
-
return;
|
|
544
|
-
const children = next(el.childNodes);
|
|
545
|
-
return {
|
|
546
|
-
_type: schema.block.name,
|
|
547
|
-
style: blockStyle,
|
|
548
|
-
markDefs: [],
|
|
549
|
-
children: Array.isArray(children) ? children : children ? [children] : []
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
},
|
|
553
|
-
// TextRun rule
|
|
554
|
-
{
|
|
555
|
-
deserialize(el) {
|
|
556
|
-
if (isWordOnlineTextRun(el)) {
|
|
557
|
-
if (!isElement(el) || !el.textContent)
|
|
558
|
-
return;
|
|
559
|
-
const text = Array.from(el.childNodes).filter(
|
|
560
|
-
(node) => isNormalTextRun(node) || isFindHit(node)
|
|
561
|
-
).map((span2) => isElement(span2) ? span2.textContent ?? "" : "").join("");
|
|
562
|
-
if (!text)
|
|
563
|
-
return;
|
|
564
|
-
const span = {
|
|
565
|
-
...DEFAULT_SPAN,
|
|
566
|
-
marks: [],
|
|
567
|
-
text
|
|
568
|
-
};
|
|
569
|
-
if (hasStrongFormatting(el) && span.marks.push("strong"), hasEmphasisFormatting(el) && !isInHeading(el) && !isInBlockquote(el) && span.marks.push("em"), hasUnderlineFormatting(el))
|
|
570
|
-
if (isElement(el) && el.parentElement && tagName(el.parentElement) === "a") {
|
|
571
|
-
const linkElement = el.parentElement;
|
|
572
|
-
if (linkElement) {
|
|
573
|
-
const prevSibling = linkElement.previousSibling, nextSibling = linkElement.nextSibling, hasPrevUnderline = prevSibling && isElement(prevSibling) && hasUnderlineFormatting(prevSibling), hasNextUnderline = nextSibling && isElement(nextSibling) && hasUnderlineFormatting(nextSibling);
|
|
574
|
-
(hasPrevUnderline || hasNextUnderline) && span.marks.push("underline");
|
|
575
|
-
}
|
|
576
|
-
} else
|
|
577
|
-
span.marks.push("underline");
|
|
578
|
-
return hasStrikethroughFormatting(el) && span.marks.push("strike-through"), span;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
];
|
|
583
|
-
}
|
|
584
|
-
const LIST_CONTAINER_TAGS = Object.keys(HTML_LIST_CONTAINER_TAGS);
|
|
585
|
-
function isEmphasis$1(el) {
|
|
586
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
587
|
-
return /font-style\s*:\s*italic/.test(style || "");
|
|
588
|
-
}
|
|
589
|
-
function isStrong$1(el) {
|
|
590
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
591
|
-
return /font-weight\s*:\s*700/.test(style || "");
|
|
592
|
-
}
|
|
593
|
-
function isUnderline$1(el) {
|
|
594
|
-
if (!isElement(el) || tagName(el.parentNode) === "a")
|
|
595
|
-
return !1;
|
|
596
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
597
|
-
return /text-decoration\s*:\s*underline/.test(style || "");
|
|
598
|
-
}
|
|
599
|
-
function isStrikethrough(el) {
|
|
600
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
601
|
-
return /text-decoration\s*:\s*(?:.*line-through.*;)/.test(style || "");
|
|
602
|
-
}
|
|
603
|
-
function isGoogleDocs(el) {
|
|
604
|
-
return isElement(el) && !!el.getAttribute("data-is-google-docs");
|
|
605
|
-
}
|
|
606
|
-
function isRootNode(el) {
|
|
607
|
-
return isElement(el) && !!el.getAttribute("data-is-root-node");
|
|
608
|
-
}
|
|
609
|
-
function getListItemStyle$1(el) {
|
|
610
|
-
const parentTag = tagName(el.parentNode);
|
|
611
|
-
if (!(parentTag && !LIST_CONTAINER_TAGS.includes(parentTag)))
|
|
612
|
-
return tagName(el.parentNode) === "ul" ? "bullet" : "number";
|
|
613
|
-
}
|
|
614
|
-
function getListItemLevel$1(el) {
|
|
615
|
-
let level = 0;
|
|
616
|
-
if (tagName(el) === "li") {
|
|
617
|
-
let parentNode = el.parentNode;
|
|
618
|
-
for (; parentNode; ) {
|
|
619
|
-
const parentTag = tagName(parentNode);
|
|
620
|
-
parentTag && LIST_CONTAINER_TAGS.includes(parentTag) && level++, parentNode = parentNode.parentNode;
|
|
621
|
-
}
|
|
622
|
-
} else
|
|
623
|
-
level = 1;
|
|
624
|
-
return level;
|
|
625
|
-
}
|
|
626
|
-
const blocks = {
|
|
627
|
-
...HTML_BLOCK_TAGS,
|
|
628
|
-
...HTML_HEADER_TAGS
|
|
629
|
-
};
|
|
630
|
-
function getBlockStyle(schema, el) {
|
|
631
|
-
const childTag = tagName(el.firstChild), block = childTag && blocks[childTag];
|
|
632
|
-
return block ? schema.styles.some((style) => style.name === block.style) ? block.style : BLOCK_DEFAULT_STYLE : BLOCK_DEFAULT_STYLE;
|
|
633
|
-
}
|
|
634
|
-
function createGDocsRules(schema) {
|
|
635
|
-
return [
|
|
636
|
-
{
|
|
637
|
-
deserialize(el, next) {
|
|
638
|
-
if (isElement(el) && tagName(el) === "span" && isGoogleDocs(el)) {
|
|
639
|
-
if (!el.textContent)
|
|
640
|
-
return !el.previousSibling && !el.nextSibling && el.setAttribute("data-lonely-child", "true"), next(el.childNodes);
|
|
641
|
-
const span = {
|
|
642
|
-
...DEFAULT_SPAN,
|
|
643
|
-
marks: [],
|
|
644
|
-
text: el.textContent
|
|
645
|
-
};
|
|
646
|
-
return isStrong$1(el) && span.marks.push("strong"), isUnderline$1(el) && span.marks.push("underline"), isStrikethrough(el) && span.marks.push("strike-through"), isEmphasis$1(el) && span.marks.push("em"), span;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
},
|
|
650
|
-
{
|
|
651
|
-
deserialize(el, next) {
|
|
652
|
-
if (tagName(el) === "li" && isGoogleDocs(el))
|
|
653
|
-
return {
|
|
654
|
-
...DEFAULT_BLOCK,
|
|
655
|
-
listItem: getListItemStyle$1(el),
|
|
656
|
-
level: getListItemLevel$1(el),
|
|
657
|
-
style: getBlockStyle(schema, el),
|
|
658
|
-
children: next(el.firstChild?.childNodes || [])
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
},
|
|
662
|
-
{
|
|
663
|
-
deserialize(el) {
|
|
664
|
-
if (tagName(el) === "br" && isGoogleDocs(el) && isElement(el) && el.classList.contains("apple-interchange-newline"))
|
|
665
|
-
return {
|
|
666
|
-
...DEFAULT_SPAN,
|
|
667
|
-
text: ""
|
|
668
|
-
};
|
|
669
|
-
if (tagName(el) === "br" && isGoogleDocs(el) && isElement(el) && el?.parentNode?.textContent === "")
|
|
670
|
-
return {
|
|
671
|
-
...DEFAULT_SPAN,
|
|
672
|
-
text: ""
|
|
673
|
-
};
|
|
674
|
-
if (tagName(el) === "br" && isGoogleDocs(el) && isElement(el) && isRootNode(el))
|
|
675
|
-
return {
|
|
676
|
-
...DEFAULT_SPAN,
|
|
677
|
-
text: ""
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
];
|
|
682
|
-
}
|
|
683
|
-
const whitespaceTextNodeRule = {
|
|
684
|
-
deserialize(node) {
|
|
685
|
-
return node.nodeName === "#text" && isWhitespaceTextNode(node) ? {
|
|
686
|
-
...DEFAULT_SPAN,
|
|
687
|
-
marks: [],
|
|
688
|
-
text: (node.textContent ?? "").replace(/\s\s+/g, " ")
|
|
689
|
-
} : void 0;
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
function isWhitespaceTextNode(node) {
|
|
693
|
-
const isWhitespaceOnly = node.nodeType === 3 && (node.textContent || "").replace(/[\r\n]/g, " ").replace(/\s\s+/g, " ") === " ", hasSiblingContext = node.nextSibling && node.nextSibling.nodeType !== 3 && node.previousSibling && node.previousSibling.nodeType !== 3, hasParentSiblingContext = node.parentNode && tagName(node.parentNode) === "span" && !node.nextSibling && !node.previousSibling && node.parentNode.previousSibling && node.parentNode.previousSibling.nodeType !== 3 && node.parentNode.nextSibling && node.parentNode.nextSibling.nodeType !== 3;
|
|
694
|
-
return (isWhitespaceOnly && (hasSiblingContext || hasParentSiblingContext) || node.textContent !== " ") && tagName(node.parentNode) !== "body";
|
|
695
|
-
}
|
|
696
|
-
function resolveListItem(schema, listNodeTagName) {
|
|
697
|
-
if (listNodeTagName === "ul" && schema.lists.some((list) => list.name === "bullet"))
|
|
698
|
-
return "bullet";
|
|
699
|
-
if (listNodeTagName === "ol" && schema.lists.some((list) => list.name === "number"))
|
|
700
|
-
return "number";
|
|
701
|
-
}
|
|
702
|
-
function createHTMLRules(schema, options) {
|
|
703
|
-
return [
|
|
704
|
-
whitespaceTextNodeRule,
|
|
705
|
-
{
|
|
706
|
-
// Pre element
|
|
707
|
-
deserialize(el) {
|
|
708
|
-
if (tagName(el) !== "pre")
|
|
709
|
-
return;
|
|
710
|
-
const isCodeEnabled = schema.styles.some(
|
|
711
|
-
(style) => style.name === "code"
|
|
712
|
-
);
|
|
713
|
-
return {
|
|
714
|
-
_type: "block",
|
|
715
|
-
style: "normal",
|
|
716
|
-
markDefs: [],
|
|
717
|
-
children: [
|
|
718
|
-
{
|
|
719
|
-
...DEFAULT_SPAN,
|
|
720
|
-
marks: isCodeEnabled ? ["code"] : [],
|
|
721
|
-
text: el.textContent || ""
|
|
722
|
-
}
|
|
723
|
-
]
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
// Blockquote element
|
|
728
|
-
{
|
|
729
|
-
deserialize(el, next) {
|
|
730
|
-
if (tagName(el) !== "blockquote")
|
|
731
|
-
return;
|
|
732
|
-
const blocks2 = {
|
|
733
|
-
...HTML_BLOCK_TAGS,
|
|
734
|
-
...HTML_HEADER_TAGS
|
|
735
|
-
};
|
|
736
|
-
delete blocks2.blockquote;
|
|
737
|
-
const nonBlockquoteBlocks = Object.keys(blocks2), children = [];
|
|
738
|
-
return el.childNodes.forEach((node, index) => {
|
|
739
|
-
if (el.ownerDocument)
|
|
740
|
-
if (node.nodeType === 1 && nonBlockquoteBlocks.includes(
|
|
741
|
-
node.localName.toLowerCase()
|
|
742
|
-
)) {
|
|
743
|
-
const span = el.ownerDocument.createElement("span"), previousChild = children[children.length - 1];
|
|
744
|
-
previousChild && previousChild.nodeType === 3 && previousChild.textContent?.trim() && span.appendChild(el.ownerDocument.createTextNode("\r")), node.childNodes.forEach((cn) => {
|
|
745
|
-
span.appendChild(cn.cloneNode(!0));
|
|
746
|
-
}), index !== el.childNodes.length && span.appendChild(el.ownerDocument.createTextNode("\r")), children.push(span);
|
|
747
|
-
} else
|
|
748
|
-
children.push(node);
|
|
749
|
-
}), {
|
|
750
|
-
_type: "block",
|
|
751
|
-
style: "blockquote",
|
|
752
|
-
markDefs: [],
|
|
753
|
-
children: next(children)
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
},
|
|
757
|
-
// Block elements
|
|
758
|
-
{
|
|
759
|
-
deserialize(el, next) {
|
|
760
|
-
const blocks2 = {
|
|
761
|
-
...HTML_BLOCK_TAGS,
|
|
762
|
-
...HTML_HEADER_TAGS
|
|
763
|
-
}, tag = tagName(el);
|
|
764
|
-
let block = tag ? blocks2[tag] : void 0;
|
|
765
|
-
if (!block)
|
|
766
|
-
return;
|
|
767
|
-
if (el.parentNode && tagName(el.parentNode) === "li")
|
|
768
|
-
return next(el.childNodes);
|
|
769
|
-
const blockStyle = block.style;
|
|
770
|
-
return schema.styles.some((style) => style.name === blockStyle) || (block = DEFAULT_BLOCK), {
|
|
771
|
-
...block,
|
|
772
|
-
children: next(el.childNodes)
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
// Ignore span tags
|
|
777
|
-
{
|
|
778
|
-
deserialize(el, next) {
|
|
779
|
-
const tag = tagName(el);
|
|
780
|
-
if (!(!tag || !(tag in HTML_SPAN_TAGS)))
|
|
781
|
-
return next(el.childNodes);
|
|
782
|
-
}
|
|
783
|
-
},
|
|
784
|
-
// Ignore div tags
|
|
785
|
-
{
|
|
786
|
-
deserialize(el, next) {
|
|
787
|
-
if (tagName(el) === "div")
|
|
788
|
-
return next(el.childNodes);
|
|
789
|
-
}
|
|
790
|
-
},
|
|
791
|
-
// Ignore list containers
|
|
792
|
-
{
|
|
793
|
-
deserialize(el, next) {
|
|
794
|
-
const tag = tagName(el);
|
|
795
|
-
if (!(!tag || !(tag in HTML_LIST_CONTAINER_TAGS)))
|
|
796
|
-
return next(el.childNodes);
|
|
797
|
-
}
|
|
798
|
-
},
|
|
799
|
-
// Deal with br's
|
|
800
|
-
{
|
|
801
|
-
deserialize(el) {
|
|
802
|
-
if (tagName(el) === "br")
|
|
803
|
-
return {
|
|
804
|
-
...DEFAULT_SPAN,
|
|
805
|
-
text: `
|
|
806
|
-
`
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
},
|
|
810
|
-
// Deal with list items
|
|
811
|
-
{
|
|
812
|
-
deserialize(el, next, block) {
|
|
813
|
-
const tag = tagName(el), listItem = tag ? HTML_LIST_ITEM_TAGS[tag] : void 0;
|
|
814
|
-
if (!listItem)
|
|
815
|
-
return;
|
|
816
|
-
const parentTag = tagName(el.parentNode) || "", listTag = HTML_LIST_CONTAINER_TAGS[parentTag] ? parentTag : "ul", enabledListItem = resolveListItem(schema, listTag);
|
|
817
|
-
return enabledListItem ? (listItem.listItem = enabledListItem, {
|
|
818
|
-
...listItem,
|
|
819
|
-
children: next(el.childNodes)
|
|
820
|
-
}) : block({ _type: "block", children: next(el.childNodes) });
|
|
821
|
-
}
|
|
822
|
-
},
|
|
823
|
-
// Deal with decorators - this is a limited set of known html elements that we know how to deserialize
|
|
824
|
-
{
|
|
825
|
-
deserialize(el, next) {
|
|
826
|
-
const decorator = HTML_DECORATOR_TAGS[tagName(el) || ""];
|
|
827
|
-
if (!(!decorator || !schema.decorators.some(
|
|
828
|
-
(decoratorType) => decoratorType.name === decorator
|
|
829
|
-
)))
|
|
830
|
-
return {
|
|
831
|
-
_type: "__decorator",
|
|
832
|
-
name: decorator,
|
|
833
|
-
children: next(el.childNodes)
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
},
|
|
837
|
-
// Special case for hyperlinks, add annotation (if allowed by schema),
|
|
838
|
-
// If not supported just write out the link text and href in plain text.
|
|
839
|
-
{
|
|
840
|
-
deserialize(el, next) {
|
|
841
|
-
if (tagName(el) !== "a")
|
|
842
|
-
return;
|
|
843
|
-
const linkEnabled = schema.annotations.some(
|
|
844
|
-
(annotation) => annotation.name === "link"
|
|
845
|
-
), href = isElement(el) && el.getAttribute("href");
|
|
846
|
-
return href ? linkEnabled ? {
|
|
847
|
-
_type: "__annotation",
|
|
848
|
-
markDef: {
|
|
849
|
-
_key: options.keyGenerator ? options.keyGenerator() : keyGenerator(),
|
|
850
|
-
_type: "link",
|
|
851
|
-
href
|
|
852
|
-
},
|
|
853
|
-
children: next(el.childNodes)
|
|
854
|
-
} : el.appendChild(el.ownerDocument.createTextNode(` (${href})`)) && next(el.childNodes) : next(el.childNodes);
|
|
855
|
-
}
|
|
856
|
-
},
|
|
857
|
-
{
|
|
858
|
-
deserialize(el, next) {
|
|
859
|
-
if (isElement(el) && (tagName(el) === "td" || tagName(el) === "th"))
|
|
860
|
-
return {
|
|
861
|
-
...DEFAULT_BLOCK,
|
|
862
|
-
children: next(el.childNodes)
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
},
|
|
866
|
-
{
|
|
867
|
-
deserialize(el) {
|
|
868
|
-
if (isElement(el) && tagName(el) === "img") {
|
|
869
|
-
const src = el.getAttribute("src") ?? void 0, alt = el.getAttribute("alt") ?? void 0, props = Object.fromEntries(
|
|
870
|
-
Array.from(el.attributes).map((attr) => [attr.name, attr.value])
|
|
871
|
-
), ancestorOfLonelyChild = el?.parentElement?.parentElement?.getAttribute("data-lonely-child"), ancestorOfListItem = el.closest("li") !== null;
|
|
872
|
-
if (ancestorOfLonelyChild && !ancestorOfListItem) {
|
|
873
|
-
const image2 = options.matchers?.image?.({
|
|
874
|
-
context: {
|
|
875
|
-
schema,
|
|
876
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
877
|
-
},
|
|
878
|
-
props: {
|
|
879
|
-
...props,
|
|
880
|
-
...src ? { src } : {},
|
|
881
|
-
...alt ? { alt } : {}
|
|
882
|
-
}
|
|
883
|
-
});
|
|
884
|
-
if (image2)
|
|
885
|
-
return {
|
|
886
|
-
_type: "__block",
|
|
887
|
-
block: image2
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
const inlineImage = options.matchers?.inlineImage?.({
|
|
891
|
-
context: {
|
|
892
|
-
schema,
|
|
893
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
894
|
-
},
|
|
895
|
-
props: {
|
|
896
|
-
...props,
|
|
897
|
-
...src ? { src } : {},
|
|
898
|
-
...alt ? { alt } : {}
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
if (inlineImage)
|
|
902
|
-
return inlineImage;
|
|
903
|
-
const image = options.matchers?.image?.({
|
|
904
|
-
context: {
|
|
905
|
-
schema,
|
|
906
|
-
keyGenerator: options.keyGenerator ?? keyGenerator
|
|
907
|
-
},
|
|
908
|
-
props: {
|
|
909
|
-
...props,
|
|
910
|
-
...src ? { src } : {},
|
|
911
|
-
...alt ? { alt } : {}
|
|
912
|
-
}
|
|
913
|
-
});
|
|
914
|
-
if (image)
|
|
915
|
-
return {
|
|
916
|
-
_type: "__block",
|
|
917
|
-
block: image
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
];
|
|
923
|
-
}
|
|
924
|
-
function isEmphasis(el) {
|
|
925
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
926
|
-
return /font-style:italic/.test(style || "");
|
|
927
|
-
}
|
|
928
|
-
function isStrong(el) {
|
|
929
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
930
|
-
return /font-weight:700/.test(style || "") || /font-weight:600/.test(style || "");
|
|
931
|
-
}
|
|
932
|
-
function isUnderline(el) {
|
|
933
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
934
|
-
return /text-decoration:underline/.test(style || "");
|
|
935
|
-
}
|
|
936
|
-
function isNotion(el) {
|
|
937
|
-
return isElement(el) && !!el.getAttribute("data-is-notion");
|
|
938
|
-
}
|
|
939
|
-
function createNotionRules() {
|
|
940
|
-
return [
|
|
941
|
-
{
|
|
942
|
-
deserialize(el) {
|
|
943
|
-
if (isElement(el) && tagName(el) === "span" && isNotion(el)) {
|
|
944
|
-
const span = {
|
|
945
|
-
...DEFAULT_SPAN,
|
|
946
|
-
marks: [],
|
|
947
|
-
text: el.textContent
|
|
948
|
-
};
|
|
949
|
-
return isStrong(el) && span.marks.push("strong"), isUnderline(el) && span.marks.push("underline"), isEmphasis(el) && span.marks.push("em"), span;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
];
|
|
954
|
-
}
|
|
955
|
-
function getListItemStyle(el) {
|
|
956
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
957
|
-
if (style && style.match(/lfo\d+/))
|
|
958
|
-
return style.match("lfo1") ? "number" : "bullet";
|
|
959
|
-
}
|
|
960
|
-
function getListItemLevel(el) {
|
|
961
|
-
const style = isElement(el) && el.getAttribute("style");
|
|
962
|
-
if (!style)
|
|
963
|
-
return;
|
|
964
|
-
const levelMatch = style.match(/level\d+/);
|
|
965
|
-
if (!levelMatch)
|
|
966
|
-
return;
|
|
967
|
-
const [level] = levelMatch[0].match(/\d/) || [];
|
|
968
|
-
return (level ? Number.parseInt(level, 10) : 1) || 1;
|
|
969
|
-
}
|
|
970
|
-
function isWordListElement(el) {
|
|
971
|
-
if (!isElement(el))
|
|
972
|
-
return !1;
|
|
973
|
-
if (el.className && (el.className === "MsoListParagraphCxSpFirst" || el.className === "MsoListParagraphCxSpMiddle" || el.className === "MsoListParagraphCxSpLast"))
|
|
974
|
-
return !0;
|
|
975
|
-
const style = el.getAttribute("style");
|
|
976
|
-
return !!(style && /mso-list:\s*l\d+\s+level\d+\s+lfo\d+/.test(style));
|
|
977
|
-
}
|
|
978
|
-
function getHeadingStyle(el) {
|
|
979
|
-
const tag = tagName(el);
|
|
980
|
-
if (tag && HTML_HEADER_TAGS[tag])
|
|
981
|
-
return HTML_HEADER_TAGS[tag]?.style;
|
|
982
|
-
}
|
|
983
|
-
function createWordRules() {
|
|
984
|
-
return [
|
|
985
|
-
{
|
|
986
|
-
deserialize(el, next) {
|
|
987
|
-
const tag = tagName(el);
|
|
988
|
-
if ((tag === "p" || HTML_HEADER_TAGS[tag || ""]) && isWordListElement(el)) {
|
|
989
|
-
const headingStyle = getHeadingStyle(el);
|
|
990
|
-
return {
|
|
991
|
-
...DEFAULT_BLOCK,
|
|
992
|
-
listItem: getListItemStyle(el),
|
|
993
|
-
level: getListItemLevel(el),
|
|
994
|
-
style: headingStyle || BLOCK_DEFAULT_STYLE,
|
|
995
|
-
children: next(el.childNodes)
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
];
|
|
1001
|
-
}
|
|
1002
|
-
function createRules(schema, options) {
|
|
1003
|
-
return [
|
|
1004
|
-
...createWordRules(),
|
|
1005
|
-
...createWordOnlineRules(schema, options),
|
|
1006
|
-
...createNotionRules(),
|
|
1007
|
-
...createGDocsRules(schema),
|
|
1008
|
-
...createHTMLRules(schema, options)
|
|
1009
|
-
];
|
|
1010
|
-
}
|
|
1011
|
-
function trimWhitespace(context, mode, blocks2) {
|
|
1012
|
-
const trimmedBlocks = [];
|
|
1013
|
-
let consecutiveEmptyCount = 0;
|
|
1014
|
-
for (const block of blocks2) {
|
|
1015
|
-
const trimmedBlock = isTextBlock(context, block) ? trimTextBlockWhitespace(block) : block;
|
|
1016
|
-
if (mode === "preserve") {
|
|
1017
|
-
trimmedBlocks.push(trimmedBlock);
|
|
1018
|
-
continue;
|
|
1019
|
-
}
|
|
1020
|
-
if (mode === "remove") {
|
|
1021
|
-
if (isEmptyTextBlock(context, trimmedBlock))
|
|
1022
|
-
continue;
|
|
1023
|
-
trimmedBlocks.push(trimmedBlock);
|
|
1024
|
-
continue;
|
|
1025
|
-
}
|
|
1026
|
-
if (mode === "normalize") {
|
|
1027
|
-
if (isEmptyTextBlock(context, trimmedBlock)) {
|
|
1028
|
-
consecutiveEmptyCount++, consecutiveEmptyCount === 1 && trimmedBlocks.push(trimmedBlock);
|
|
1029
|
-
continue;
|
|
1030
|
-
}
|
|
1031
|
-
trimmedBlocks.push(trimmedBlock), consecutiveEmptyCount = 0;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
return trimmedBlocks;
|
|
1035
|
-
}
|
|
1036
|
-
function isEmptyTextBlock(context, block) {
|
|
1037
|
-
return !(!isTextBlock(context, block) || block.children.some(
|
|
1038
|
-
(child) => !isSpan(context, child) || child.text.trim() !== ""
|
|
1039
|
-
));
|
|
1040
|
-
}
|
|
1041
|
-
function trimTextBlockWhitespace(block) {
|
|
1042
|
-
let index = 0;
|
|
1043
|
-
for (const child of block.children) {
|
|
1044
|
-
if (!isMinimalSpan(child)) {
|
|
1045
|
-
index++;
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
const nextChild = nextSpan(block, index), prevChild = prevSpan(block, index);
|
|
1049
|
-
index === 0 && (child.text = child.text.replace(/^[^\S\n]+/g, "")), index === block.children.length - 1 && (child.text = child.text.replace(/[^\S\n]+$/g, "")), /\s/.test(child.text.slice(Math.max(0, child.text.length - 1))) && nextChild && isMinimalSpan(nextChild) && /\s/.test(nextChild.text.slice(0, 1)) && (child.text = child.text.replace(/[^\S\n]+$/g, "")), /\s/.test(child.text.slice(0, 1)) && prevChild && isMinimalSpan(prevChild) && /\s/.test(prevChild.text.slice(Math.max(0, prevChild.text.length - 1))) && (child.text = child.text.replace(/^[^\S\n]+/g, "")), child.text || block.children.splice(index, 1), prevChild && Array.isArray(prevChild.marks) && isEqualMarks(prevChild.marks, child.marks) && isWhiteSpaceChar(child.text) ? (prevChild.text += " ", block.children.splice(index, 1)) : nextChild && Array.isArray(nextChild.marks) && isEqualMarks(nextChild.marks, child.marks) && isWhiteSpaceChar(child.text) && (nextChild.text = ` ${nextChild.text}`, block.children.splice(index, 1)), index++;
|
|
1050
|
-
}
|
|
1051
|
-
return block;
|
|
1052
|
-
}
|
|
1053
|
-
function nextSpan(block, index) {
|
|
1054
|
-
const next = block.children[index + 1];
|
|
1055
|
-
return next && next._type === "span" ? next : null;
|
|
1056
|
-
}
|
|
1057
|
-
function prevSpan(block, index) {
|
|
1058
|
-
const prev = block.children[index - 1];
|
|
1059
|
-
return prev && prev._type === "span" ? prev : null;
|
|
1060
|
-
}
|
|
1061
|
-
function isWhiteSpaceChar(text) {
|
|
1062
|
-
return ["\xA0", " "].includes(text);
|
|
1063
|
-
}
|
|
1064
|
-
class HtmlDeserializer {
|
|
1065
|
-
keyGenerator;
|
|
1066
|
-
schema;
|
|
1067
|
-
rules;
|
|
1068
|
-
parseHtml;
|
|
1069
|
-
whitespaceMode;
|
|
1070
|
-
_markDefs = [];
|
|
1071
|
-
/**
|
|
1072
|
-
* Create a new serializer respecting a Sanity block content type's schema
|
|
1073
|
-
*
|
|
1074
|
-
* @param blockContentType - Schema type for array containing _at least_ a block child type
|
|
1075
|
-
* @param options - Options for the deserialization process
|
|
1076
|
-
*/
|
|
1077
|
-
constructor(schema, options = {}) {
|
|
1078
|
-
const { rules = [], unstable_whitespaceOnPasteMode = "preserve" } = options, standardRules = createRules(schema, {
|
|
1079
|
-
keyGenerator: options.keyGenerator,
|
|
1080
|
-
matchers: options.matchers
|
|
1081
|
-
});
|
|
1082
|
-
this.schema = schema, this.keyGenerator = options.keyGenerator ?? keyGenerator, this.rules = [...rules, ...standardRules], this.whitespaceMode = unstable_whitespaceOnPasteMode;
|
|
1083
|
-
const parseHtml = options.parseHtml || defaultParseHtml();
|
|
1084
|
-
this.parseHtml = (html) => {
|
|
1085
|
-
const cleanHTML = M(html), doc = parseHtml(cleanHTML);
|
|
1086
|
-
for (const processor of preprocessors)
|
|
1087
|
-
processor(cleanHTML, doc);
|
|
1088
|
-
return doc.body;
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
/**
|
|
1092
|
-
* Deserialize HTML.
|
|
1093
|
-
*
|
|
1094
|
-
* @param html - The HTML to deserialize, as a string
|
|
1095
|
-
* @returns Array of blocks - either portable text blocks or other allowed blocks
|
|
1096
|
-
*/
|
|
1097
|
-
deserialize = (html) => {
|
|
1098
|
-
this._markDefs = [];
|
|
1099
|
-
const { parseHtml } = this, fragment = parseHtml(html), children = Array.from(fragment.childNodes), blocks2 = trimWhitespace(
|
|
1100
|
-
{ schema: this.schema },
|
|
1101
|
-
this.whitespaceMode,
|
|
1102
|
-
flattenNestedBlocks(
|
|
1103
|
-
{ schema: this.schema },
|
|
1104
|
-
ensureRootIsBlocks(
|
|
1105
|
-
this.schema,
|
|
1106
|
-
this.deserializeElements(children)
|
|
1107
|
-
)
|
|
1108
|
-
)
|
|
1109
|
-
);
|
|
1110
|
-
return this._markDefs.length > 0 && blocks2.filter((block) => isTextBlock({ schema: this.schema }, block)).forEach((block) => {
|
|
1111
|
-
block.markDefs = block.markDefs || [], block.markDefs = block.markDefs.concat(
|
|
1112
|
-
this._markDefs.filter((def) => block.children.flatMap((child) => child.marks || []).includes(def._key))
|
|
1113
|
-
);
|
|
1114
|
-
}), blocks2.map((block) => (block._type === "block" && (block._type = this.schema.block.name), block));
|
|
1115
|
-
};
|
|
1116
|
-
/**
|
|
1117
|
-
* Deserialize an array of DOM elements.
|
|
1118
|
-
*
|
|
1119
|
-
* @param elements - Array of DOM elements to deserialize
|
|
1120
|
-
* @returns
|
|
1121
|
-
*/
|
|
1122
|
-
deserializeElements = (elements = []) => {
|
|
1123
|
-
let nodes = [];
|
|
1124
|
-
return elements.forEach((element) => {
|
|
1125
|
-
nodes = nodes.concat(this.deserializeElement(element));
|
|
1126
|
-
}), nodes;
|
|
1127
|
-
};
|
|
1128
|
-
/**
|
|
1129
|
-
* Deserialize a DOM element
|
|
1130
|
-
*
|
|
1131
|
-
* @param element - Deserialize a DOM element
|
|
1132
|
-
* @returns
|
|
1133
|
-
*/
|
|
1134
|
-
deserializeElement = (element) => {
|
|
1135
|
-
const next = (elements) => {
|
|
1136
|
-
if (isNodeList(elements))
|
|
1137
|
-
return this.deserializeElements(Array.from(elements));
|
|
1138
|
-
if (Array.isArray(elements))
|
|
1139
|
-
return this.deserializeElements(elements);
|
|
1140
|
-
if (elements)
|
|
1141
|
-
return this.deserializeElement(elements);
|
|
1142
|
-
}, block = (props) => ({
|
|
1143
|
-
_type: "__block",
|
|
1144
|
-
block: props
|
|
1145
|
-
});
|
|
1146
|
-
let node;
|
|
1147
|
-
for (let i = 0; i < this.rules.length; i++) {
|
|
1148
|
-
const rule = this.rules[i];
|
|
1149
|
-
if (!rule.deserialize)
|
|
1150
|
-
continue;
|
|
1151
|
-
const ret = rule.deserialize(element, next, block), type = resolveJsType(ret);
|
|
1152
|
-
if (type !== "array" && type !== "object" && type !== "null" && type !== "undefined")
|
|
1153
|
-
throw new Error(
|
|
1154
|
-
`A rule returned an invalid deserialized representation: "${node}".`
|
|
1155
|
-
);
|
|
1156
|
-
if (ret !== void 0) {
|
|
1157
|
-
{
|
|
1158
|
-
if (ret === null)
|
|
1159
|
-
throw new Error("Deserializer rule returned `null`");
|
|
1160
|
-
Array.isArray(ret) ? node = ret : isPlaceholderDecorator(ret) ? node = this.deserializeDecorator(ret) : isPlaceholderAnnotation(ret) ? node = this.deserializeAnnotation(ret) : node = ret;
|
|
1161
|
-
}
|
|
1162
|
-
if (ret && !Array.isArray(ret) && isMinimalBlock(ret) && "listItem" in ret) {
|
|
1163
|
-
let parent = element.parentNode?.parentNode;
|
|
1164
|
-
for (; parent && tagName(parent) === "li"; )
|
|
1165
|
-
parent = parent.parentNode?.parentNode, ret.level = ret.level ? ret.level + 1 : 1;
|
|
1166
|
-
}
|
|
1167
|
-
ret && !Array.isArray(ret) && isMinimalBlock(ret) && ret.style === "blockquote" && ret.children.forEach((child, index) => {
|
|
1168
|
-
isMinimalSpan(child) && child.text === "\r" && (child.text = `
|
|
1169
|
-
`, (index === 0 || index === ret.children.length - 1) && ret.children.splice(index, 1));
|
|
1170
|
-
});
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
return node || next(element.childNodes) || [];
|
|
1175
|
-
};
|
|
1176
|
-
/**
|
|
1177
|
-
* Deserialize a `__decorator` type
|
|
1178
|
-
* (an internal made up type to process decorators exclusively)
|
|
1179
|
-
*
|
|
1180
|
-
* @param decorator -
|
|
1181
|
-
* @returns array of ...
|
|
1182
|
-
*/
|
|
1183
|
-
deserializeDecorator = (decorator) => {
|
|
1184
|
-
const { name } = decorator, applyDecorator = (node) => {
|
|
1185
|
-
if (isPlaceholderDecorator(node))
|
|
1186
|
-
return this.deserializeDecorator(node);
|
|
1187
|
-
if (isMinimalSpan(node))
|
|
1188
|
-
node.marks = node.marks || [], node.text.trim() && node.marks.unshift(name);
|
|
1189
|
-
else if ("children" in node && Array.isArray(node.children)) {
|
|
1190
|
-
const block = node;
|
|
1191
|
-
block.children = block.children.map(applyDecorator);
|
|
1192
|
-
}
|
|
1193
|
-
return node;
|
|
1194
|
-
};
|
|
1195
|
-
return decorator.children.reduce((children, node) => {
|
|
1196
|
-
const ret = applyDecorator(node);
|
|
1197
|
-
return Array.isArray(ret) ? children.concat(ret) : (children.push(ret), children);
|
|
1198
|
-
}, []);
|
|
1199
|
-
};
|
|
1200
|
-
/**
|
|
1201
|
-
* Deserialize a `__annotation` object.
|
|
1202
|
-
* (an internal made up type to process annotations exclusively)
|
|
1203
|
-
*
|
|
1204
|
-
* @param annotation -
|
|
1205
|
-
* @returns Array of...
|
|
1206
|
-
*/
|
|
1207
|
-
deserializeAnnotation = (annotation) => {
|
|
1208
|
-
const { markDef } = annotation;
|
|
1209
|
-
this._markDefs.push(markDef);
|
|
1210
|
-
const applyAnnotation = (node) => {
|
|
1211
|
-
if (isPlaceholderAnnotation(node))
|
|
1212
|
-
return this.deserializeAnnotation(node);
|
|
1213
|
-
if (isMinimalSpan(node))
|
|
1214
|
-
node.marks = node.marks || [], node.text.trim() && node.marks.unshift(markDef._key);
|
|
1215
|
-
else if ("children" in node && Array.isArray(node.children)) {
|
|
1216
|
-
const block = node;
|
|
1217
|
-
block.children = block.children.map(applyAnnotation);
|
|
1218
|
-
}
|
|
1219
|
-
return node;
|
|
1220
|
-
};
|
|
1221
|
-
return annotation.children.reduce((children, node) => {
|
|
1222
|
-
const ret = applyAnnotation(node);
|
|
1223
|
-
return Array.isArray(ret) ? children.concat(ret) : (children.push(ret), children);
|
|
1224
|
-
}, []);
|
|
1225
|
-
};
|
|
1226
|
-
}
|
|
1227
27
|
function normalizeBlock(node, options = {}) {
|
|
1228
28
|
const schema = {
|
|
1229
29
|
block: {
|
|
@@ -1279,7 +79,27 @@ function normalizeBlock(node, options = {}) {
|
|
|
1279
79
|
}
|
|
1280
80
|
function htmlToBlocks(html, schemaType, options = {}) {
|
|
1281
81
|
const schema = isSanitySchema(schemaType) ? sanitySchemaToPortableTextSchema(schemaType) : schemaType;
|
|
1282
|
-
return
|
|
82
|
+
return htmlToPortableText(html, {
|
|
83
|
+
schema,
|
|
84
|
+
keyGenerator: options.keyGenerator,
|
|
85
|
+
parseHtml: options.parseHtml,
|
|
86
|
+
rules: options.rules,
|
|
87
|
+
whitespaceMode: options.unstable_whitespaceOnPasteMode,
|
|
88
|
+
types: adaptMatchers(options.matchers)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function adaptMatchers(matchers) {
|
|
92
|
+
if (!(!matchers?.image && !matchers?.inlineImage))
|
|
93
|
+
return {
|
|
94
|
+
image: ({ context, value, isInline }) => {
|
|
95
|
+
const matcher = isInline ? matchers.inlineImage : matchers.image;
|
|
96
|
+
if (!matcher)
|
|
97
|
+
return;
|
|
98
|
+
const result = matcher({ context, props: value });
|
|
99
|
+
if (result)
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
1283
103
|
}
|
|
1284
104
|
function isSanitySchema(schema) {
|
|
1285
105
|
return schema.hasOwnProperty("jsonType");
|